You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# WPF MVVM模式下多ViewModel与共享Model双向同步方案咨询

推荐实现方案

1. 核心优化思路:让Model层自带变更通知能力

当前架构的核心问题是Model类为无通知的哑类,才需要额外维护ViewModel和Model的双向同步逻辑,以及多ViewModel间的同步逻辑。首先改造Model层,让其实现INotifyPropertyChanged接口:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class SampleModel : INotifyPropertyChanged
{
    private string _material;
    public string Material
    {
        get => _material;
        set
        {
            if (_material == value) return;
            _material = value;
            OnPropertyChanged();
        }
    }

    private double _weight;
    public double Weight
    {
        get => _weight;
        set
        {
            if (_weight == value) return;
            _weight = value;
            OnPropertyChanged();
        }
    }

    private double _length;
    public double Length
    {
        get => _length;
        set
        {
            if (_length == value) return;
            _length = value;
            OnPropertyChanged();
        }
    }

    private double _width;
    public double Width
    {
        get => _width;
        set
        {
            if (_width == value) return;
            _width = value;
            OnPropertyChanged();
        }
    }

    private double _height;
    public double Height
    {
        get => _height;
        set
        {
            if (_height == value) return;
            _height = value;
            OnPropertyChanged();
        }
    }

    private object _sharedProperty;
    public object SharedProperty
    {
        get => _sharedProperty;
        set
        {
            if (Equals(_sharedProperty, value)) return;
            _sharedProperty = value;
            OnPropertyChanged();
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 简化ViewModel实现,消除循环调用

在ViewModel基类中增加初始化状态标志,即可解决构造函数调用链的循环问题,不需要在每个同步方法中写重复的相等判断。同时统一订阅Model的变更事件,自动同步ViewModel属性:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public abstract class AbstractViewModel : INotifyPropertyChanged
{
    public SampleModel Instance { get; }
    private bool _isInitializing;

    public event PropertyChangedEventHandler PropertyChanged;

    public AbstractViewModel(SampleModel instance)
    {
        Instance = instance;
        _isInitializing = true;
        SyncViewModel();
        _isInitializing = false;

        // 订阅Model的变更事件,Model更新后自动同步到当前ViewModel
        Instance.PropertyChanged += OnModelPropertyChanged;
    }

    private void OnModelPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        // 只同步当前ViewModel关心的属性,可由子类重写实现自定义逻辑
        SyncViewModel(e.PropertyName);
    }

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        // 初始化阶段跳过同步到Model的逻辑,避免循环
        if (!_isInitializing)
        {
            SyncModel(propertyName);
        }
    }

    // 改为按需同步单属性,不需要每次全量同步所有属性
    protected abstract void SyncModel(string propertyName);
    protected abstract void SyncViewModel(string propertyName = null);
}

3. 子类ViewModel简化实现

public class SampleViewModelA : AbstractViewModel
{
    public string Material
    {
        get => _material;
        set
        {
            if (_material == value) return;
            _material = value;
            OnPropertyChanged();
        }
    }

    public double Weight
    {
        get => _weight;
        set
        {
            if (_weight == value) return;
            _weight = value;
            OnPropertyChanged();
        }
    }

    public object SharedProperty
    {
        get => _sharedProperty;
        set
        {
            if (Equals(_sharedProperty, value)) return;
            _sharedProperty = value;
            OnPropertyChanged();
        }
    }

    public SampleViewModelA(SampleModel instance) : base(instance) { }

    protected override void SyncModel(string propertyName)
    {
        switch (propertyName)
        {
            case nameof(Material):
                Instance.Material = Material;
                break;
            case nameof(Weight):
                Instance.Weight = Weight;
                break;
            case nameof(SharedProperty):
                Instance.SharedProperty = SharedProperty;
                break;
        }
    }

    protected override void SyncViewModel(string propertyName = null)
    {
        if (propertyName is null or nameof(Material))
            Material = Instance.Material;
        if (propertyName is null or nameof(Weight))
            Weight = Instance.Weight;
        if (propertyName is null or nameof(SharedProperty))
            SharedProperty = Instance.SharedProperty;
    }

    private string _material;
    private double _weight;
    private object _sharedProperty;
}

SampleViewModelB按照同样逻辑实现自己关心的Length、Width、Height和SharedProperty即可。

4. 多ViewModel自动同步逻辑说明

所有ViewModel持有同一个Model实例,任意ViewModel修改属性后同步到Model,Model触发变更通知,其他订阅了该Model的ViewModel会自动同步对应属性,不需要额外的控制器、全局事件订阅逻辑,也不会出现触发源订阅自己触发的事件的问题。

如果存在跨多个Model的共享属性,可以单独实现一个全局状态单例类,同样实现INotifyPropertyChanged,需要用到该属性的ViewModel直接订阅这个全局状态类的变更事件即可。

额外简化方案(无特殊业务需求可直接使用)

如果ViewModel不需要对属性做额外的业务校验、转换处理,完全可以取消ViewModel的私有字段,直接包装Model的属性,连同步逻辑都可以完全省略:

public string Material
{
    get => Instance.Material;
    set
    {
        Instance.Material = value;
        OnPropertyChanged();
    }
}

这种实现下,所有ViewModel的属性直接绑定到同一个Model的属性,修改会实时同步到所有关联的ViewModel,不需要任何额外的同步代码,维护成本极低。

内容的提问来源于stack exchange,提问作者user23623447

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 21:39:03