代码之家  ›  专栏  ›  技术社区  ›  Heinzi

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

  •  4
  • Heinzi  · 技术社区  · 14 年前

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

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

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

    • 项目本身( Binding . )?然后,我在命令中没有对列表的引用,所以我需要更改我的模型,使每个列表项都包含对列表的后引用。
    • 名单?那我就没有这个项目的参考资料了。
    • 两者都有?然后我需要编写一个多转换器,将列表和项目转换为一些自定义对象。对于这样一个简单的任务,开销似乎很大。

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

    2 回复  |  直到 14 年前
        1
  •  4
  •   Arthur    14 年前

    我以这种方式实现了这样的命令,我将该项作为参数传递。命令本身知道它应该在哪个列表上操作。通过调用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>
    
        2
  •  4
  •   Wonko the Sane    14 年前

    首先,我将在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);
        }
    
    
    }
    

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

    如果项目是非唯一的,那么根据预期的结果,您需要做更多的逻辑。

    现在,在视图中,您的代码看起来像(注意,静态资源变成了一个绑定):

    <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>