首页 > 解决方案 > 如何在其父视图模型和模型的集合中删除视图模型和模型

问题描述

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

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

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

  1. 用户在子视图上单击删除
  2. 视图从父视图的 datacontext 调用 DeleteChild 命令,将它自己的 datacontext 作为参数传递
  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#wpfmvvmprism

解决方案


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

差不多就是这样。我会补充

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

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


推荐阅读