Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set Image.Source property with Dispatcher?

I tried use this recomendations: http://msdn.microsoft.com/en-us/library/ms741870.aspx ("Handling a Blocking Operation with a Background Thread").

This is my code:

  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            ;
        }

        private void Process()
        {
            // some code creating BitmapSource thresholdedImage

            ThreadStart start = () =>
            {
                Dispatcher.BeginInvoke(
                    System.Windows.Threading.DispatcherPriority.Normal,
                    new Action<ImageSource>(Update),
                    thresholdedImage);
            };
            Thread nt = new Thread(start);
            nt.SetApartmentState(ApartmentState.STA);
            nt.Start();
        }

        private void button1_Click(object sender, RoutedEventArgs e)
        {
            button1.IsEnabled = false;
            button1.Content = "Processing...";

            Action action = new Action(Process);
            action.BeginInvoke(null, null);
        }

        private void Update(ImageSource source)
        {
            this.image1.Source = source; // ! this line throw exception

            this.button1.IsEnabled = true; // this line works
            this.button1.Content = "Process"; // this line works
        }
    }

In marked line it throws InvalidOperationException "due to the calling thread cannot access this object because a different thread owns it.". But application works if I remove this line.

XAML:
<!-- language: xaml -->
    <Window x:Class="BlackZonesRemover.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:my="clr-namespace:BlackZonesRemover"
            Title="MainWindow" Height="600" Width="800" Loaded="Window_Loaded">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Border Background="LightBlue">
                <Image Name="image1" Stretch="Uniform" />
            </Border>
            <Button Content="Button" Grid.Row="1" Height="23" Name="button1" Width="75" Margin="10" Click="button1_Click" />
        </Grid>
    </Window>

What difference between Image.Source property and Button.IsEnabled and Button.Content properties? What can I do?

like image 582
Maxim Kamalov Avatar asked Jun 13 '11 09:06

Maxim Kamalov


2 Answers

Specific advice: thresholdImage is being created on a background thread. Either create it on the UI thread, or freeze it once it has been created.

General advice: The difference is that ImageSource is a DependencyObject so it has thread affinity. Therefore, you need to create the ImageSource on the same thread as the Image to which you're assigning it (ie. the UI thread), or you need to Freeze() the ImageSource once you've created it, thus allowing any thread to access it.

like image 200
Kent Boogaart Avatar answered Nov 11 '22 12:11

Kent Boogaart


The problem is because thresholdedImage is created in the background thread and used on UI thread.

Calling Freeze method might help. See Updating an Image UI property from a BackgroundWorker thread

like image 23
byte Avatar answered Nov 11 '22 10:11

byte