通过ICommands单击按钮删除ListBoxItem

时间:2019-04-22 14:44:00

标签: c# wpf xaml listbox

我刚开始使用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");
    }
}

问题是:

  1. 为什么没有显示消息框?我该如何运作?
  2. 如何检索哪个索引/ ListBoxItem触发了按钮 点击?
  3. 如何将按钮对准行尾?

非常感谢!

1 个答案:

答案 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(); }
    }