【问题标题】:WPF: Command parameter for a delete command in a listWPF:列表中删除命令的命令参数
【发布时间】:2011-03-29 10:54:07
【问题描述】:

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

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

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

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

有什么想法吗?这对我来说似乎是一个相当普遍的情况,所以我想一定有一些行之有效的最佳实践解决方案......

【问题讨论】:

    标签: wpf data-binding mvvm command viewmodel


    【解决方案1】:

    我以这种方式实现了这样的命令,我将项目作为参数传递。命令 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>
    

    【讨论】:

    • 当客! :-) 是的,为列表的每个实例创建一个单独的命令确实是解决方案。
    【解决方案2】:

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

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

    如果项目不是唯一的,您将不得不做更多的逻辑,这取决于预期的结果。

    现在,在视图中,您的代码将如下所示(注意 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>
    

    【讨论】:

    • 我在代码中没有对mMyList 的引用。视图中显示了多个此类列表。
    • 对不起 - 我错过了命令是静态资源。一般来说,在 MVVM 解决方案中 [据我了解] 命令在 ViewModel 中处理,而不是在 View 中。我将更新我的答案以反映这一点。
    • 谢谢!是的,将命令放入列表的视图模型确实是要走的路。我接受了 Arthur 的解决方案,因为他的速度更快,但您的解决方案也非常有帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-29
    • 2010-09-14
    • 2020-11-26
    • 2012-03-10
    • 2011-10-04
    • 2012-09-11
    • 2017-07-26
    相关资源
    最近更新 更多