C# 模型由后台线程更新,如何获取对ViewModel的更改?
我有一个模型可以在后台自我更新。目前我在模型上使用INotifyPropertyChanged,但有人告诉我这是个坏主意,因为模型应该是独立于UI的 当模型在MVVM设计模式中发生更改时,是否有用于更新ViewModel的首选模式 该模型应该是独立于用户界面的 …模型当然不应该知道视图,这就是为什么您要让模型(或ViewModel)实现INotifyPropertyChanged,这样视图就可以绑定到模型(或VM)上的属性,并让框架的更改通知通知视图更改(这样您的模型就不需要)C# 模型由后台线程更新,如何获取对ViewModel的更改?,c#,wpf,mvvm,C#,Wpf,Mvvm,我有一个模型可以在后台自我更新。目前我在模型上使用INotifyPropertyChanged,但有人告诉我这是个坏主意,因为模型应该是独立于UI的 当模型在MVVM设计模式中发生更改时,是否有用于更新ViewModel的首选模式 该模型应该是独立于用户界面的 …模型当然不应该知道视图,这就是为什么您要让模型(或ViewModel)实现INotifyPropertyChanged,这样视图就可以绑定到模型(或VM)上的属性,并让框架的更改通知通知视图更改(这样您的模型就不需要) 当然,如果您要根
当然,如果您要根据后台线程的数据对UI进行更改,则需要将它们安全地分派到UI线程-您可以使用标准的.net线程机制(如BackgroundWorker),也可以使用WPF的类。ViewModel的目的是允许模型独立于UI 只需让viewmodel侦听来自模型的事件
public MyViewModel(IView view, IModel model) {
model.SomeEvent += HandleSomeEvent;
....
}
如果要发送INotifyPropertyChanged,需要先切换到uithread
(如果您的模型比viewmodel寿命长,您应该查看一些弱引用事件模式,以允许GC清理viewmodel)两条注释:
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;
}
编辑:我实际上并不建议使用硬编码字符串作为属性名称。下面是一个示例,您可以使用它在使用反射的构造过程中获取属性名称。然后创建一个基类。然后,您可以从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
#区域是可检查的
公共场所是可以检查的
{
收到
{
锁(m_可检查锁)
{
返回m_是可检查的;
}
}
保护集
{
布尔火=假;
锁(m_可检查锁)
{
如果(m_可检查!=值)
{
m_可检查=值;
火=真;
}
}
如果(火灾)
{
NotifyPropertyChanged(m_正在检查);
}
}
}
私有只读对象m_可检查_Lock=new object();
私有布尔m_可检查=false;
静态只读属性ChangedEventArgs m_正在检查=
NotifyPropertyChangedHelper.CreateArgs(o=>
o、 不可检查);
#端区
这就是我对对象进行编码的方式。我确信可以继续使用此“模式”。“如果要发送INotifyPropertyChanged,需要先切换到uithread。”--这不正确。对于使用INotifyPropertyChanged的简单属性绑定,WPF会自动将UI更新发送到UI线程。不需要在UI线程中引发PropertyChanged
事件。例如,请参见该问题的公认答案。@PeterDuniho,我已经很久没有处理过这个问题了,所以我可能完全离开了这里,但我不明白WPF在发起活动时是如何发挥作用的?公认的答案是WPF将在UI线程上调用getter,但这并不意味着在UI线程上调用PropertyChanged事件。如果模型以某种方式进行了PropertyChanged(这是新的PropertyChangedArgs(“prop”))
,则绑定到事件的处理程序将在当前线程上调用。这可能不是问题,但它不同于您期望在UI线程上发生的常规PropertyChanged处理。“这并不意味着PropertyChanged事件是在UI线程上调用的”——我从来没有这样写过。我写的是不需要这样。引发事件时,WPF将处理将其事件处理移动到UI线程的操作。(正如您在回答中所写的)“您需要首先切换到uithread”这一点并不正确。@PeterDuniho,INotifyPropertyChange没有声明“必须在UI线程上调用PropertyChanged”,但由于WPF为您这样做,这很可能是您的意图。还要注意的是,像UWP这样的其他框架要求调用者分派到正确的线程。“因为WPF为您做”——同样,WPF不会在UI线程上引发事件。它处理UI线程上的事件。这是一个非常显著的差异。这里的要点是,发布的问题是关于WPF的,在这种情况下,“您需要先切换到uithread”的说法是不正确的。