MVVM INotifyPropertyChanged-线程问题? [英] MVVM INotifyPropertyChanged - Thread issues?

查看:92
本文介绍了MVVM INotifyPropertyChanged-线程问题?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚开始学习MVVM和WPF,非常抱歉提出愚蠢的问题.

I'm just starting to learn MVVM and WPF so sorry for asking stupid questions.

我正在使用不同的教程和示例来学习,并且遇到了

I'm using different tutorials and examples to learn and I come across this example (read Example 2) which I don't understand.

private void RaisePropertyChanged(string propertyName)
{
    // take a copy to prevent thread issues
    PropertyChangedEventHandler handler = PropertyChanged;
    if (handler != null)
    {
        handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

基本上,该评论对我来说意义不大 ...复制副本以防止出现线程问题".

Basically, the comment doesn't make much sense to me... "take a copy to prevent thread issues".

此行:

PropertyChangedEventHandler handler = PropertyChanged;

不会创建新的完全不同的handler对象(不会克隆). 这只是对同一PropertyChanged对象的新引用,对吧?

doesn't create a new, totally different handler object (it's not cloned). It's just a new reference to the same PropertyChanged object, right?

我进行了一些测试以了解实际情况:

I did some tests to find out what is really happening:

PropertyChangedEventHandler handler = PropertyChanged;
var message = "PropertyChanged: " + PropertyChanged.GetHashCode() + "\n";
message += "handler: " + handler.GetHashCode() + "\n";
message += "are equal (1): " + (PropertyChanged.Equals(handler)) + "\n";
message += "are equal (2): " + (PropertyChanged == handler) + "\n";

MessageBox.Show(message);

结果如下:

这证实了我的理论,即这两个对象确实是相同的,而分配只是 NOOP . 我不知道这与线程问题"(从评论中)有什么关系?!?

This confirms my theory that these 2 objects are really the SAME and the assignment is just a NOOP. What I don't understand is how is this related at all with "thread issues" (from the comment)?!?

还有另一件事:经过一番测试(使用一个非常简单的示例),我发现PropertyChanged事件为永不为空. 为什么我们完全需要空检查?

And one more thing: after a bit of testing (using a really simple example) I found out that the PropertyChanged event is never null. Why do we need the null check at all?

在我看来,先前的方法可以简化为:

In my view the previous method can be condensed to just this:

private void RaisePropertyChanged(string propertyName)
{
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}

我进行了一些测试(再次,在一个非常简单的示例中),它似乎工作得很好 ...... 是否有一些捕获物或我找不到的东西?也许我只是发现了不好的例子?

I tested a bit (again, on a really simple example) and it seems to work very well... Is there some catch or something that I didn't find? Maybe I just found bad examples?

无论如何,自从我说我刚刚开始学习WPF和MVVM以来,还有很多我不知道的东西,但是我想了解真正发生的事情,而不仅仅是花一些代码并只是粘贴它,而不了解其原因和工作方式.参见货物崇拜编程

Anyway, there's a lot of stuff I don't know since as I said I just started learning WPF and MVVM, but I want to understand what is really happening, not just take some code and just paste it without understanding why and how it works. See cargo cult programming and magic programming.

好的,根据答案,可以在验证和呼叫之间更改PropertyChanged事件 .此外,PropertyChanged事件可以为空. 但是,我无法重现这些行为...

OK, based on the answers, the PropertyChanged event can be changed between verification and call. More, the PropertyChanged event can be null. However, I haven't been able to reproduce these behaviors...

有人真的可以给我举个例子,说明这两种说法都发生了吗?当然可以帮助您识别类似情况.

Can someone actually give me an example where both statements happen? It would certainly help recognize similar situations.

推荐答案

如果只做

PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

冒着PropertyChanged为null的风险,并且您将获得null引用异常,因此应在事件处理程序不为null之前进行检查.现在,如果您愿意

you risk that PropertyChanged will be null and you'll get null reference exception hence you should check before if event handler is not null. Now if you would do

if (PropertyChanged != null)  
    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

在多线程情况下,您冒着风险,使PropertyChanged在检查和调用之间变为空.为了避免潜在的竞争状况,请将当前委托保留在局部变量中,然后进行检查和调用.

in multi threaded situation you risk that PropertyChanged will become null between check and call. To avoid potential race condition you keep current delegate in local variable and check and call that.

var handler = PropertyChanged;
if (handler != null)
    handler(this, new PropertyChangedEventArgs(propertyName));

这是安全的,因为

代表是一成不变创建后,代理的调用列表不会更改

Delegates are immutable; once created, the invocation list of a delegate does not change

因此,即使在新的委托之间进行PropertyChanged更改,也会创建新的委托,但handler仍将具有您当前的调用列表

so even if PropertyChanged was to change in between new delegate will be created but handler will still have your invocation list as it was at the moment you did

var handler = PropertyChanged;


更新:C#6固定语法

此参数已在C#6中解决,在C#6中,有一个新的运算符可协助处理这种级别的混乱,因为从C#6开始,所有事件处理程序都应使用以下语法作为标准:


Update: C# 6 Fixed Syntax

This argument has been solved in C# 6, where there is a new opertator to assist with dealing with this level of confusion, since C#6, all event handlers should use the following syntax as a standard:

https://codeblog.jonskeet.uk/2015/01/30/clean-event-handlers-invocation-with-c-6/

PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

这篇关于MVVM INotifyPropertyChanged-线程问题?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