Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/271.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何处理主模型(MVVM)中子模型的更改_C#_Wpf_Mvvm - Fatal编程技术网

C# 如何处理主模型(MVVM)中子模型的更改

C# 如何处理主模型(MVVM)中子模型的更改,c#,wpf,mvvm,C#,Wpf,Mvvm,从模型更新动态创建的复选框状态的最佳实践是什么?复选框的实际值保存在主模型的子模型中,并根据其逻辑进行更改。复选框的属性绑定到各自的FooViewModels。但是如何更改FooViewModel的属性呢 1方式:主模型触发特殊事件->主VM处理它并使用事件参数找到要更新的目标FooViewModel->主VM使用事件参数中指定的值设置目标FooViewModel属性->复选框通过绑定到FooViewModel更新 2方式:主模型持有实现INPC的FooModels的可观察集合,每个都被FooV

从模型更新动态创建的复选框状态的最佳实践是什么?复选框的实际值保存在主模型的子模型中,并根据其逻辑进行更改。复选框的属性绑定到各自的FooViewModels。但是如何更改FooViewModel的属性呢

1方式:主模型触发特殊事件->主VM处理它并使用事件参数找到要更新的目标FooViewModel->主VM使用事件参数中指定的值设置目标FooViewModel属性->复选框通过绑定到FooViewModel更新

2方式:主模型持有实现INPC的FooModels的可观察集合,每个都被FooViewModel包装(在主VM中使用CollectionChanged事件)。主模型设置一些FooModel的属性->FooViewModel处理PropertyChanged并将其进一步传输触发自己的PropertyChanged事件->复选框通过绑定到FooViewModel进行更新。 FooViewModel中的传输代码:

this._model.PropertyChanged += (s, a) => this.RaisePropertyChangedEvent(a.PropertyName);
我的下一步是实施第二种方式:

// MainModel class that holds collection of extra models (CfgActionModel):
class MainModel: BindableBase
{
    ObservableCollection<CfgActionModel> _actionsColl
        = new ObservableCollection<CfgActionModel>();

    public ObservableCollection<CfgActionModel> ActionCollection
    {
        get => this._actionsColl;
    }

    public void AddAction(ConfigEntry cfgEntry, bool isMeta)
    {
        CfgActionModel actionModel = new CfgActionModel()
        {
            CfgEntry = cfgEntry,
            Content = cfgEntry.ToString(),
            IsEnabled = true,
            IsChecked = false
        };

        this._actionsColl.Add(actionModel);
    }
}

// Extra model that is wrapped with CfgActionViewModel:
class CfgActionModel: BindableBase
{
    ConfigEntry _cfgEntry; // Custom enumeration value unique for each checkbox
    string _content;
    bool _isEnabled = false;
    bool _isChecked = false;

    public ConfigEntry CfgEntry
    {
        get => this._cfgEntry;
        set
        {
            if (this._cfgEntry == value) return;

            this._cfgEntry = value;
            this.RaisePropertyChangedEvent(nameof(CfgEntry));
        }
    }

    public string Content
    {
        get => this._content;
        set
        {
            if (this._content == value) return;

            this._content = value;
            this.RaisePropertyChangedEvent(nameof(Content));
        }
    }

    public bool IsEnabled
    {
        get => this._isEnabled;
        set
        {
            if (this._isEnabled == value) return;

            this._isEnabled = value;
            this.RaisePropertyChangedEvent(nameof(IsEnabled));
        }
    }

    public bool IsChecked
    {
        get => this._isChecked;
        set
        {
            if (this._isChecked == value) return;

            this._isChecked = value;
            this.RaisePropertyChangedEvent(nameof(IsChecked));
        }
    }
}

// CfgActionViewModel that is checkbox in UI is bound to:
class CfgActionViewModel: BindableBase
{
    CfgActionModel _model;

    public CfgActionViewModel(CfgActionModel model)
    {
        this._model = model;

        this._model.PropertyChanged += (s, a) => this.RaisePropertyChangedEvent(a.PropertyName);
    }

    public string Content
    {
        get => this._model.Content;
        set => this._model.Content = value;
    }

    public bool IsEnabled
    {
        get => this._model.IsEnabled;
        set => this._model.IsEnabled = value;
    }

    public bool IsChecked
    {
        get => this._model.IsChecked;
        set => this._model.IsChecked = value;
    }
}

// MainViewModel where we fill the model with data:
class MainViewModel
{
    MainModel model;

    readonly ObservableCollection<CfgActionViewModel> _actionVMColl = new ObservableCollection<CfgActionViewModel>();
    public ObservableCollection<CfgActionViewModel> ActionVMCollection => this._actionVMColl;

