C# 如何删除ViewModel及其集合中的模型';s的父母';视图模型和模型

C# 如何删除ViewModel及其集合中的模型';s的父母';视图模型和模型,c#,wpf,mvvm,prism,C#,Wpf,Mvvm,Prism,我正在试图找出删除模型(因此是VM)的最佳方法,尽管搜索了很多次,但我还没有找到适合我情况的满意答案 简化版本是,给定一个包含自身列表的模型,以及包含自身集合的后续viewmodel,通知和删除事件的顺序是什么 我的工作假设是,流程是这样的 用户在子视图上单击“删除” 视图从父视图的datacontext调用DeleteChild命令,并将其自身的datacontext作为参数传递 父VM通知它的模型(父模型)它正在删除它的子VM之一 父VM从其集合中删除子VM 父模型将删除子模型 这似乎过于复

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

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

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

  • 用户在子视图上单击“删除”
  • 视图从父视图的datacontext调用DeleteChild命令,并将其自身的datacontext作为参数传递
  • 父VM通知它的模型(父模型)它正在删除它的子VM之一
  • 父VM从其集合中删除子VM
  • 父模型将删除子模型
  • 这似乎过于复杂,此方法将需要单独的逻辑来删除根项,但是如果使用视图调用它自己的deleteself命令,则意味着列表和集合中的空项需要与父VM和模型进行通信。是否有删除模型的“典型”方法

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

    模型

    公共类嵌套BoxModel
    {
    公共嵌套BoxModel()
    {
    NestingBoxModels=新列表();
    }
    公共列表NestingBoxModels{get;}
    公共布尔值应删除{get;private set;}
    /// 
    ///通知孩子准备搬走
    /// 
    ///待通知的儿童
    公共void DeleteChild(NestingBoxModel子项)
    {
    NestingBoxModels.Find(c=>c==child)?.PrepareForRemoval();
    }
    /// 
    ///通知所有儿童准备搬走
    ///标记为准备移除
    /// 
    公共无效准备删除()
    {
    NestingBoxModels.ForEach(nb=>nb.PrepareForRemoval());
    ShouldBeRemoved=true;
    }
    //用于保存并最终删除模型的其他内容
    }
    
    视图模型

    公共类NestingBoxViewModel:BindableBase
    {
    公共嵌套BoxViewModel()
    {
    模型=新的NestingBoxModel();
    ViewModels=新的ObservableCollection();
    DeleteChildCommand=新的DelegateCommand(DeleteChild);
    DeleteCommand=新的DelegateCommand(PrepareForRemoval);
    }
    公共NestingBoxModel模型{get;private set;}
    公共ObservableCollection视图模型{get;private set;}
    公共ICommand DeleteChildCommand{get;}
    公共ICommand DeleteCommand{get;}
    /// 
    ///查找、通知和删除子viewmodel
    /// 
    ///要删除的子viewmodel
    私有void DeleteChild(对象子对象)
    {
    var matchingchild=ViewModels.First(vm=>vm.Equals(child));
    if(matchingchild!=null)
    {
    Model.DeleteChild(matchingchild.Model);
    ViewModels.Remove(匹配子对象);
    匹配child.PrepareForRemoval();
    }
    }
    /// 
    ///准备垃圾收集
    /// 
    公共无效准备删除()
    {
    ViewModels.ToList().ForEach(vm=>vm.PrepareForRemoval());
    Model=null;
    ViewModels=null;
    }
    }
    
    看法

    
    
    如果它不是凌乱的,那肯定是混乱的

  • 用户在子视图上单击“删除”
  • 视图从父视图的datacontext调用DeleteChild命令,并将其自身的datacontext作为参数传递
  • 父VM通知它的模型(父模型)它正在删除它的子VM之一
  • 父VM从其集合中删除子VM
  • 父模型将删除子模型
  • 差不多就是这样。我想补充一点

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


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

    非常好。那么通知广播本质上就是每个家长都订阅的事件?在我的特定应用程序中,大多数父控件都有一位数的子控件,因此我还考虑传递回调函数,让子控件直接响应UI,然后通知它的父控件,而不是将视图绑定到它的父函数。正如您所建议的,由于多种原因,模型确实使用了事件。事件是一个选项,但它实际上可以是事件聚合器或某些消息总线。关于CQR有很多话要说。。。
    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>