我刚开始使用XAML / WPF,脑子里有很多问题。其中之一是如何绑定按钮单击以通过ICommand界面删除ListBoxItem
。我创建了一个简单的WPF项目,这是我的XAML:
<ListBox Name="lb" HorizontalAlignment="Left" Height="129" Margin="15,17,0,0" VerticalAlignment="Top" Width="314" Grid.ColumnSpan="2" >
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Setter Property="Height" Value="30" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<StackPanel Orientation="Horizontal">
<CheckBox Margin="5,5" Height="18" IsChecked="{TemplateBinding IsSelected}">
<ContentPresenter Content="{TemplateBinding Content}"/>
</CheckBox>
<Button Content="[x]" Height="22" Width="22" HorizontalAlignment="Right"
Command="{Binding ElementName=lb, Path=DataContext.DeleteItemCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}" CommandParameter="{Binding }"/>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.Resources>
<ListBoxItem Content="Foo" />
<ListBoxItem Content="Bar" />
</ListBox>
这是我的窗口:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new Context(); // Also tried before InitializeComponent()
}
public class Context
{
public ICommand DeleteItemCommand = new DeleteItemCommand();
}
}
DeleteItemCommand
在哪里:
public class DeleteItemCommand : ICommand
{
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
MessageBox.Show("Meep");
}
}
问题是:
ListBoxItem
触发了按钮
点击?非常感谢!
答案 0 :(得分:1)
您遇到的一个问题是ICommand只是一个变量。
您需要一个公共属性才能绑定。
更像
public ICommand DeleteItemCommand {get;set;} = new DeleteItemCommand();
另一个问题是您的元素名称。这受名称范围的限制,我想您会发现列表框位于另一个名称范围中。
相反,只需将相对源绑定与祖先类型ListBox一起使用。
大约。
Command="{Binding DataContext.DeleteItemCommand,
RelativeSource={RelativeSource AncestorType={x:Type ListBox}}}
顺便说一句。
我建议研究一个框架,以简化命令等操作。
MVVMLight是我的建议。使用nuget mvvmlightlibs添加到项目。 https://msdn.microsoft.com/en-gb/magazine/dn237302.aspx?f=255&MSPPError=-2147217396
以下内容基于我已有的一些代码,因此仅是示例性的,而不是您正在做的事情。
查看:
<Window.DataContext>
<local:MainWindowViewModel/>
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding People}"
HorizontalContentAlignment="Stretch">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding LastName}"/>
<Button Content="Delete"
Command="{Binding DataContext.DeletePersonCommand, RelativeSource={RelativeSource AncestorType=ListBox}}"
CommandParameter="{Binding}"
Grid.Column="1"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
Viewmodel使用mvvmlight中的relaycommand
using GalaSoft.MvvmLight.CommandWpf;
using System.Collections.ObjectModel;
namespace wpf_99
{
public class MainWindowViewModel : BaseViewModel
{
private RelayCommand<Person> deletePersonCommand;
public RelayCommand<Person> DeletePersonCommand
{
get
{
return deletePersonCommand
?? (deletePersonCommand = new RelayCommand<Person>(
(person) =>
{
People.Remove(person);
}
));
}
}
private ObservableCollection<Person> people = new ObservableCollection<Person>();
public ObservableCollection<Person> People
{
get { return people; }
set { people = value; }
}
public MainWindowViewModel()
{
People.Add(new Person { FirstName = "Chesney", LastName = "Brown" });
People.Add(new Person { FirstName = "Gary", LastName = "Windass" });
People.Add(new Person { FirstName = "Liz", LastName = "McDonald" });
People.Add(new Person { FirstName = "Carla", LastName = "Connor" });
}
}
}
BaseViewModel与inotifypropertychanged上的msdn文章差不多:
public class BaseViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Mvvmlight具有自己的基本视图模型,但是您无法序列化从该继承的vm。
人员: 公共类Person:BaseViewModel { 私有字符串firstName;
public string FirstName
{
get { return firstName; }
set { firstName = value; RaisePropertyChanged(); }
}
private string lastName;
public string LastName
{
get { return lastName; }
set { lastName = value; RaisePropertyChanged(); }
}