【发布时间】:2021-06-23 09:43:55
【问题描述】:
在 ViewModel 中,我有一个本身实现 INotifyPropertyChanged 的属性。绑定到 DependencyProperty 时,即使我提高了属性更改,当我仅在绑定到 DependencyProperty 的当前实例上设置属性时,我也不会进入 DependencyProperty 更改的回调。 (详情见下方代码)
为什么这个构造会失败?
实现我想要的一种方法是在每次更改其属性时将 CurrentFoobar 设置为新实例。
是否存在更漂亮的方法来实现想要的行为?
编辑: 我知道这个特定的示例可能看起来无关紧要,因为可以简单地绑定到 TextBlocks Text 属性。但是,我有兴趣为不公开与 TextBlock 不同的正确依赖属性的控件做 类似的操作。
代码
我有一个 ViewModel,其属性为 Foobar 类型的“CurrentFoobar”。
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
var foobar = new Foobar() {Foo = "Hello", Bar = 42};
CurrentFoobar = foobar;
updateCommand = new UpdateCommand(this);
}
private UpdateCommand updateCommand;
public ICommand UpdateCommand
{
get => updateCommand;
}
private Foobar _curfoobar;
public Foobar CurrentFoobar
{
get => _curfoobar;
set
{
_curfoobar = value;
_curfoobar.PropertyChanged += (s, e) => OnPropertyChanged();
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Foobar 是一个具有两个属性 string Foo 和 int Bar 的类。 Foobar 实现 INotifyPropertyChanged。
public class Foobar : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private string _foo;
public string Foo
{
get => _foo;
set
{
_foo = value;
OnPropertyChanged();
}
}
private int _bar;
public int Bar
{
get => _bar;
set
{
_bar = value;
OnPropertyChanged();
}
}
}
在 CurrentFoobar 设置器中,我订阅了当前 Foobar 实例上的 PropertyChanged,并引发 OnPropertyChanged。
private Foobar _curfoobar;
public Foobar CurrentFoobar
{
get => _curfoobar;
set
{
_curfoobar = value;
_curfoobar.PropertyChanged += (s, e) => OnPropertyChanged();
OnPropertyChanged();
}
}
此外,我有一个带有 CustomControl 的视图,它公开了一个 DependencyProperty“FoobarProperty”。 我将此 DependencyProperty 绑定到我的 ViewModels CurrentFoobar。
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
public static readonly DependencyProperty FoobarProperty = DependencyProperty.Register(
"Foobar", typeof(Foobar), typeof(UserControl1), new PropertyMetadata(default(Foobar), FoobarPropertyChangedCallback));
private static void FoobarPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uc1 = d as UserControl1;
var newfb = e.NewValue as Foobar;
uc1.TextBlock1.Text = newfb.Foo;
uc1.TextBlock2.Text = newfb.Bar.ToString();
}
public Foobar Foobar
{
get { return (Foobar) GetValue(FoobarProperty); }
set { SetValue(FoobarProperty, value); }
}
}
如果我将 CurrentFoobar 设置为 Foobar 的新实例,则 DependencyProperty 会按预期更新。但是,如果我只是更改 CurrentFoobar 的当前实例的属性,它不会。自从我提出 CurrentFoobar 的属性更改后,我本来希望它会更新。
为了更好的衡量,这里是更新命令:
public class UpdateCommand : ICommand
{
private MainViewModel _vm;
public UpdateCommand(MainViewModel vm)
{
_vm = vm;
}
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
_vm.CurrentFoobar.Foo = "World";
_vm.CurrentFoobar.Bar = 84;
}
public event EventHandler CanExecuteChanged;
}
【问题讨论】:
-
"我希望它会更新,因为我提出了 CurrentFoobar 的属性更改。" - 不是那样工作的
-
在 xaml 中使用绑定而不是
uc1.TextBlock1.Text = newfb.Foo; uc1.TextBlock2.Text = newfb.Bar.ToString(); -
@ASh 不,显然不。你知道原因吗?我本来希望 DependencyProperty 侦听 PropertyChanged 事件。抱歉没有发布 xaml - CurrentFoobar 绑定到 xaml 中的 FoobarProperty 为:
。
标签: c# wpf data-binding dependency-properties inotifypropertychanged