【问题标题】:C# WPF INotifyPropertyChanged not updating formC# WPF INotifyPropertyChanged 不更新表单
【发布时间】:2021-08-25 17:51:49
【问题描述】:

我正在尝试使用基于用户输入的一些计算来实现一个表单。使用 MVVM 模式,特别是 INotifyPropertyChanged。

当用户在文本框中输入一个值,计算例程被触发,并且表单随结果更新时,一切都很好。

但是,当从代码隐藏更改输入时,Inotify 例程会触发,计算完成,但绑定的控件不会更新。

我有两个问题:

  1. 使用框架内的页面,我想在页面改变时触发刷新
  2. 导入以前保存在 Xml 文件中的数据。同样,例程会触发,但不会更新表单的绑定控件。

我附上了代码的精简版本,但这并不是我认为的真正问题。注意我使用的是单例类。

谢谢

================

//INotify code
using s = Calc.Models.GlobalStrings;

namespace Calc.ViewModels.INotify
{
    public class UcIOChanged : INotifyPropertyChanged
    {
        private static UcIOChanged instance;
        public UcIOChanged() { }

        //Make the class is a singleton
        public static UcIOChanged Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new UcIOChanged();
                }
                return instance;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        public string Pressure 
        { 
            get 
            { 
                return s.Pressure; 
            } 
            set 
            { 
                s.Pressure = value; OnPropertyChanged(); 
            } 
        }

        public void OnPropertyChanged()
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Pressure)));

        }
    }
}

【问题讨论】:

  • 这可能会有所帮助。在绑定到 Pressure 属性的 UI 元素上,尝试以下 UpdateSourceTrigger=PropertyChanged.. 例如
  • 请注意,nameof(Pressure) 绝对不应该在 OnPropertyChanged 方法中。应该有一个字符串参数,并且应该像OnPropertyChanged(nameof(Pressure));一样调用该方法
  • @Saurav 所说的不正确。 UpdateSourceTrigger=PropertyChanged 与 INotifyPropertyChanged 接口的 PropertyChanged 事件无关。它控制其他绑定方向(从目标到源)的工作方式,并且对 OneWay 绑定(仅从源到目标)没有任何影响。
  • 关于@Saurav 评论,我在 XML 中确实有这样的代码。此外,当一个输入属性发生变化时,它会更新许多其他绑定结果,这在我提供的代码示例中没有显示。

标签: c# wpf inotifypropertychanged


【解决方案1】:

注意我使用的是单例类。

这段代码没有错误。 但是您可能使用不正确。 为避免意外使用错误,我建议您更改实现:

public class UcIOChanged
{
    // Hide the constructor to avoid
    // accidentally creating other instances.
    private UcIOChanged() {}

    //Make the class is a singleton
    public static UcIOChanged Instance { get; } = new UcIOChanged();

    public string Pressure
    {
        get
        {
            return s.Pressure;
        }
        set
        {
            if (!Equals(s.Pressure, value))
            {
                s.Pressure = value;
                PressureChanged?.Invoke(this, EventArgs.Empty);
            }

        }
    }

    // The event of the same name.
    // It's easier for one or two properties
    // than the INotifyPropertyChanged implementation.
    public event EventHandler PressureChanged;
}

使用:

    <TextBox Text="{Binding Pressure, Source={x:Static local:UcIOChanged.Instance}}"/>

P.S.如果您在代码中的某处更改 s.Pressure 而不是通过 UcIOChanged.Instance 的实例,则可能会影响正确操作。
因此,您必须确保只有在通知其更改时才能访问此变量(属性或字段?)。

【讨论】:

  • 它比 INotifyPropertyChanged 实现更容易......”对于多个属性来说可能是不正确的,当您可以只写 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Pressure))) 而不是 PressureChanged?.Invoke(this, EventArgs.Empty) 时,但只声明一个事件而不是每个属性一个。不需要 OnPropertyChanged 方法。当然你必须声明接口实现。
  • 好吧,对于两个来说这不是真的:-)
  • 错误不在类的实现中。如果您创建了多个UcIOChanged 实例,则可能会发生意外错误。这正是我在示例中展示的内容。使用另一个事件是次要的,并不重要。这只是附加信息。隐藏实例构造函数很重要。如果这没有帮助,那么我们需要弄清楚你如何使用这个类。这需要重现问题的解决方案的最小示例。
  • 另外,请务必注意,在计算逻辑中,您应该始终仅通过UcIOChanged.Instance 实例访问s.Pressure 变量。无论您在哪里进行这些计算。
  • 要获取 XAML 中的实例,您必须使用 x: 静态标记扩展。在我的示例中仔细查看我是如何获取 Source 以进行绑定的。也可以为数据上下文或其他一些属性获取它。
猜你喜欢
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-12
  • 2014-06-02
相关资源
最近更新 更多