模型由后台线程更新,如何获取ViewModel的更改?

时间:2009-12-14 08:33:09

标签: c# wpf mvvm

我有一个在后台更新自己的模型。目前我在模型上使用INotifyPropertyChanged,但我被告知这是一个坏主意,因为模型应该与UI无关。

当模型在MVVM设计模式中发生变化时,是否存在更新ViewModel的首选模式?

3 个答案:

答案 0 :(得分:3)

两条评论:

  1. 关于INotifyPropertyChanged没有固有的UI特定内容。它只是一个界面。您可以在Model对象上自由实现它,并且没有任何问题。
  2. 如果WPF绑定到ViewModel上的属性(Foo)并且您甚至在另一个线程上触发了PropertyChanged事件,WPF实际上会在GUI线程上调用该属性的getter,这样您就不会不得不处理调度员! 警告:如果这样做,请确保您的属性访问者是线程安全的。
  3. 例如:

    class MyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void NotifyPropertyChanged(String info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    
        public MyViewModel(MyModel mdl)
        {
            mdl.PropertyChanged += 
                new PropertyChangedEventHandler(
                    mdl_PropertyChanged);
            _mdl = mdl;
        }
    
        private MyModel _mdl = null;
    
        void mdl_PropertyChanged(object sender, 
            PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "Foo")
            {
                this.Foo = _mdl.Foo;
            }
        }
    
        public int Foo
        {
            get
            {
                lock(_foo_Lock)
                {
                    return _foo;
                }
            }
            set
            {
                lock(_foo_Lock)
                {
                    _foo = value;
                }
                NotifyPropertyChanged("Foo");
            }
        }
        private readonly object _foo_Lock = new object();
        private int _foo = 0;
    }
    

    编辑:我实际上并不建议您使用硬编码字符串作为属性名称。这是一个helper class,您可以使用反射在构造期间获取属性名称。然后创建一个AbstractViewModel基类。然后,您可以从AbstractViewModel继承并实现如下属性:

        #region IsCheckable
        public bool IsCheckable
        {
            get
            {
                lock(m_IsCheckable_Lock)
                {
                    return m_IsCheckable;
                }
            }
            protected set
            {
                bool fire = false;
                lock(m_IsCheckable_Lock)
                {
                    if (m_IsCheckable != value)
                    {
                        m_IsCheckable = value;
                        fire = true;
                    }
                }
                if(fire)
                {
                    NotifyPropertyChanged(m_IsCheckableArgs);
                }
            }
        }
        private readonly object m_IsCheckable_Lock = new object();
        private bool m_IsCheckable = false;
        static readonly PropertyChangedEventArgs m_IsCheckableArgs =
            NotifyPropertyChangedHelper.CreateArgs<MyViewModel>(o => 
                    o.IsCheckable);
        #endregion
    

答案 1 :(得分:2)

  

该模型应该与UI无关。

......好吧,模型当然不应该是意识到的View,这就是为什么你要让你的模型(或ViewModel)实现INotifyPropertyChanged,所以View可以绑定到Model上的Properties (或VM),让框架的更改通知告知更改视图(因此您的模型不需要)

当然,如果您根据后台线程中的数据更改UI,则需要安全地将它们分派到UI线程 - 您可以使用标准.net线程机制(如BackgroundWorker)或者您可以使用WPF的Dispatcher类。

答案 2 :(得分:0)

ViewModel的目的是允许模型独立。

让viewmodel监听模型中的事件

public MyViewModel(IView view, IModel model) {
    model.SomeEvent += HandleSomeEvent;
    ....
}

如果你想发送INotifyPropertyChanged,你需要先切换到uithread。

(如果您的模型比viewmodel长,您应该查看一些弱参考事件模式以允许GC清理视图模型)