0

假设我有一个标准的 WPF ItemsControl 绑定到“Dog”对象的 ObservableCollection,如下所示:

<ItemsControl ItemsSource="{Binding Dogs}">
<ItemsControl.ItemTemplate>
    <DataTemplate>
         <StackPanel Orientation="Horizontal">
             <TextBlock Text="{Binding Name}"/>
             <TextBlock Text="{Binding Breed}"/>
             <TextBlock Text="{Binding Weight}"/>
         </StackPanel>
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

我希望用户能够删除集合中的任何狗。过去,我一直在使用 ListBox 控件并将 ViewModel 绑定到 SelectedItem 属性。然后,我创建一个按钮,其中包含一个从 ObservableCollection 中删除所选对象的事件。

这工作正常,但我想把它布置好,这样每一行都可以有自己的删除按钮。

<ItemsControl ItemsSource="{Binding Dogs}">
<ItemsControl.ItemTemplate>
    <DataTemplate>
         <StackPanel Orientation="Horizontal">
             <TextBlock Text="{Binding Name}"/>
             <TextBlock Text="{Binding Breed}"/>
             <TextBlock Text="{Binding Weight}"/>
             <Button Click="Click_EventHandler"/>
         </StackPanel>
    </DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

一个看起来像这样的事件:

private void ListBox_PreviewMouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
    {
          //Delete this Dog Object from Observable Collection
    }

将一个按钮推入 ItemTemplate 并给它一个事件会使 WPF 崩溃,并将命令绑​​定到 ItemTemplate 中的按钮根本不会做任何事情,因此我以前的方法将不起作用。

我能想到的唯一方法是将 ToggleButton 添加到 ItemTemplate 并绑定到 View Model,然后在 Setter 中触发一个事件。不完全是一个优雅的解决方案。

有人对如何解决这个问题有更好的想法吗?

4

1 回答 1

1

您可以像其他所有内容一样绑定命令,但首先您需要实现ICommand接口,如下所示:

public class RelayCommand: ICommand
{
  private Action<object> _execute;
  private Predicate<object> _canExecute;

  public RelayCommand(Action<object> execute, Predicate<object> canExecute)
  {
      _execute = execute;
      _canExecute = canExecute;
  }

  public RelayCommand(Action<object> execute) : this(execute, null) { }

  public event EventHandler CanExecuteChanged;

  public bool CanExecute(object parameter)
  {
      return _canExecute != null ? _canExecute(parameter) : true;
  }

  public void Execute(object parameter)
  {
      if (CanExecute(parameter) && _execute != null) _execute(parameter);
  }
}

然后你的Dog类需要公开例如ICommand DeleteCmd属性:

class Dog
{
   ...
   private RelayCommand _deleteCmd;

   private void DoDelete(object parameter)
   {
      //put delete action here
   }

   public ICommand DeleteCmd
   {
      get
      {
         if (_deleteCmd == null) _deleteCmd = new RelayCommand(o => DoDelete(o));
         return _deleteCmd;
      }
   }
}

然后你像这样绑定它:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding Name}"/>
    <TextBlock Text="{Binding Breed}"/>
    <TextBlock Text="{Binding Weight}"/>
    <Button Command="{Binding DeleteCmd}"/>
</StackPanel>
于 2013-05-31T19:53:16.783 回答