假设我有一个标准的WPF ItemsControl绑定到ObservableCollection的“Dog”对象,如下所示:
<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中触发事件。不完全是一个优雅的解决方案。
任何人都对如何解决这个问题有更好的了解?
答案 0 :(得分: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>