You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在Prism框架中用DelegateCommand跨视图删除DataGrid绑定的ObservableCollection条目

嘿,在Prism+Unity的WPF MVVM场景里处理跨ViewModel的交互,用**EventAggregator(事件聚合器)**绝对是最优解——完全符合MVVM的解耦原则,不用让两个ViewModel硬关联。我给你一步步拆解怎么实现:

步骤1:定义跨ViewModel的删除事件

首先创建一个继承自Prism PubSubEvent的事件类,用来传递删除触发信号(如果需要直接传递待删除的项,也可以用泛型指定类型)。假设你的数据实体是DataItem,代码如下:

using Prism.Events;

// 泛型参数指定要传递的类型,这里是你的数据项类型
public class DeleteSelectedItemEvent : PubSubEvent<DataItem>
{
    // 空类即可,PubSubEvent已经封装了所有发布订阅的核心逻辑
}

如果你的DataGrid ViewModel自己维护选中项,也可以用无泛型的PubSubEvent,只传递触发信号就行。

步骤2:在DataGrid的ViewModel中订阅事件并实现删除逻辑

假设DataGrid对应的ViewModel是MainContentViewModel,它持有绑定DataGrid的ObservableCollection<DataItem>,还有选中项的绑定属性。我们需要在这个ViewModel里订阅删除事件,并且实现实际的删除逻辑:

using Prism.Events;
using Prism.Mvvm;
using System.Collections.ObjectModel;

public class MainContentViewModel : BindableBase
{
    private readonly IEventAggregator _eventAggregator;
    private DataItem _selectedItem;

    // 绑定DataGrid的ItemsSource
    public ObservableCollection<DataItem> DataItems { get; } = new ObservableCollection<DataItem>();

    // 绑定DataGrid的SelectedItem
    public DataItem SelectedItem
    {
        get => _selectedItem;
        set => SetProperty(ref _selectedItem, value);
    }

    // 通过构造函数注入EventAggregator,Unity容器会自动处理依赖
    public MainContentViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        // 订阅删除事件,指定触发时执行的方法
        // 可选:加上ThreadOption.UIThread确保在UI线程执行更新(避免跨线程操作UI)
        _eventAggregator.GetEvent<DeleteSelectedItemEvent>()
                        .Subscribe(DeleteSelectedItem, ThreadOption.UIThread);
    }

    private void DeleteSelectedItem(DataItem itemToDelete)
    {
        // 如果事件传递了待删除项就用传递的,否则用当前选中项
        var targetItem = itemToDelete ?? SelectedItem;
        if (targetItem != null && DataItems.Contains(targetItem))
        {
            DataItems.Remove(targetItem);
        }
    }

    // 可选:如果ViewModel会被销毁,记得取消订阅避免内存泄漏
    public void Dispose()
    {
        _eventAggregator.GetEvent<DeleteSelectedItemEvent>().Unsubscribe(DeleteSelectedItem);
    }
}

如果你的DataGrid允许多选,可以把SelectedItem换成IList<DataItem> SelectedItems,删除时遍历移除所有选中项即可。

步骤3:在RibbonTab的ViewModel中发布删除事件

RibbonTab对应的ViewModel(比如RibbonViewModel)同样注入IEventAggregator,给删除按钮绑定一个DelegateCommand,在命令执行时发布删除事件:

using Prism.Commands;
using Prism.Events;
using Prism.Mvvm;

public class RibbonViewModel : BindableBase
{
    private readonly IEventAggregator _eventAggregator;
    // 绑定Ribbon按钮的Command
    public ICommand DeleteCommand { get; }

    public RibbonViewModel(IEventAggregator eventAggregator)
    {
        _eventAggregator = eventAggregator;
        DeleteCommand = new DelegateCommand(ExecuteDelete);
    }

    private void ExecuteDelete()
    {
        // 两种发布方式选一种:
        // 1. 如果RibbonViewModel能拿到选中项(比如通过共享服务),直接传递过去
        // _eventAggregator.GetEvent<DeleteSelectedItemEvent>().Publish(targetItem);
        // 2. 直接发布空信号,让DataGrid的ViewModel自己处理选中项(更解耦)
        _eventAggregator.GetEvent<DeleteSelectedItemEvent>().Publish(null);
    }
}

第二种方式更推荐,因为Ribbon的ViewModel不需要关心数据细节,只负责触发操作,符合单一职责原则。

步骤4:确保ViewModel被正确注入

因为你用的是Unity容器,只要在注册环节(比如Module的RegisterTypes方法或者App.xaml.cs的初始化代码)把ViewModel和View关联好,Prism会自动把IEventAggregator注入到ViewModel的构造函数中:

// 示例:在Module的RegisterTypes方法中注册View和ViewModel
public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.RegisterForNavigation<MainContentView, MainContentViewModel>();
    containerRegistry.RegisterForNavigation<RibbonTabView, RibbonViewModel>();
}

如果是直接给View的DataContext赋值(比如在XAML里用ViewModelLocator.AutoWireViewModel="True"),Prism的ViewModelLocator也会自动从容器中获取带依赖的ViewModel实例。

内容的提问来源于stack exchange,提问作者Peasant King

火山引擎 最新活动