ViewModel 中的 ObservableProperty 不会触发 WPF 中模型对象的 PropertyChanged

问题描述 投票:0回答:1

问题:

我正在开发一个 WPF 应用程序,使用 MVVM 模式CommunityToolkit.Mvvm 包来处理

ObservableProperty
INotifyPropertyChanged
。但是,在将复杂模型对象(例如,
Settings
)绑定到 ViewModel 时,我遇到了问题。
由于我仍在学习 WPF 和 MVVM 概念,因此我还没有深入了解一切是如何工作的,并且我可能会在这里遗漏一些重要的东西。

设置如下:

  1. 我有一个
    Settings
    模型类,它继承自
    ObservableObject
    (来自 CommunityToolkit)并包含多个属性:
public partial class Settings : ObservableObject
{
    [ObservableProperty]
    private string serverPath;

    [ObservableProperty]
    private string updatePath;

    // Other properties...
}
  1. 在我的 ViewModel 中,我最初使用
    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     
    }
}
  1. 在我的视图中,我设置了与“设置”属性的双向绑定,如下所示:
<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();
    }

}
c# wpf community-toolkit-mvvm
1个回答
0
投票

你的解释有些自相矛盾。 因此,我的回答将部分基于我的猜测。

<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();
    }
© www.soinside.com 2019 - 2024. All rights reserved.