2010-08-13 42 views
4

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

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

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

  • 该项目本身(Binding .)?然后我没有对命令中的列表的引用,所以我需要更改模型,以便每个列表项都包含对列表的反向引用。
  • 清单?然后我没有对该项目的参考。
  • Both?然后我需要编写一个MultiConverter,将列表和项目翻译成一些自定义对象。对于这样一个简单的任务似乎有很多开销。

任何想法?这对我来说似乎是一个相当常见的场景,所以我想必须有一些行之有效的最佳实践解决方案......

回答

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

丹科! :-)是的,为列表的每个实例创建一个单独的命令确实是解决方案。 – Heinzi 2010-08-13 13:52:52

3

首先,我会处理的命令在视图模型。我假设用于绑定的列表位于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> 
+0

我没有在代码中引用'mMyList'。该视图中显示了多个此类列表。 – Heinzi 2010-08-13 12:45:34

+0

对不起 - 我错过了命令是一个StaticResource。一般来说,在MVVM解决方案中[这是我的理解]命令是在ViewModel中处理的,而不是在View中处理的。我会更新我的答案以反映这一点。 – 2010-08-13 12:52:12

+0

谢谢!是的,把这个命令放入列表的视图模型确实是一条可行的路。我接受了Arthur的解决方案,因为他速度更快,但你的帮助也非常大! – Heinzi 2010-08-13 13:54:45