如何将 ObservableCollection<bool> 绑定到 WPF 中的复选框列表框

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

让我在这个问题之前声明我对 C# 和 WPF 都很陌生。

我正在尝试将一组

Boolean
值连接到包含 6 个复选框的容器,并在按下按钮时存储这些值的状态。我假设有一种简单的方法可以做到这一点,因为将复选框绑定到集合似乎是一件非常自然的事情,但到目前为止我看到的所有解决方案似乎都过于复杂(例如:http://merill .net/2009/10/wpf-checked-listbox/)。

我通过修改

ListBox
的数据模板来创建复选框,并将
ItemsSource
ListBox
设置为
ObservableCollection
,但我的问题是我不知道将
IsChecked
绑定到什么,因为我试图将它绑定到集合中的实际对象而不是对象的属性。

c# wpf mvvm
4个回答
5
投票

使用

IsChecked="{Binding}"
直接绑定集合的item。

<ListBox ItemsSource="{Binding MyBooleanCollection}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding Mode=OneWay}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

但是,无法使用此方法绑定到源。因为

IsChecked
CheckBox
属性上的绑定不是绑定项的索引。因此,它不能更改集合,只能更改集合的项目。

更新

要解决该限制,您可以创建布尔值的包装器:

public class Wrapper<T> : INotifyPropertyChanged
{
    private T value;
    public T Value
    {
        get { return value; }
        set
        {
            {
                this.value = value;
                OnPropertyChanged();
            }
        }
    }

    public static implicit operator Wrapper<T>(T value)
    {
        return new Wrapper<T> { value = value };
    }
    public static implicit operator T(Wrapper<T> wrapper)
    {
        return wrapper.value;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

这是一个用法示例:

public partial class MainWindow : Window
{
    public ObservableCollection<Wrapper<bool>> MyBooleanCollection { get; private set; }

    public MainWindow()
    {
        InitializeComponent();

        DataContext = this;
        MyBooleanCollection = new ObservableCollection<Wrapper<bool>>() { false, true, true, false, true };
    }
}

在 XAML 中:

<CheckBox IsChecked="{Binding Value}"/>

4
投票

ItemTemplate
中你可以写

<CheckBox IsChecked="{Binding Path=.}"/>

<CheckBox IsChecked="{Binding Mode=OwnWay}"/>

直接绑定到项目对象,即集合中的

bool
值。


但请注意,无论哪种情况,当选中或取消选中复选框时,集合中的绑定值都不会被替换。为了在单击复选框时立即更新集合,您的集合必须包含具有布尔属性且绑定了

IsChecked

 的对象。

在您的情况下,这可能如下所示简单(因为您的问题听起来像您不需要属性更改通知):

public class BooleanHelper { public bool Value { get; set; } }

绑定现在看起来像这样:

<CheckBox IsChecked="{Binding Path=Value}"/>

该集合现在将是一个

ObservableCollection<BooleanHelper>

,您可能会添加如下项目:

Items.Add(new BooleanHelper { Value = true });
    

0
投票
通过您提供的链接,您还可以对 CheckedListItem 类使用 INotifyPropertyChanged 扩展,但前提是您不想使用 ObservableCollection。会是这样的:

public class CheckedListItem : INotifyPropertyChanged { private int _Id; public int Id { get; set; NotifyIfAnythingChanged("Id"); } private string _Name; public string Name { get; set; NotifyIfAnythingChanged("Name"); } private bool _IsChecked; public bool IsChecked { get; set; NotifyIfAnythingChanged("IsChecked"); } private void NotifyIfAnythingChanged(String propName) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propName)); } public event PropertyChangedEventHandler PropertyChanged; }

你的列表框应该是这样的:

<ListBox x:Name="MyListBox"> <ListBox.ItemTemplate> <DataTemplate> <CheckBox Content={Binding Path=Name} IsChecked="{Binding Mode=TwoWay, Path=IsChecked}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox>

在后面的代码中,您应该只初始化 ObservableCollection 一次,因为对其进行的每次更改都会导致 UI 更新。

ObservableCollection<CheckedListItem> MyList = new ObservableCollection<CheckedListItem>(); MyListBox.ItemsSource = MyList;

现在对 MyList 所做的每一个更改,例如 Add()、Remove() 等都会影响您的 UI。


0
投票
Я решил проблему так: Есть класс в нем, имеется колекция

ObservableCollection 和 мне нужно было отслеживать изменения в этой колекции поэтому создании экземпляра класса я подписывался на события изменений колекции и выполнял свое событие о том что данное изменено.

//Наследую для обратной связи о каких либо изменениях public class Company : INotifyPropertyChanged { //Собитие public event PropertyChangedEventHandler PropertyChanged; //Обработчик события protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } ... //Та самя колекция в которой я хочу отслеживать измения private ObservableCollection<bool> _companyBuldVisible; public ObservableCollection<bool> CompanyBuldVisible { get => _companyBuldVisible; set { _companyBuldVisible = value; OnPropertyChanged(); //Это вызывается только при создании или переприсвоению } } ... public ICommand SelectCompany { get; set; } public Company() { SelectCompany = new Command(async p => { ... //Подписываться на собитие возможно только когда колекция инициализирована, поэтому я повесил его на Клик CompanyBuldVisible.CollectionChanged += CompanyBuldVisible_CollectionChanged; // Подписка на событие что какое значение было изменено }); } private void CompanyBuldVisible_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { //Отписываюсь для того чтобы подписки не скапливались и обработка не срабатывала несколько раз CompanyBuldVisible.CollectionChanged -= CompanyBuldVisible_CollectionChanged; OnPropertyChanged("CompanyBuldVisible"); //Сообщаю об этом изменении свой класс } }
    
© www.soinside.com 2019 - 2024. All rights reserved.