【问题标题】:NotifyOfPropertyChange() is not notifying viewmodel propertiesNotifyOfPropertyChange() 不通知视图模型属性
【发布时间】:2017-06-02 17:13:09
【问题描述】:

我有一个简单的 WPF 应用程序,我想知道为什么 NotifyOfPropertyChange() 没有按预期工作。我有一个带有两个属性和一个按钮的 MainWindowViewModel,当我单击该按钮时,我调用 NotifyOfPropertyChange() 来通知所有属性都已更改。我还有一个在 ViewModel 构造函数中编译的属性列表:

properties = typeof(MainWindowViewModel).GetProperties()
    .Where(p => p.DeclaringType == typeof(MainWindowViewModel));

在构造函数中,我已经订阅了PropertyChanged:

PropertyChanged += (sender, args) =>
{
    if (properties.Any(p => p.Name == args.PropertyName))
        IsDirty = true;
};

这是我的整个 MainViewModel:

public class MainWindowViewModel : Screen
{
    private string name;
    private IEnumerable<PropertyInfo> properties;

    public string Name
    {
        get { return name; }
        set
        {
            name = value;
            NotifyOfPropertyChange(() => Name);
        }
    }

    private int age;

    public int Age
    {
        get { return age; }
        set
        {
            age = value;
            NotifyOfPropertyChange(() => Age);
        }
    }

    private bool isDirty;

    public bool IsDirty
    {
        get { return isDirty; }
        set
        {
            isDirty = value;
            NotifyOfPropertyChange(() => IsDirty);
        }
    }

    public MainWindowViewModel()
    {
        // get list of class properties
        properties = typeof(MainWindowViewModel).GetProperties()
            .Where(p => p.DeclaringType == typeof(MainWindowViewModel));


        // if any property has been updated, set isDirty to true
        PropertyChanged += (sender, args) =>
        {
            if (properties.Any(p => p.Name == args.PropertyName))
                IsDirty = true;
        };

    }

    public void Save()
    {
        NotifyOfPropertyChange();
    }
}

当应用程序运行时,构造函数会正确生成属性列表:Name、Age 和 IsDirty。但是,当单击“保存”按钮时, PropertyChangedEvent 为与视图模型无关的其他属性引发:IsInitialized 和 IsActive,它们是屏幕的属性,并且不会为列表中的任何属性引发。有人可以告诉我这里发生了什么或提供替代解决方案吗?我认为我要做什么很清楚,这是一个验证场景,如果单击保存按钮,我需要调用 PropertyChanged 并设置一个标志,以便可以验证所有属性。

【问题讨论】:

  • 在 MainWindowViewModel 中任何属性的设置器上设置断点。二传手真的被调用了吗? (如果是,继续单步执行 setter 进入 NotifyOfPropertyChange 的代码,看看该方法到底在做什么......)
  • 不,我不相信 NotifyOfPropertyChange() 调用实际的设置器。
  • 好吧,当然 NotifyOfPropertyChange 没有调用 setter。请注意,该方法不称为“RequestPropertyChange”或“ChangeProperty”,而是称为“NotifyOfPropertyChange”......明白了吗? :-) 那么,在您的代码中,您的某个属性的设置器在哪里调用?
  • 我没有调用任何设置器,也没有设置任何实际属性。我只是在没有参数的情况下调用 NotifyOfPropertyChange(),以便在所有属性上调用 PropertyChanged 事件。它正在被调用,只是没有在我的视图模型中的任何属性上。
  • 啊,我明白了。 NotifyOfPropertyChange() 是 CalibrunMicro 的一项功能,对吗?等一下……

标签: c# wpf mvvm caliburn.micro


【解决方案1】:

NotifyOfPropertyChange() 方法的方法签名是:

public virtual void NotifyOfPropertyChange([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null)

(链接到 Caliburn.Micro github 存储库:https://github.com/Caliburn-Micro/Caliburn.Micro/blob/master/src/Caliburn.Micro/PropertyChangedBase.cs#L44

注意CallerMemberName 属性。

Save 方法中调用它,如NotifyOfPropertyChange(); 将导致 PropertyChanged 事件,其中 PropertyChangedEventArgs.PropertyName 设置为“Save”(名称调用 NotifyOfPropertyChange()) 的方法。这当然没有意义。

要表明您的类中的任何属性已更改,您必须显式传递 null"" 作为 NotifyOfPropertyChange 的参数(有效地绕过 CallerMemberName 替换):

public void Save()
{
    NotifyOfPropertyChange(null);
}

传递null 或空字符串作为属性名称是有效的。没有属性名称的 PropertyChanged 事件表明任何一个或多个属性已更改其值。

考虑到这一点,PropertyChanged 事件处理程序也应该得到改进,以正确尊重没有属性名称的 PropertyChanged 事件:

PropertyChanged += (sender, args) =>
{
    if (string.IsNullOrEmpty(args.PropertyName) || properties.Any(p => p.Name == args.PropertyName))
        IsDirty = true;
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-14
    • 2014-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-02
    • 1970-01-01
    • 2012-09-02
    相关资源
    最近更新 更多