按钮单击ICommands时删除ListBoxItem

问题描述 投票:0回答:1

我刚开始使用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. 如何将按钮对齐到行尾?

非常感谢!

c# wpf xaml listbox
1个回答
1
投票

你遇到的一个问题是你的ICommand只是一个变量。

你需要一个公共财产才能绑定。

更像

    public ICommand DeleteItemCommand {get;set;} = new DeleteItemCommand();

另一个问题是你的元素名称。这取决于名称范围,我想你会发现列表框在另一个名称范围内。

相反,只需使用与ancestortype ListBox的relativesource绑定。

大致。

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:public class Person:BaseViewModel {private string firstName;

    public string FirstName
    {
        get { return firstName; }
        set { firstName = value; RaisePropertyChanged(); }
    }
    private string lastName;

    public string LastName
    {
        get { return lastName; }
        set { lastName = value; RaisePropertyChanged(); }
    }
© www.soinside.com 2019 - 2024. All rights reserved.