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

时间:2013-07-23 12:22:31

标签: c# wpf mvvm

让我通过声明我对C#和WPF都很陌生来为这个问题添加前缀。

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

我通过修改ListBox的数据模板来创建复选框,并将ItemsSource的{​​{1}}设置为ListBox,但问题是我不知道知道要绑定ObservableCollection的内容,因为我试图将它绑定到集合中的实际对象而不是对象的属性。

3 个答案:

答案 0 :(得分:5)

使用IsChecked="{Binding}"直接绑定集合的项目。

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

但是,使用此方法无法绑定到源。因为IsChecked的{​​{1}}属性上的绑定不是绑定项的索引。因此,它不能更改集合,只能更改集合的项目。

更新

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

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

在XAML中:

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

答案 1 :(得分:4)

ItemTemplate你可以写

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

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

直接绑定到item对象,即集合中的bool值。


但请注意,在任何一种情况下,选中或取消选中CheckBox时,不会替换集合中的绑定值。为了在单击CheckBox时立即更新集合,您的集合必须包含具有绑定IsChecked的布尔属性的对象。

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

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

绑定现在看起来像这样:

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

该集合现在是ObservableCollection<BooleanHelper>,您可能会添加如下项目:

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

答案 2 :(得分: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()等等都会影响你的用户界面。