通过 ICommands 删除按钮单击时的 ListBoxItem
Posted
技术标签:
【中文标题】通过 ICommands 删除按钮单击时的 ListBoxItem【英文标题】:Remove ListBoxItem on button click through ICommands 【发布时间】:2019-09-11 18:06:00 【问题描述】:我刚开始使用 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
点击?
如何将按钮与行尾对齐?
非常感谢!
【问题讨论】:
【参考方案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。
人: 公共类人:BaseViewModel 私有字符串名字;
public string FirstName
get return firstName;
set firstName = value; RaisePropertyChanged();
private string lastName;
public string LastName
get return lastName;
set lastName = value; RaisePropertyChanged();
【讨论】:
嗨@Andy!谢谢回复。为命令提供访问器使其工作。这个丑陋的RelativeSource
有什么解决方法吗?!另外,如何将按钮与绝对右侧对齐?还有....如何检索按钮的 ListBoxItem 索引?
你意识到每个线程应该只是一个问题?相对源 - 您可以将数据上下文作为资源,但我建议您不要认为它看起来很丑陋。至少现在。如果你想在右边和左边一些东西,请使用带有列的网格而不是 stackpanel。不要使用索引,将行视图模型传递给命令 CommandParameter="Binding"
我对 WPF 比较陌生,最好有一个完整的示例。在这种情况下,围绕同一上下文创建多个线程没有任何意义。另外,我不知道如何“将行视图模型传递给命令”。以上是关于通过 ICommands 删除按钮单击时的 ListBoxItem的主要内容,如果未能解决你的问题,请参考以下文章
我将如何在按钮单击时从 uiview 中删除 UIBezierPath。?