OnPropertyChanged 二级更新
OnPropertyChanged 2nd level update
搜索没有给我带来任何线索,我有点不知所措。
WPF 到目前为止都是自学的,所以我可能会忽略一些简单的东西。
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<TextBlock Text={Binding BoundTextProperty}"/>
这是简化的 xml
public class MainViewModel
{
private Model Data;
public MainViewModel()
{...}
public string BoundTextProperty => Data.BoundTextProperty;
...
}
绑定的 属性 引用 属性 在模型中保存数据
public class Model : INotifyPropertyChanged
{
private long number;
public long Number
{
get { return number; }
set
{
number = value;
OnPropertyChanged(nameof(BoundTextProperty));
}
}
public string BoundTextProperty => $"Some text {Number} some text again";
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我发誓它在某些时候起作用了。
该字符串还有一些其他变量,但这是它工作原理的基本原理,或者更确切地说不是。
我的问题是 Binding 是否真的可以冒泡,如果可以,为什么不呢?
您必须添加代码以将 Model 的 PropertyChanged 事件从 ViewModel 冒泡到 View。
这是一个示例(基于您的代码):
public class MainViewModel : ViewModelBase
{
private readonly Model Data;
public MainViewModel()
{
Data = new Model();
Data.PropertyChanged += ModelOnPropertyChanged;
}
private void ModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(Model.BoundTextProperty):
OnPropertyChanged(nameof(MainViewModel.BoundTextProperty));
break;
// add cases for other properties here:
}
}
public string BoundTextProperty => Data.BoundTextProperty;
}
public class Model : ModelBase
{
private long number;
public long Number
{
get { return number; }
set
{
number = value;
OnPropertyChanged(nameof(BoundTextProperty));
}
}
public string BoundTextProperty => $"Some text {Number} some text again";
}
public abstract class ViewModelBase : Base
{
// add other ViewModel related stuff here
}
public abstract class ModelBase : Base
{
// add other Model related stuff here
}
public abstract class Base : INotifyPropertyChanged
{
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
您需要为您在 XAML 中绑定的源 属性 引发 PropertyChanged
事件。在这种情况下,您绑定到 MainViewModel
的 BoundTextProperty
,这意味着 MainViewModel
class 应该引发 PropertyChanged
事件。
来源 属性 是否包含引发 PropertyChanged
事件的 class 的另一个 属性 并不重要。它是通知视图的绑定的源对象。
您也可以直接绑定到 "model" 属性,前提是您在视图模型中将 Data
转换为 public 属性:
public Model Data { get; private set; }
...
<TextBlock Text="{Binding Data.BoundTextProperty}"/>
如果您选择坚持使用包装器 属性,MainViewModel
必须实施 INotifyPropertyChanged
事件并在模型更新时引发 PropertyChanged
事件:
public class MainViewModel : INotifyPropertyChanged
{
private readonly Model Data;
public MainViewModel()
{
Data = new Model();
Data.PropertyChanged += Data_PropertyChanged;
}
private void Data_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged("BoundTextProperty");
}
public string BoundTextProperty => Data.BoundTextProperty;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
搜索没有给我带来任何线索,我有点不知所措。 WPF 到目前为止都是自学的,所以我可能会忽略一些简单的东西。
<Window.DataContext>
<local:MainViewModel/>
</Window.DataContext>
<TextBlock Text={Binding BoundTextProperty}"/>
这是简化的 xml
public class MainViewModel
{
private Model Data;
public MainViewModel()
{...}
public string BoundTextProperty => Data.BoundTextProperty;
...
}
绑定的 属性 引用 属性 在模型中保存数据
public class Model : INotifyPropertyChanged
{
private long number;
public long Number
{
get { return number; }
set
{
number = value;
OnPropertyChanged(nameof(BoundTextProperty));
}
}
public string BoundTextProperty => $"Some text {Number} some text again";
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
我发誓它在某些时候起作用了。 该字符串还有一些其他变量,但这是它工作原理的基本原理,或者更确切地说不是。
我的问题是 Binding 是否真的可以冒泡,如果可以,为什么不呢?
您必须添加代码以将 Model 的 PropertyChanged 事件从 ViewModel 冒泡到 View。 这是一个示例(基于您的代码):
public class MainViewModel : ViewModelBase
{
private readonly Model Data;
public MainViewModel()
{
Data = new Model();
Data.PropertyChanged += ModelOnPropertyChanged;
}
private void ModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
switch (e.PropertyName)
{
case nameof(Model.BoundTextProperty):
OnPropertyChanged(nameof(MainViewModel.BoundTextProperty));
break;
// add cases for other properties here:
}
}
public string BoundTextProperty => Data.BoundTextProperty;
}
public class Model : ModelBase
{
private long number;
public long Number
{
get { return number; }
set
{
number = value;
OnPropertyChanged(nameof(BoundTextProperty));
}
}
public string BoundTextProperty => $"Some text {Number} some text again";
}
public abstract class ViewModelBase : Base
{
// add other ViewModel related stuff here
}
public abstract class ModelBase : Base
{
// add other Model related stuff here
}
public abstract class Base : INotifyPropertyChanged
{
public virtual event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
您需要为您在 XAML 中绑定的源 属性 引发 PropertyChanged
事件。在这种情况下,您绑定到 MainViewModel
的 BoundTextProperty
,这意味着 MainViewModel
class 应该引发 PropertyChanged
事件。
来源 属性 是否包含引发 PropertyChanged
事件的 class 的另一个 属性 并不重要。它是通知视图的绑定的源对象。
您也可以直接绑定到 "model" 属性,前提是您在视图模型中将 Data
转换为 public 属性:
public Model Data { get; private set; }
...
<TextBlock Text="{Binding Data.BoundTextProperty}"/>
如果您选择坚持使用包装器 属性,MainViewModel
必须实施 INotifyPropertyChanged
事件并在模型更新时引发 PropertyChanged
事件:
public class MainViewModel : INotifyPropertyChanged
{
private readonly Model Data;
public MainViewModel()
{
Data = new Model();
Data.PropertyChanged += Data_PropertyChanged;
}
private void Data_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
OnPropertyChanged("BoundTextProperty");
}
public string BoundTextProperty => Data.BoundTextProperty;
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}