如何在其父视图模型和模型的集合中删除视图模型和模型

How to delete a ViewModel and Model in a collection of it's parent's ViewModel and Model

我正在尝试找出删除模型(因此它是 VM)的最佳方法,尽管进行了相当多的搜索,但我还没有找到适合我的情况的满意答案。

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

我的工作假设是流程是这样的

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

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

如果我现在必须写点什么,它看起来会像下面这样

型号

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
}

ViewModel

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>

如果它不凌乱,那肯定会令人困惑。

  1. User clicks delete on a child view
  2. The view calls the DeleteChild command from the parent view's datacontext, passing it's own datacontext as a parameter
  3. The parent VM notifies it's Model (the parent model) that it's deleting one of it's children's VMs
  4. The parent VM removes the child VM from it's collection
  5. The parent model removes the child model

差不多就这些了。我会添加

3a. the Model broadcasts a notification about one of its children being removed

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