冒泡 NotifyPropertyChanged

根据这个答案,我不需要担心 NotifyPropertyChanges 冒泡层次结构,但我仍然无法使用这样的(简化的测试-)结构:


数据保持类


public class TestNotifyChanged : INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;


    private string _Test = "default";

    public string Test

    {

        get

        {

            return _Test;

        }

        set

        {

            if(_Test!=value)

            {

                _Test = value;

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Test"));

            }

        }

    }

}

使用该测试类和测试属性的 ViewModel:


public class ViewModel : INotifyPropertyChanged

{

    public event PropertyChangedEventHandler PropertyChanged;


    private TestNotifyChanged tnc = new TestNotifyChanged(); // only to init, otherwise VS screams at me


    public ViewModel(TestNotifyChanged tnc)

    {

        tnc = tnc; // getting an instance of TestNotifyChanged from "Master" passed in, which hopefully will be replaces by a singleton class.

    }


    private string _Test;

    public string Test

    {

        get

        {

            return tnc.Test;  // this might be the crucial part!?

        }

        set

        {

            if (_Test != value) // never hits that, as I would expect, but you never know..

            {

                _Test = value;

                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("Test"));  // of course also never hit, as expected

            }

        }

    }

}

最后是我的 MainWindow cs


public partial class MainWindow : Window

{

    TestNotifyChanged tnc;

    public MainWindow()

    {

        InitializeComponent();

        tnc = new TestNotifyChanged();

        DataContext = new ViewModel(tnc); // pass in my Test-Object that has the Values.

    }


现在发生了什么:

  • 默认值“default”显示在 TextBlock 中。

  • 当我单击按钮时,消息框显示“新值”

  • TextBlock更新为“新值”

我想要达到的目标:

  • 看起来很简单:TextBlock 应该更新为“新值”

当我直接在 ViewModel 上设置测试值时,我可以轻松地完成这项工作- 但这似乎不正确,并且与我认为我可以构建我的应用程序/代码的方式相去甚远。未来的目标是拥有一个单例(我发现静态不起作用)“RecordStore”,它包含大部分数据(并从 API、本地数据库或仅从内存中获取它,如果其中任何一个完成)

所以问题是:
为什么 NotifyPropertyChange 没有冒泡到 View/ViewModel?
或者还有其他我没有看到的问题?


不负相思意
浏览 378回答 1
1回答

至尊宝的传说

“冒泡”是路由事件的概念。像 PropertyChanged 这样的常规事件不会“冒泡”。除了tnc = tnc;ViewModel 中的明显错误(应该是this.tnc = tnc;)之外,这两个类的 Test 属性是不相关的。为了更新自己的 Test 属性,ViewModel 必须在 处注册一个 PropertyChanged 事件处理程序tnc。并且它必须tnc在其自身的 Test 属性更改时更新该属性。public class ViewModel : INotifyPropertyChanged{&nbsp; &nbsp; public event PropertyChangedEventHandler PropertyChanged;&nbsp; &nbsp; private TestNotifyChanged tnc;&nbsp; &nbsp; public ViewModel(TestNotifyChanged t)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; tnc = t;&nbsp; &nbsp; &nbsp; &nbsp; tnc.PropertyChanged += (s, e) =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (e.PropertyName == nameof(Test) || string.IsNullOrEmpty(e.PropertyName))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Test = tnc.Test; // update ViewModel.Test from TestNotifyChanged.Test&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; private string test;&nbsp; &nbsp; public string Test&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; get&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return test; // always return own value&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; set&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (test != value)&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; test = value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Test)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; tnc.Test = Test; // update TestNotifyChanged.Test from ViewModel.Test&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}或者,删除 Test 属性的支持字段并仅操作tnc.Test:public class ViewModel : INotifyPropertyChanged{&nbsp; &nbsp; public event PropertyChangedEventHandler PropertyChanged;&nbsp; &nbsp; private TestNotifyChanged tnc;&nbsp; &nbsp; public ViewModel(TestNotifyChanged t)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; tnc = t;&nbsp; &nbsp; &nbsp; &nbsp; tnc.PropertyChanged += (s, e) =>&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (e.PropertyName == nameof(Test) || string.IsNullOrEmpty(e.PropertyName))&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Test)));&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; };&nbsp; &nbsp; }&nbsp; &nbsp; public string Test&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; get { return tnc.Test; }&nbsp; &nbsp; &nbsp; &nbsp; set { tnc.Test = Test; }&nbsp; &nbsp; }}幸运的是,这完全没有必要。相反,可能只是一个公共Tnc财产,如public class ViewModel{&nbsp; &nbsp; public TestNotifyChanged Tnc { get; }&nbsp; &nbsp; public ViewModel(TestNotifyChanged tnc)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; Tnc = tnc;&nbsp; &nbsp; }}使用这样的绑定:<TextBlock Text="{Binding Tnc.Test}"/>
打开App,查看更多内容
随时随地看视频慕课网APP