【问题标题】:How to delete a ViewModel and Model in a collection of it's parent's ViewModel and Model如何在其父视图模型和模型的集合中删除视图模型和模型
【发布时间】:2018-09-21 04:08:59
【问题描述】:

我试图找出删除模型(因此它是 VM)的最佳方法,尽管搜索了很多,但我还没有找到适合我的情况的令人满意的答案。

简化版本是,给定一个包含自身列表的模型,以及包含自身集合的后续视图模型,应该以什么顺序通知和删除事物?

我的工作假设是流程类似于

  1. 用户在子视图上单击删除
  2. 视图从父视图的数据上下文中调用 DeleteChild 命令,并将其自己的数据上下文作为参数传递
  3. 父虚拟机通知它的模型(父模型)它正在删除它的子虚拟机之一
  4. 父虚拟机从其集合中移除子虚拟机
  5. 父模型移除子模型

这似乎过于复杂,而且这种方法需要单独的逻辑来删除根项目,但是让视图调用它自己的 deleteself 命令意味着列表和集合中的空项目需要与父 VM 和模型进行通信。是否有删除模型的“典型”方法?

如果我现在必须写一些东西,它会如下所示

模型

public class NestingBoxModel
{
    public NestingBoxModel()
    {
        NestingBoxModels = new List<NestingBoxModel>();
    }

    public List<NestingBoxModel> NestingBoxModels { get; }

    public Boolean ShouldBeRemoved { get; private set; }

    /// <summary>
    /// Notfies child to prepare for removal
    /// </summary>
    /// <param name="child">Child to be notified</param>
    public void DeleteChild(NestingBoxModel child)
    {
       NestingBoxModels.Find(c => c == child)?.PrepareForRemoval();
    }

    /// <summary>
    /// Notifes all children to prepare for removal
    /// Marked as ready for removal
    /// </summary>
    public void PrepareForRemoval()
    {
        NestingBoxModels.ForEach(nb => nb.PrepareForRemoval());

        ShouldBeRemoved = true;
    }

    // Other stuff for saving and eventually removing the model
}

视图模型

public class NestingBoxViewModel : BindableBase
{
    public NestingBoxViewModel()
    {
        Model = new NestingBoxModel();
        ViewModels = new ObservableCollection<NestingBoxViewModel>();
        DeleteChildCommand = new DelegateCommand<object>(DeleteChild);
        DeleteCommand = new DelegateCommand(PrepareForRemoval);
    }

    public NestingBoxModel Model { get; private set; }

    public ObservableCollection<NestingBoxViewModel> ViewModels { get; private set; }

    public ICommand DeleteChildCommand { get; }
    public ICommand DeleteCommand { get; }

    /// <summary>
    /// Finds, notifies, and removes child viewmodel
    /// </summary>
    /// <param name="child">Child viewmodel to be removed</param>
    private void DeleteChild(object child)
    {
        var matchingchild = ViewModels.First<NestingBoxViewModel>(vm => vm.Equals(child));
        if (matchingchild != null)
        {
            Model.DeleteChild(matchingchild.Model);
            ViewModels.Remove(matchingchild);
            matchingchild.PrepareForRemoval();
        }
    }

    /// <summary>
    /// Prepares for garbage collection
    /// </summary>
    public void PrepareForRemoval()
    {
        ViewModels.ToList<NestingBoxViewModel>().ForEach(vm => vm.PrepareForRemoval());

        Model = null;
        ViewModels = null;
    }
}

查看

<Border Width="5">
    <StackPanel Margin="10">
        <Button Content="New NestingBox" Command="{Binding DeleteChildCommand, RelativeSource={RelativeSource TemplatedParent}}" CommandParameter="{Binding}"/>
        <ItemsControl ItemsSource="{Binding ViewModels}">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <local:NestingBoxView/>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </StackPanel>
</Border>

如果不是乱七八糟,那肯定会令人困惑。

【问题讨论】:

    标签: c# wpf mvvm prism


    【解决方案1】:
    1. 用户在子视图上单击删除
    2. 视图从父视图的数据上下文中调用 DeleteChild 命令,并将其自己的数据上下文作为参数传递
    3. 父虚拟机通知它的模型(父模型)它正在删除它的子虚拟机之一
    4. 父虚拟机从其集合中移除子虚拟机
    5. 父模型移除子模型

    差不多就是这样。我会添加

    3a。模型广播一个关于其一个孩子被移除的通知

    因为视图模型不应该更改自己镜像模型集合的视图模型集合。推理:模型集合很可能会在视图模型不做任何事情的情况下发生变化,因此无论如何它都必须对变化做出反应,并且您可以免费获得对源自视图模型的变化的反应。

    【讨论】:

    • 优秀。所以通知广播本质上只是每个父母都订阅的事件?在我的特定应用程序中,大多数父母都会有个位数的孩子,所以我也在考虑传递一个回调函数,让孩子控件直接响应 UI,然后通知它的父级而不是绑定到它的父级函数的视图。出于多种原因,模型确实按照您的建议使用事件。
    • 事件是一种选择,但它实际上可以是事件聚合器或某些消息总线之类的任何东西。关于 CQRS 有很多话要说……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-01-03
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 1970-01-01
    相关资源
    最近更新 更多