在动态复选框列表中获取选定的项目WPF C#

发布于 2025-01-27 17:21:21 字数 1384 浏览 2 评论 0原文

在我的ViewModel中,我有一个类别的集合(类别具有ID和名称)。 我设法在视图中动态显示了我的复选框列表。 Thoses复选框用于过滤一些数据(仅显示具有检查类别的数据)。 如何获得检查类别?

<ListBox x:Name="listViewCategories" Grid.Row="1" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedItems}" BorderBrush="Transparent" SelectionMode="Multiple" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="{x:Null}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}"
                      Margin="3"
                      IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

这是我的模型,

private ObservableCollection<Category> _selectedItems = new();
public ObservableCollection<Category> SelectedItems
{
    get => _selectedItems;
    set => SetProperty(ref _selectedItems, value, () => Console.WriteLine("Click"));
}

我尝试了很多事情。

  • 在类别中创建一个属性,并将签名键绑定到该属性(实现InotifyPropertychanged的类别),但它不起作用。
  • 将复选框的“签名”绑定到ListBoxItem的“签发属性”,但我的SelecteItems集合从未被通知任何变化。

感谢您的帮助!

In my viewmodel, I have a Collection of Categories (a Category has an id and a name).
I managed to dynamically display my list of checkboxes in my view. Thoses checkboxes are used to filter some data (displaying only data that have the checked categories).
How can I get the checked categories?

<ListBox x:Name="listViewCategories" Grid.Row="1" ItemsSource="{Binding Categories}" SelectedItem="{Binding SelectedItems}" BorderBrush="Transparent" SelectionMode="Multiple" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="{x:Null}">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding Name}"
                      Margin="3"
                      IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

And here is my model

private ObservableCollection<Category> _selectedItems = new();
public ObservableCollection<Category> SelectedItems
{
    get => _selectedItems;
    set => SetProperty(ref _selectedItems, value, () => Console.WriteLine("Click"));
}

I have tried a lot of things.

  • creating a property in Category 'IsChecked' and bind IsChecked of the checkbok to that property (Category implementing INotifyPropertyChanged) but it doesn't work.
  • Binding 'IsChecked' of the checkbox to the IsSelected property of the ListBoxItem but my SelectedItems collection is never notified of any changement.

Thanks for you help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

舞袖。长 2025-02-03 17:21:21

我想有多种方法可以解决这个问题。在下面,您找到了我的路。

我建议使用microsoft.xaml.behaviors.wpf.dll可以通过Nuget下载。其中包含&lt;互动。triggers&gt;,可用于将事件映射到命令。
我还提供了一个listView来显示所选类别。
请参阅以下代码。

这是XAML的应用程序:

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
    <local:ApplicationViewModel />
</Window.DataContext>
<Grid>
    <StackPanel>
    <ListBox x:Name="listViewCategories" Grid.Row="1" ItemsSource="{Binding Categories}"  BorderBrush="Transparent" SelectionMode="Multiple" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="{x:Null}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding Name}"
                                  Margin="3"
                                  IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
                     >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Checked">
                            <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.(local:ApplicationViewModel.CheckedCommand)}"
                                                    PassEventArgsToCommand="True"
                                                   CommandParameter="{Binding}"/>
                        </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.(local:ApplicationViewModel.UnCheckedCommand)}"
                                                    PassEventArgsToCommand="True"
                                                   CommandParameter="{Binding}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
        <StackPanel>
            <TextBlock Text="Selected Categories" />
            <ListView ItemsSource="{Binding SelectedCategories}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </StackPanel>
    
</Grid>

这是我的类别类别:

  public class Category


{
    
    private string id;

    public string ID
    {
        get { return id; }
        set { id = value; }
    }

    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
   

    }
}

这是我的ViewModel类:

 public class ApplicationViewModel
{
    public ApplicationViewModel()
    {
        Categories = new ObservableCollection<Category>
        {
            new Category{ID="1",Name="Apple"},
            new Category{ID="2",Name="Banana"},
            new Category{ID="2",Name="Orange"},

        };
        SelectedCategories = new ObservableCollection<Category>();
        
    }

 

    public ObservableCollection<Category> Categories { get; set; }
    public ObservableCollection<Category> SelectedCategories { get; set; } = new();



    private ICommand _checkedCommand;
    public ICommand CheckedCommand
    {
        get
        {
            if (_checkedCommand == null)
            {
                _checkedCommand = new RelayCommand(param =>
                {
                    var category = param as Category;
                    this.SelectedCategories.Add(category);
                });

            }
            return _checkedCommand;
        }
    }

    private ICommand _unCheckedCommand;
    public ICommand UnCheckedCommand {
        get
        {
            if(_unCheckedCommand == null)
            {
                _unCheckedCommand = new RelayCommand(param => {

                    var category = param as Category;
                    this.SelectedCategories.Remove(category);
                });
            }
            return _unCheckedCommand;
        }
    }



}