    public MainViewModel()
    {
        this.model = new MainModel();

        this.model.ActionCollection.CollectionChanged += (s, a) =>
        {
            // when new model is created we create new ViewModel wrapping it
            if (a.Action == NotifyCollectionChangedAction.Add)
            {
                CfgActionModel newModel = (CfgActionModel) a.NewItems[0];
                CfgActionViewModel actionViewModel = new CfgActionViewModel(newModel);

                _actionVMColl.Add(actionViewModel);
            }
        };

        model.AddAction(ConfigEntry.AutoBuy, false);
        model.AddAction(ConfigEntry.Bomb, false);
    }
}
//保存额外模型集合的MainModel类(CfgActionModel):
类main模型:BindableBase
{
可观测收集(行动集合)
=新的ObservableCollection();
公共可观测集合操作集合
{
get=>这个;
}
公共无效添加操作(ConfigEntry cfgEntry,布尔伊斯梅塔)
{
CfgActionModel actionModel=新的CfgActionModel()
{
CfgEntry=CfgEntry,
Content=cfgEntry.ToString(),
IsEnabled=true,
IsChecked=false
};
此._actionsColl.Add(actionModel);
}
}
//使用CfgActionViewModel包装的额外模型:
类CfgActionModel:BindableBase
{
ConfigEntry\u cfgEntry;//每个复选框的自定义枚举值都是唯一的
字符串内容;
bool _isEnabled=false;
bool\u isChecked=false;
公营绅士
{
get=>这个;
设置
{
如果(this.\cfgEntry==值)返回;
这个。\ cfgEntry=价值;
此。提高产权变更(名称(CfgEntry));
}
}
公共字符串内容
{
获取=>此内容;
设置
{
if(this.\u content==value)返回;
这个。_内容=值;
this.RaisePropertyChangedEvent(名称(内容));
}
}
公共场所被禁止
{
get=>这个;
设置
{
如果(this._isEnabled==value)返回;
此项。_isEnabled=值;
此.RaisePropertyChangedEvent(名称(IsEnabled));
}
}
公共场所被检查
{
get=>这个;
设置
{
如果(this._isChecked==value)返回;
此项。_isChecked=值;
此.RaisePropertyChangedEvent(名称(已检查));
}
}
}
//在UI中为复选框的CfgActionViewModel绑定到:
类CfgActionViewModel:BindableBase
{
cfgactionmodelu模型;
公共CfgActionViewModel(CfgActionModel模型)
{
这个._model=model;
this.\u model.PropertyChanged+=(s,a)=>this.RaisePropertyChangedEvent(a.PropertyName);
}
公共字符串内容
{
get=>this.\u model.Content;
set=>this.\u model.Content=value;
}
公共场所被禁止
{
get=>这一点。_model.IsEnabled;
set=>this.\u model.IsEnabled=value;
}
公共场所被检查
{
get=>这个;
set=>this.\u model.IsChecked=value;
}
}
//MainViewModel,其中我们使用数据填充模型:
类MainViewModel
{
主模型;
只读ObservableCollection _actionVMColl=新ObservableCollection();
public ObservableCollection ActionVMCollection=>this.\u actionVMColl;
公共主视图模型()
{
this.model=新的MainModel();
this.model.ActionCollection.CollectionChanged+=(s,a)=>
{
//创建新模型时,我们将创建新的ViewModel并对其进行包装
if(a.Action==NotifyCollectionChangedAction.Add)
{
CfgActionModel newModel=(CfgActionModel)a.NewItems[0];
CfgActionViewModel actionViewModel=新的CfgActionViewModel(新模型);
_actionVMColl.Add(actionViewModel);
}
};
model.AddAction(ConfigEntry.AutoBuy,false);
model.AddAction(ConfigEntry.Bomb,false);
}
}
视图中的DataTemplate如下所示:

<DataTemplate DataType="{x:Type mvvm:CfgActionViewModel}">
    <CheckBox
        IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" 
        IsEnabled="{Binding Path=IsEnabled, Mode=TwoWay}" 
        Content="{Binding Path=Content, Mode=OneWay}"/>
</DataTemplate>


MVVM是否可以在某个地方避免与MainViewModel交互(第二种方式),或者每个子ViewModel的属性必须由MainViewModel设置(第一种方式)?

这两种方法都可以接受。但就我个人而言,我会采取方法1,使我的模型尽可能薄

您可以参考示例代码了解如何实现方法#1

公共类MainViewModel:BindableBase { 公共ObservableCollection子视图模型{get;} 公共主视图模型() { 子视图模型=新的ObservableCollection(); SubViewModels.CollectionChanged+=SubViewModels\u CollectionChanged; } 私有void子视图模型\u CollectionChanged(对象发送方,NotifyCollectionChangedEventArgs e) { if(e.Action==NotifyCollectionChangedAction.Add) { foreach(e.NewItems.Cast()中的var subVM) { subVM.PropertyChanged+=SubViewModel_PropertyChanged; } } //TODO:取消订阅在集合中删除的子视图模型,以避免内存泄漏。 } 私有void子视图模型_属性已更改(对象发送者,属性更改开发者) { 开关(如PropertyName) { 案例名称(SubViewModel.IsChecked): //托多:在这里做你的事。。。 打破 } } } 公共类子视图模型:BindableBase { 一等兵
public class MainViewModel : BindableBase
{
    public ObservableCollection<SubViewModel> SubViewModels { get; }

    public MainViewModel()
    {
        SubViewModels = new ObservableCollection<SubViewModel>();

        SubViewModels.CollectionChanged += SubViewModels_CollectionChanged;
    }

    private void SubViewModels_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if(e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach(var subVM in e.NewItems.Cast<SubViewModel>())
            {
                subVM.PropertyChanged += SubViewModel_PropertyChanged;
            }
        }

        // TODO: Unsubscribe to SubViewModels that are removed in collection to avoid memory leak.
    }

    private void SubViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case nameof(SubViewModel.IsChecked):
                // TODO: Do your thing here...
                break;
        }
    }
}

public class SubViewModel : BindableBase
{
    private bool _isChecked;

    public bool IsChecked
    {
        get => _isChecked;
        set => SetProperty(ref _isChecked, value);
    }
}