根据这个答案的说法,我不需要为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.
}
private void ButtonGet_Click(object sender, RoutedEventArgs e)
{
tnc.Test = "new Value";
MessageBox.Show($"{tnc.Test}"); // got "new Value" here!
}
}
在xaml中,除了这个按钮之外,还有一个简单的TextBlock,它绑定到ViewModel的Test属性:
<TextBlock x:Name="OutputId" Text="{Binding Path=Test, Mode=OneWay}"/>
现在发生了什么:
我想达到的目标是:
当我直接在ViewModel上设置测试值时,我可以轻松地完成这个任务--但这似乎不正确,而且与我认为可以构造我的应用程序/代码的东西相去甚远。未来的目标是拥有一个拥有大部分数据的"RecordStore“(静态不起作用)(并从API、本地数据库或内存中获得这些数据)。
所以问题是:
为什么NotifyPropertyChange没有冒泡到视图/视图模型?
或者还有什么我看不出来的问题?
我读过类层次结构中的INotifyPropertyChanged冒泡,通过MVVM的INotifyPropertyChanged属性将ViewModel事件泡起来的好方法是什么?,https://learn.microsoft.com/en-us/dotnet/framework/winforms/how-to-implement-the-inotifypropertychanged-interface,OnPropertyChange调用但对UI没有任何影响
这些问题大多也很古老..。
编辑:
我用这种方式尝试了@MineR的建议:
// made tnc public in ViewModel
public TestNotifyChanged tnc = new TestNotifyChanged();
// changed Binding directly to that (and it's Property):
<TextBlock x:Name="OutputId" Text="{Binding Path=tnc.Test, Mode=OneWay}"/>
不幸的是,现在我甚至没有得到默认,所以我一定是误会了。
EDIT2
我在第一次编辑时做了一件错事:
// this isn't recognized as bindable parameter:
public TestNotifyChanged tnc = new TestNotifyChanged();
// it instead has to be
public TestNotifyChanged tnc { get; }
我将其设置为TNC
,删除了本地Test
参数,直接绑定到Path=TNC.Test
因此,我理解,PropertyChanges并不像我所希望的那样浮出水面,最好直接绑定到嵌套对象。
发布于 2018-07-31 05:29:18
“冒泡”是路由事件的一个概念。像PropertyChanged这样的常规活动不会“泡汤”。
除了ViewModel中明显的bug ViewModel(应该是this.tnc = tnc;
)之外,这两个类的测试属性是不相关的。为了更新自己的Test,ViewModel必须在tnc
注册一个PropertyChanged事件处理程序。当它自己的Test属性发生变化时,它必须更新tnc
的属性。
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private TestNotifyChanged tnc;
public ViewModel(TestNotifyChanged t)
{
tnc = t;
tnc.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(Test) || string.IsNullOrEmpty(e.PropertyName))
{
Test = tnc.Test; // update ViewModel.Test from TestNotifyChanged.Test
}
};
}
private string test;
public string Test
{
get
{
return test; // always return own value
}
set
{
if (test != value)
{
test = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Test)));
tnc.Test = Test; // update TestNotifyChanged.Test from ViewModel.Test
}
}
}
}
或者,删除Test的后备字段,只在tnc.Test
上操作
public class ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private TestNotifyChanged tnc;
public ViewModel(TestNotifyChanged t)
{
tnc = t;
tnc.PropertyChanged += (s, e) =>
{
if (e.PropertyName == nameof(Test) || string.IsNullOrEmpty(e.PropertyName))
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Test)));
}
};
}
public string Test
{
get { return tnc.Test; }
set { tnc.Test = Test; }
}
}
,幸运的是,它根本没有必要.
取而代之的可能是一个公共的Tnc
属性,如
public class ViewModel
{
public TestNotifyChanged Tnc { get; }
public ViewModel(TestNotifyChanged tnc)
{
Tnc = tnc;
}
}
有这样的装订:
<TextBlock Text="{Binding Tnc.Test}"/>
https://stackoverflow.com/questions/51603023
复制相似问题