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

WPF:列表中删除命令的命令参数,wpf,data-binding,mvvm,command,viewmodel,Wpf,Data Binding,Mvvm,Command,Viewmodel,在我的viewmodel中,我有一个包含项的列表(ObservableCollection)。在视图中,此列表显示在ItemsControl中。每行中都有一个“删除”按钮。我想要按钮后面的命令从列表中删除该项 <ItemsControl ItemsSource="{Binding myList}"> <ItemsControl.ItemTemplate> ... <Button Command="{StaticReso

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

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

...
删除项目
...
我应该传递什么作为命令参数

  • 项目本身(
    绑定。
    )?然后,我在命令中没有对列表的引用,因此我需要更改模型,使每个列表项都包含对列表的反向引用
  • 名单?那我就没有提到这个项目了
  • 两者都有?然后,我需要编写一个多转换器,将列表和项目转换为一些自定义对象。对于这样一个简单的任务来说,似乎有很多开销

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

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

i、 e.有代表的命令

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;
    }
    ...
}
公共密封类SimpleParameterCommandModel:CommandModel
{
私有只读操作执行;
私有只读功能可执行;
公共SimpleParameterCommandModel(字符串标签、字符串工具提示、操作执行、Func canExecute)
:base(appCtx、dataCtx、标签、工具提示)
{
如果(execute==null)抛出新的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);
}
private ICommand _DeleteCommand=null;
公共ICommand delete命令
{
得到
{
如果(_DeleteCommand==null)
{
_DeleteCommand=new SimpleParameterCommandModel(“删除”,“从数据存储中删除所选内容”,
(items)=>items.ToList().ForEach(i=>DeleteItem(i)),
(items)=>items!=null&&items.Count()>0&&AllowDelete);
}
返回_delete命令;
}
}
公共void DeleteItem(DataObjectModel项)
{
如果(item==null){抛出新的ArgumentNullException(“item”);}
myCollection.Remove(item.Object);
}
编辑:XAML

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

删除项目

首先,我将处理ViewModel中的命令。我假设用于绑定的列表在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);
    }


}
类MyViewModel
{ 
//…正在剪裁ViewModel类的其余部分。。。
私有ObservableCollection mMyList=新ObservableCollection();
私有ICommand和mmydelete命令;
公共MyViewModel()
{
InitializeMyList();
mMyDeleteCommand=newmycommandclass(
(项目)=>删除项目(项目),
()=>mDeleteCanExecute
);
}
公共可观测集合MyList
{
获取{return mMyList;}
设置
{ 
//更新值并实现INPC的某些函数
SetProperty(“MyList”,参考mMyList,值);
}
}
公共ICommand mydelete命令
{
获取{return mMyDeleteCommand;}
}
void DeleteHandler(变量项)
{
int index=mMyList.Remove(项目);
}
}
这些物品是独一无二的吗?如果是这样,您可以传递该项,并且Delete命令处理程序可以在列表中查找该项

<ItemsControl ItemsSource="{Binding myList}">
    <ItemsControl.ItemTemplate>
        ...
            <Button Command="{StaticResource myDeleteCommand}" CommandParameter="???">
                Remove item
            </Button>
        ...
    </ItemsControl.ItemTemplate>
</ItemsControl>
如果项目是非唯一的,那么您必须根据预期结果执行更多的逻辑操作

现在,在视图中,您的代码如下所示(请注意,StaticResource变成了一个绑定):


...
删除项目
...

code中没有对
mMyList
的引用。视图中显示了多个这样的列表。很抱歉-我没有注意到该命令是静态资源。通常,在MVVM解决方案中[据我所知]命令是在ViewModel中处理的,而不是在视图中处理的。我将更新我的答案以反映这一点。谢谢!是的,将命令放入列表的viewmodel中确实是一种方法。我接受了亚瑟的解决方案,因为他速度快了一点,但你的解决方案也非常有用!丹克!:-)是的,为列表的每个实例创建单独的命令确实是解决方案。