Using events and Commands within ItemsControl in WPF

给你一囗甜甜゛ 提交于 2019-12-10 11:47:49

问题


Say I have a standard WPF ItemsControl bound to an ObservableCollection of "Dog" objects like so:

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

I want the user to be able delete any of the dogs in the collection. In the past I've been doing this with a ListBox control and binding my ViewModel to the SelectedItem property. I then create a button with an event that removes the selected object from the ObservableCollection.

This works OK but I'd like to lay it out so each row can have its own delete button.

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

And an event that looks like this:

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

Shoving a button into the ItemTemplate and giving it an event crashes WPF, and binding a command to a button within an ItemTemplate doesn't do anything at all so my former method will not work.

The only way I can think of doing this is adding a ToggleButton to the ItemTemplate and binding to the View Model, and then firing an event in the Setter. Not exactly an elegant solution.

Anyone have any better idea on how to go about this?


回答1:


You can bind commands like everything else, but first you need your implementation of ICommand interface, something like this:

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);
  }
}

and then your Dog class needs to expose for example ICommand DeleteCmd property:

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

and then you bind it like this:

<StackPanel Orientation="Horizontal">
    <TextBlock Text="{Binding Name}"/>
    <TextBlock Text="{Binding Breed}"/>
    <TextBlock Text="{Binding Weight}"/>
    <Button Command="{Binding DeleteCmd}"/>
</StackPanel>


来源:https://stackoverflow.com/questions/16864502/using-events-and-commands-within-itemscontrol-in-wpf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!