Изменяется ли привязка данных WPF к потоку пользовательского интерфейса? - PullRequest
16 голосов
/ 24 августа 2009

Я только что заметил, что при изменении связанных свойств в моем ViewModel (MVVM) из фонового рабочего потока я не получаю никаких исключений, и представление обновляется правильно. Означает ли это, что я могу смело полагаться на привязку данных wpf, отслеживая все изменения в потоке пользовательского интерфейса ViewModel? Я думаю, что где-то читал, что нужно убедиться (в ViewModel), что INotifyPropertyChanged.PropertyChanged запускается в потоке пользовательского интерфейса. Это изменилось в 3.5 или что-то?

Ответы [ 2 ]

14 голосов
/ 24 августа 2009

Да для скаляров, нет для коллекций. Для коллекций вам понадобится специализированная коллекция, которая предназначена для вас, или вы можете вручную выполнить маршалинг потока пользовательского интерфейса через Dispatcher.

Возможно, вы прочитали, что INotifyCollectionChanged.CollectionChanged должен запускаться в потоке пользовательского интерфейса, потому что это просто не соответствует INotifyPropertyChanged.PropertyChanged. Ниже приведен очень простой пример, подтверждающий изменения свойств маршалов WPF.

Window1.xaml.cs

using System.ComponentModel;
using System.Threading;
using System.Windows;

namespace WpfApplication1
{
    public partial class Window1 : Window
    {
        private CustomerViewModel _customerViewModel;

        public Window1()
        {
            InitializeComponent();
            _customerViewModel = new CustomerViewModel();
            DataContext = _customerViewModel;

            var thread = new Thread((ThreadStart)delegate
            {
                while (true)
                {
                    Thread.Sleep(2000);
                    //look ma - no marshalling!
                    _customerViewModel.Name += "Appended";
                    _customerViewModel.Address.Line1 += "Appended";
                }
            });

            thread.Start();
        }
    }

    public abstract class ViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected void OnPropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;

            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }

    public class CustomerViewModel : ViewModel
    {
        private string _name;
        private AddressViewModel _address = new AddressViewModel();

        public string Name
        {
            get { return _name; }
            set
            {
                if (_name != value)
                {
                    _name = value;
                    OnPropertyChanged("Name");
                }
            }
        }

        public AddressViewModel Address
        {
            get { return _address; }
        }
    }

    public class AddressViewModel : ViewModel
    {
        private string _line1;

        public string Line1
        {
            get { return _line1; }
            set
            {
                if (_line1 != value)
                {
                    _line1 = value;
                    OnPropertyChanged("Line1");
                }
            }
        }
    }
}

Window1.xaml

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="300">
    <StackPanel>
        <TextBox Text="{Binding Name}"/>
        <TextBox Text="{Binding Address.Line1}"/>
    </StackPanel>
</Window>
1 голос
/ 28 октября 2009

Я полагаю, что в 2.0 и предыдущих воплощениях .NET вы получили бы InvalidOperationException из-за сходства потоков при выполнении вышеупомянутого примера (ссылка, опубликованная bitbonk, датирована 2006 г.).

Теперь, с 3.5, WPF, похоже, направляет изменения свойства фонового потока в диспетчер для вас.

Итак, в общем, зависит от того, на какую версию .NET вы ориентируетесь. Надеюсь, это устранит любую путаницу.

Один из моих коллег по Lab49 опубликовал здесь блог в 2007 году:

http://blog.lab49.com/archives/1166

...