【问题标题】:View is not getting notified when value of static Property Changes静态属性值更改时视图未收到通知
【发布时间】:2014-03-12 08:48:14
【问题描述】:

我有一个 ViewModelBase 类如下:

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public static event PropertyChangedEventHandler GlobalPropertyChanged = delegate { };
    public static void OnGlobalPropertyChanged(string propertyName, Type className)
    {
        GlobalPropertyChanged(className,new PropertyChangedEventArgs(propertyName));
    }
}

现在,我有另一个名为 GroupViewModel 的视图模型,它继承了 ViewModelBase:

public class GroupViewModel : ViewModelBase
{
    public GroupsViewModel()
    {
        CurrentGroup = new Group();
    }

    private static Group _currentGroup;
    public static Group CurrentGroup
    {
        get
        {
            return _currentGroup;
        }
        set
        {
            _currentGroup = value;
            OnGlobalPropertyChanged("CurrentGroup", typeof(Group));
        }
    }
}

现在在 Groups.xaml 页面中:

<Grid DataContext="{Binding CurrentGroup}">
    .....
    .....
    <TextBlock Text="{Binding GroupName, TargetNullValue=''}" />
    .....
    .....
</Grid>

我有另一个名为 MainWindowViewModel 的 ViewModel,我尝试将 CurrentGroup 保存到数据库,如下面的代码,然后我设置 CurrentGroup = new Group(); 但在 Group.xaml 中,TextBox 的文本没有被清除:

Group group = GroupViewModel.CurrentGroup;
db.Groups.Add(group);
db.SaveChanges();
GroupViewModel.CurrentGroup = new Group();

更新:

如果我在 GroupsViewModel 中使用以下代码,则输出符合预期。我的意思是当静态属性更改时视图会更新。

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
         = delegate { };
private static void NotifyStaticPropertyChanged(string propertyName)
{
   StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}

如果我在 ViewModelBase 中使用相同的代码(请注意 GroupsViewModel 继承 ViewModelBase),那么当静态属性的值发生更改时,视图不会更新。在这种情况下,我还将 NotifyStaticPropertyChanged 标记为 public 以避免编译时错误,例如有关保护级别的错误。

【问题讨论】:

  • 试用here提供的解决方案。
  • 必须引发视图模型的属性更改事件,静态成员不是实例的成员。
  • @RohitVats 好的,我会尝试并告诉你。
  • @Silvermind 必须引发视图模型的属性更改事件是什么意思?
  • @RohitVats 我无法打开您提供的链接。它只是继续加载.......

标签: c# wpf xaml


【解决方案1】:

对于Static PropertyChanged,你必须在你的类中创建像这样的通用静态事件:

public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
         = delegate { };
private static void NotifyStaticPropertyChanged(string propertyName)
{
   StaticPropertyChanged(null, new PropertyChangedEventArgs(propertyName));
}

而且你必须像使用实例属性一样调用:

NotifyStaticPropertyChanged("CurrentGroup");

但主要问题在于您要绑定的 XAML -

您将在命名空间、类和属性周围使用括号 因为 WPF 绑定引擎将路径解析为 ClassName.PropertyName 而不是 PropertyName.PropertyName。

所以,它会是这样的:

<Grid DataContext="{Binding Path=(local:GroupViewModel.CurrentGroup)}">
  .....
  .....
  <TextBlock Text="{Binding GroupName, TargetNullValue=''}" />
  .....
  .....
</Grid>

来源这里INPC for static properties


更新

如果我在 ViewModelBase 中使用相同的代码(请注意 GroupsViewModel 继承 ViewModelBase) 然后 View 不更新时 静态属性值的变化。

StaticPropertyChangedEvent 必须在属性所在的同一类中。对于实例属性,它不会像传统的 INotifyPropertyChanged 那样工作。

我没有任何 MSDN 文档可以断言,但我通过稍微调整事件代码以查看 XAML 是否从 XAML 连接到 StaticPropertyChangedEvent 来验证它。

把事件代码换成这个就可以看到自己了:

private static event EventHandler<PropertyChangedEventArgs> staticPC
                                                     = delegate { };
public static event EventHandler<PropertyChangedEventArgs> StaticPropertyChanged
{
   add { staticPC += value; }
   remove { staticPC -= value; }
}
protected static void NotifyStaticPropertyChanged(string propertyName)
{
   staticPC(null, new PropertyChangedEventArgs(propertyName));
} 

在 add 上放置一个断点,你会看到它会被命中,因为 WPF 绑定引擎在内部挂钩它以监听静态属性更改事件。

但是,一旦您将其移至基类 ViewModelBase,断点就不会被命中。因为,WPF 没有挂钩,所以任何属性更改都不会明显更新 UI。

【讨论】:

  • 我尝试使用上面的示例,但在 xaml 中出现以下错误:Nested Types are not supported : GroupViewModel.CurrentGroup。另外,在我的问题中,我错过了一些信息。我的 Page 的 DataContext 是 local:GroupViewModel,然后你可以在 qustion 中看到 Grid 的 DataContext 设置为 CurrentGroup 并且 textBox 的 Text 绑定到 GroupName。和你在回答中提到的不一样吗?
  • 您将静态与实例属性混淆了。 DataContext 设置为 GroupViewModel 的实例,但属性是静态的,因此您无法使用对 XAML 也有效的实例对象访问它。您必须像我在更新的答案中那样设置 DataContext 。如果 Grid 中还有其他项目,只需将该 DataContext 移动到 TextBlock 上即可。
  • 现在我没有收到任何错误,但行为仍然相同。我的意思是我的文本框仍然没有清理。
  • 我在小应用程序中进行了尝试,最终运行良好。你能在小应用程序中试试这个吗,或者让我知道制作它的至少确切步骤?
  • 您可以在此处找到演示项目:drive.google.com/file/d/0B5WyqSALui0bUW1HVk9mWjIzVk0/… 但我在该项目中遇到错误:密钥不能为空。参数名称键。
【解决方案2】:

每当您想更新特定数据类型的属性更改时,您都需要在该数据类型中实现INotifyPropertyChanged 接口。这意味着如果您想更新视图模型的属性更改,在您的情况下更改CurrentGroup 对象,您需要在视图模型中实现INotifyPropertyChanged 接口 .

但是,您似乎实际上想要更新在CurrentGroup内部进行的属性更改(以清除它们),因此在这种情况下,您还需要在 CurrentGroup 类中实现 INotifyPropertyChanged 接口。我相信这就是@Silvermind 的意思您需要引发与实例关联的事件

【讨论】:

    猜你喜欢
    • 2016-12-30
    • 1970-01-01
    • 1970-01-01
    • 2018-03-30
    • 1970-01-01
    • 1970-01-01
    • 2012-03-12
    • 2020-02-10
    相关资源
    最近更新 更多