如何将一个ObservableCollection<bool>绑定到WPF中的复选框列表(Listbox of Checkboxes)?

3

在开始这个问题之前,我要声明一下,我对C#和WPF都很陌生。

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

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


请您添加代码,这样我们才能更好地帮助您。 - Sonhja
3个回答

5
使用 IsChecked="{Binding}" 直接绑定集合中的项。
<ListBox ItemsSource="{Binding MyBooleanCollection}" >
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding Mode=OneWay}"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

然而,通过这种方法无法绑定到源代码。因为CheckBoxIsChecked属性的绑定不包括绑定项的索引。所以,它无法改变集合,只能改变集合中的项。

更新

为了解决这个限制,您可以创建一个布尔值的包装器:

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}"/>

当您绑定到例如List<bool>时,这需要设置Mode="OneWay" - Clemens
谢谢!我希望我能给你声望,但我刚刚创建了这个账户。 - jorgenfar

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 });

1
Path=.的目的是什么?这只是消除了双向绑定和绑定到源的错误,但并没有解决问题(只是隐藏了它)。更安全的做法是写{Binding} - Cédric Bignon
1
@CédricBignon 实际上我并没有说这比写 {Binding Mode=OneWay} 更好。这不重要,因为 OP 无论如何都必须将具有布尔属性的对象放入他的集合中,就像你在你的答案中展示的那样。 - Clemens
1
好的,但我认为这更糟糕。因为你没有看到它是单向的。 - Cédric Bignon

0
通过您提供的链接,您还可以将INotifyPropertyChanged扩展应用于CheckedListItem类,但前提是您不想使用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。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接