我还实现了一个relayCommand,它很简单,很简单,但是大多数MVVM-Frameworks已经具有类似的东西在商店中。

这是RelayCommand类:

public class RelayCommand : ICommand
{

    public RelayCommand(Action<object> execute) : this(execute, null) { }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }
    
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return _canExecute != null ? _canExecute(parameter) : true;
    }

    public void Execute(object parameter)
    {
        if(_execute !=null)
            _execute(parameter);
    }
    public void OnCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }
}

因此,基本上我有一个方法addCategory和RemoveCategory(在这种情况下为lambda,但您明白了),并通过EventTocommand将其绑定到ViewModel。

I guess there are multiple ways to approach this. Down below you find my way.

I would suggest using the Microsoft.Xaml.Behaviors.Wpf.dll which can be downloaded via Nuget. This contains <Interaction.Triggers> which can be used to map a event to an command.
I have also included a listview to show the selected categories.
See the following code.

This is the application XAML:

<Window x:Class="WpfApp1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp1"
    mc:Ignorable="d"
    
    xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
    Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
    <local:ApplicationViewModel />
</Window.DataContext>
<Grid>
    <StackPanel>
    <ListBox x:Name="listViewCategories" Grid.Row="1" ItemsSource="{Binding Categories}"  BorderBrush="Transparent" SelectionMode="Multiple" ScrollViewer.HorizontalScrollBarVisibility="Disabled" Background="{x:Null}">
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel/>
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding Name}"
                                  Margin="3"
                                  IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
                     >
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Checked">
                            <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.(local:ApplicationViewModel.CheckedCommand)}"
                                                    PassEventArgsToCommand="True"
                                                   CommandParameter="{Binding}"/>
                        </i:EventTrigger>
                            <i:EventTrigger EventName="Unchecked">
                                <i:InvokeCommandAction Command="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.(local:ApplicationViewModel.UnCheckedCommand)}"
                                                    PassEventArgsToCommand="True"
                                                   CommandParameter="{Binding}"/>
                            </i:EventTrigger>
                        </i:Interaction.Triggers>
                </CheckBox>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
        <StackPanel>
            <TextBlock Text="Selected Categories" />
            <ListView ItemsSource="{Binding SelectedCategories}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Name}" />
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </StackPanel>
    
</Grid>

This is my category class:

  public class Category


{
    
    private string id;

    public string ID
    {
        get { return id; }
        set { id = value; }
    }

    private string name;

    public string Name
    {
        get { return name; }
        set { name = value; }
    }
   

    }
}

This is my viewmodel class:

 public class ApplicationViewModel
{
    public ApplicationViewModel()
    {
        Categories = new ObservableCollection<Category>
        {
            new Category{ID="1",Name="Apple"},
            new Category{ID="2",Name="Banana"},
            new Category{ID="2",Name="Orange"},

        };
        SelectedCategories = new ObservableCollection<Category>();
        
    }

 

    public ObservableCollection<Category> Categories { get; set; }
    public ObservableCollection<Category> SelectedCategories { get; set; } = new();



    private ICommand _checkedCommand;
    public ICommand CheckedCommand
    {
        get
        {
            if (_checkedCommand == null)
            {
                _checkedCommand = new RelayCommand(param =>
                {
                    var category = param as Category;
                    this.SelectedCategories.Add(category);
                });

            }
            return _checkedCommand;
        }
    }

    private ICommand _unCheckedCommand;
    public ICommand UnCheckedCommand {
        get
        {
            if(_unCheckedCommand == null)
            {
                _unCheckedCommand = new RelayCommand(param => {

                    var category = param as Category;
                    this.SelectedCategories.Remove(category);
                });
            }
            return _unCheckedCommand;
        }
    }



}

I also implemented a class RelayCommand which was easy and pretty straight forward but most of the MVVM-Frameworks have something like this already in store.

this is the RelayCommand Class:

public class RelayCommand : ICommand
{

    public RelayCommand(Action<object> execute) : this(execute, null) { }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _canExecute = canExecute;
        _execute = execute;
    }
    
    private readonly Predicate<object> _canExecute;
    private readonly Action<object> _execute;

    

    public event EventHandler CanExecuteChanged;

    public bool CanExecute(object parameter)
    {
        return _canExecute != null ? _canExecute(parameter) : true;
    }

    public void Execute(object parameter)
    {
        if(_execute !=null)
            _execute(parameter);
    }
    public void OnCanExecuteChanged()
    {
        CanExecuteChanged(this, EventArgs.Empty);
    }
}

So basically I had a method AddCategory and RemoveCategory (inline in this case as lambda but you get the point) and bound this via EventToCommand to the viewmodel.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文