Как установить свойство Image.Source с помощью Dispatcher?

Я попытался использовать эти рекомендации: http://msdn.microsoft.com/en-us/library/ms741870.aspx («Обработка блокирующей операции с фоновым потоком»).

Это мой код:

  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
        }
    }

В отмеченной строке выдается InvalidOperationException «из-за того, что вызывающий поток не может получить доступ к этому объекту, поскольку им владеет другой поток». Но приложение работает, если я удалю эту строку.

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>

Какая разница между свойством Image.Source и свойствами Button.IsEnabled и Button.Content? Что я могу сделать?


person Maxim Kamalov    schedule 13.06.2011    source источник


Ответы (2)


Конкретный совет: thresholdImage создается в фоновом потоке. Либо создайте его в потоке пользовательского интерфейса, либо заморозьте его после создания.

Общий совет. Разница в том, что ImageSource – это DependencyObject, поэтому он имеет привязку к потоку. Поэтому вам нужно создать ImageSource в том же потоке, что и Image, которому вы его назначаете (т. е. поток пользовательского интерфейса), или вам нужно Freeze() ImageSource после его создания, что позволяет любому потоку получить к нему доступ.

person Kent Boogaart    schedule 13.06.2011

Проблема в том, что thresholdedImage создается в фоновом потоке и используется в потоке пользовательского интерфейса.

Вызов метода Freeze может помочь. См. раздел Обновление свойства пользовательского интерфейса изображения из потока BackgroundWorker.

person byte    schedule 13.06.2011