WPF:列表中删除命令的命令参数

时间:2010-08-13 12:31:57

标签: wpf data-binding mvvm command viewmodel

在我的viewmodel中,我有一个包含项目的列表(ObservableCollection)。在视图中,此列表显示在ItemsControl中。在每一行中,都有一个“删除”按钮。我希望按钮后面的命令从列表中删除该项目。

<ItemsControl ItemsSource="{Binding myList}">
    <ItemsControl.ItemTemplate>
        ...
            <Button Command="{StaticResource myDeleteCommand}" CommandParameter="???">
                Remove item
            </Button>
        ...
    </ItemsControl.ItemTemplate>
</ItemsControl>

我作为命令参数传递什么?

  • 项目本身(Binding .)?然后我没有对命令中的列表的引用,所以我需要更改我的模型,使每个列表项包含对列表的反向引用。
  • 名单?然后我没有对该项目的引用。
  • 两个?然后我需要编写一个MultiConverter,将列表和项目转换为一些自定义对象。对于这么简单的任务来说,似乎需要很多开销。

有什么想法吗?对我来说这似乎是一个相当常见的场景,所以我想必须有一些完善的最佳实践解决方案......

2 个答案:

答案 0 :(得分:4)

我以这种方式实现了这样的命令,我将Item作为参数传递。命令self知道它应该在哪个列表上运行。通过在我的ViewModel中调用Delete方法的委托或命令接收其构造函数中的项目列表。

即。带代理人的命令

public sealed class SimpleParameterCommandModel<T> : CommandModel
{
    private readonly Action<T> execute;
    private readonly Func<T, bool> canExecute;

    public SimpleParameterCommandModel(string label, string tooltip, Action<T> execute, Func<T, bool> canExecute)
        : base(appCtx, dataCtx, label, tooltip)
    {
        if (execute == null) throw new ArgumentNullException("execute");
        this.execute = execute;
        this.canExecute = canExecute;
    }
    ...
}

用法:

private ICommand _DeleteCommand = null;
public ICommand DeleteCommand
{
    get
    {
        if (_DeleteCommand == null)
        {
            _DeleteCommand = new SimpleParameterCommandModel<IEnumerable<DataObjectModel>>                      ("Delete", "Delete selection from data store", 
                (items) => items.ToList().ForEach(i => DeleteItem(i)),
                (items) => items != null && items.Count() > 0 && AllowDelete);
        }
        return _DeleteCommand;
    }
}
public void DeleteItem(DataObjectModel item)
{
        if (item == null) { throw new ArgumentNullException("item"); }

    myCollection.Remove(item.Object);
}

编辑:忘记XAML

<Button Command="{Binding DeleteCommand, ElementName=...}" CommandParameter="{Binding}">
        Remove item
</Button>

答案 1 :(得分:4)

首先,我将处理ViewModel中的Command。我假设用于绑定的列表在ViewModel中,因此任何在该列表上“工作”的代码也应该在ViewModel中完成。

class MyViewModel
{ 
    // ... Clipping rest of ViewModel class ...

    private ObservableCollection<MyObject> mMyList = new ObservableCollection<MyObject>(); 
    private ICommand mMyDeleteCommand;

    public MyViewModel()
    {
        InitializeMyListSomehow();
        mMyDeleteCommand = new MyCommandClass(
            (item) => DeleteItem(item),
            () => mDeleteCanExecute
        );
    }

    public ObservableCollection<MyObject> MyList
    {
        get { return mMyList; }
        set 
        { 
            // Some function that updates the value and implements INPC
            SetProperty("MyList", ref mMyList, value); 
        }
    }

    public ICommand MyDeleteCommand
    {
        get { return mMyDeleteCommand; }
    }

    void DeleteHandler(var item)
    {
        int index = mMyList.Remove(item);
    }


}

这些物品是否独一无二?如果是这样,您可以传递该项,并且删除命令处理程序可以查找列表中的项目。

如果这些项目不是唯一的,那么你需要做一些逻辑,这取决于预期的结果。

现在,在视图中,您的代码看起来像(注意StaticResource成为Binding):

<ItemsControl ItemsSource="{Binding MyList}">
    <ItemsControl.ItemTemplate>
        ...
            <Button Command="{Binding DataContext.MyDeleteCommand,
                              RelativeSource={RelativeSource FindAncestor,
                                              AncestorType={x:Type ItemsControl}}}" 
                    CommandParameter="{Binding}">
                Remove item
            </Button>
        ...
    </ItemsControl.ItemTemplate>
</ItemsControl>