C# 如何删除ViewModel及其集合中的模型';s的父母';视图模型和模型
我正在试图找出删除模型(因此是VM)的最佳方法,尽管搜索了很多次,但我还没有找到适合我情况的满意答案 简化版本是,给定一个包含自身列表的模型,以及包含自身集合的后续viewmodel,通知和删除事件的顺序是什么 我的工作假设是,流程是这样的C# 如何删除ViewModel及其集合中的模型';s的父母';视图模型和模型,c#,wpf,mvvm,prism,C#,Wpf,Mvvm,Prism,我正在试图找出删除模型(因此是VM)的最佳方法,尽管搜索了很多次,但我还没有找到适合我情况的满意答案 简化版本是,给定一个包含自身列表的模型,以及包含自身集合的后续viewmodel,通知和删除事件的顺序是什么 我的工作假设是,流程是这样的 用户在子视图上单击“删除” 视图从父视图的datacontext调用DeleteChild命令,并将其自身的datacontext作为参数传递 父VM通知它的模型(父模型)它正在删除它的子VM之一 父VM从其集合中删除子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;
}
}
看法
如果它不是凌乱的,那肯定是混乱的
因为视图模型不应更改单独镜像模型集合的视图模型集合。推理:模型集合可能会在视图模型不做任何事情的情况下发生更改,因此它无论如何都必须对更改做出反应,并且您可以免费获得对来自视图模型的更改的反应。非常好。那么通知广播本质上就是每个家长都订阅的事件?在我的特定应用程序中,大多数父控件都有一位数的子控件,因此我还考虑传递回调函数,让子控件直接响应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>