问题:
我正在开发一个 WPF 应用程序,使用 MVVM 模式 和 CommunityToolkit.Mvvm 包来处理
ObservableProperty
和 INotifyPropertyChanged
。但是,在将复杂模型对象(例如,Settings
)绑定到 ViewModel 时,我遇到了问题。设置如下:
Settings
模型类,它继承自 ObservableObject
(来自 CommunityToolkit)并包含多个属性:public partial class Settings : ObservableObject
{
[ObservableProperty]
private string serverPath;
[ObservableProperty]
private string updatePath;
// Other properties...
}
ObservableProperty
属性来声明 Settings 对象:public partial class MyViewModel : ObservableObject
{
[ObservableProperty]
private Settings _settings; // Loading via another method
partial void OnSettingsChanged(Settings value)
{
//Not fire when change value of Settings
}
}
<TextBox Text="{Binding Settings.serverPath, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
问题:
数据绑定的工作原理是,对 TextBox 的更改反映在
serverPath
对象的 Settings
属性中。但是,当 PropertyChanged
内部的属性更改时,不会触发 ViewModel 中的 Settings
事件,因此在某些情况下 UI 无法正确更新。
我希望
[ObservableProperty]
属性能够自动处理此问题,但似乎当我修改 Settings
内部的属性时,ViewModel 不会收到有关这些内部更改的通知。
问题:
为什么 ViewModel 中的
ObservableProperty
属性不处理像 Settings 这样的复杂模型对象内部的更改?我是否遗漏了 ObservableProperty
与实现 INotifyPropertyChanged
的嵌套对象一起工作的方式?有没有办法在不手动订阅 PropertyChanged 的情况下完成这项工作?
有没有办法让
ObservableProperty
属性在像PropertyChanged
这样的复杂对象中的属性被修改时自动触发Settings
?或者这是 ObservableProperty 在实现 INotifyPropertyChanged
的模型对象上下文中的限制?
如果可能的话,我不想手动处理
PropertyChanged
事件,如我的解决方法所示。任何关于为什么会发生这种行为以及如何解决它的见解将不胜感激!
手动解决方法:
我找到了一种手动解决方法,即显式处理 ViewModel 中 Settings 对象的 PropertyChanged 事件。这是可行的解决方案,但我想知道是否有办法避免这种情况:
public partial class MyViewModel : ObservableObject
{
private Settings _settings;
public Settings Settings
{
get => _settings;
set
{
if (_settings != null)
{
// Unsubscribe from the previous Settings object's PropertyChanged event
_settings.PropertyChanged -= Settings_PropertyChanged;
}
SetProperty(ref _settings, value); // Set the new value for _settings
if (_settings != null)
{
// Subscribe to the new Settings object's PropertyChanged event
_settings.PropertyChanged += Settings_PropertyChanged;
}
}
}
private void Settings_PropertyChanged(object? sender, PropertyChangedEventArgs e)
{
// Notify the UI about the Settings object change
OnPropertyChanged(nameof(Settings));
}
public MyViewModel()
{
Settings = new Settings();
}
}
你的解释有些自相矛盾。 因此,我的回答将部分基于我的猜测。
<TextBox Text="{Binding Settings.serverPath,
注意名称中字符的大小写。
serverPath
是私有字段。代码生成器使用它来创建 ServerPath
属性。这就是应该创建绑定的目的。为什么这是我的猜测...? 在您的实现中,一切都正常工作
Manual Workaround
,您已经明确指定了一个以 Upper Litter 开头的属性。但您没有写到您更改了 XAML 中的绑定路径。并且 serverPath
路径也不适合您的实现。这个矛盾让我有点困惑。
另一个不清楚的点是如何更改
Settings
属性的值,这确保了 _settings
字段的工作。该通知仅在使用属性时才能正常工作,但在使用字段时则无法正常工作。
public void SomeLoadMethod()
{
// Correct
Settings = new Settings();
// incorrect
_settings = new Settings();
}