在ListBox中绑定ItemSource是集合的复选框

时间:2017-09-06 12:20:20

标签: c# wpf xaml data-binding listbox

我有CheckBoxes的ComboBox和ListBox。根据ComboBox的SelectedItem,ListBox的ItemSource必须更改。我做了一个样本让事情变得更容易。这是代码:

视图模型

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Test
{
    class Data
    {
        public long Id;
        public object Value;

        public override string ToString()
        {
            return Value.ToString();
        }
    }

    class CheckedData: INotifyPropertyChanged
    {
        private Data myData;

        public Data MyData
        {
            get { return myData; }
            set
            {
                if (myData == value)
                    return;
                myData = value;
                RaisePropertyChanged(nameof(MyData));
            }
        }
        private bool isChecked;

        public bool IsChecked
        {
            get { return isChecked; }
            set
            {
                isChecked = value;
                RaisePropertyChanged(nameof(IsChecked));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    class BindingObject: INotifyPropertyChanged
    {
        private ObservableCollection<Data> dataList = new ObservableCollection<Data>();

        public ObservableCollection<Data> DataList
        {
            get { return dataList; }
            set
            {
                dataList = value;
                RaisePropertyChanged(nameof(DataList));
            }
        }

        private Data selectedItem;

        public Data SelectedItem
        {
            get { return selectedItem; }
            set
            {
                if (value == selectedItem)
                    return;
                selectedItem = value;
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }

    }

    class ViewModel: INotifyPropertyChanged
    {
        public ViewModel()
        {
            var tmp = new Data() {Id = 1, Value = "Cat"};
            Obj.DataList.Add(tmp);
            Obj.SelectedItem = tmp;
            Obj.DataList.Add(new Data() {Id = 2, Value = "Dog"});
            Mapping[1] = new ObservableCollection<CheckedData>()
            {
                new CheckedData() {IsChecked = true, MyData = new Data() {Id = 1, Value = "Maine coon"}},
                new CheckedData() {IsChecked = true, MyData = new Data() {Id = 2, Value = "Siberian"}}
            };

        }

        private BindingObject obj = new BindingObject();

        public BindingObject Obj
        {
            get { return obj; }
            set
            {
                if (obj == value)
                    return;
                obj = value;
                RaisePropertyChanged(nameof(Obj));
            }
        }

        private Dictionary<long, ObservableCollection<CheckedData>> mapping = new Dictionary<long, ObservableCollection<CheckedData>>();

        public Dictionary<long, ObservableCollection<CheckedData>> Mapping
        {
            get { return mapping; }
            set
            {
                if (mapping == value)
                    return;
                mapping = value;
                RaisePropertyChanged(nameof(Mapping));
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;

        protected void RaisePropertyChanged(string propertyName)
        {
            var handler = PropertyChanged;
            handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

视图

<ComboBox x:Name="comboBox" ItemsSource="{Binding Path=Obj.DataList}" SelectedItem="{Binding Path=Obj.SelectedItem, Mode=TwoWay}"/>
        <ListBox x:Name="listBox" Height="100" ItemsSource="{Binding Path=Mapping[Obj.SelectedItem.Id]}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Path=MyData.Value}" Margin="0,5,5,0"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

这是我认为应该工作的。 ComboBox没问题,但ListBox ItemSource绑定不起作用。只有我直接绑定到这样的列表:

视图模型

private ObservableCollection<CheckedData> test = new ObservableCollection<CheckedData>()
{
    new CheckedData() {IsChecked = true, MyData = new Data() {Id = 1, Value = "Maine coon"}},
    new CheckedData() {IsChecked = false, MyData = new Data() {Id = 2, Value = "Siberian"}}
};

public ObservableCollection<CheckedData> Test
{
    get { return test; }
    set
    {
        test = value;
        RaisePropertyChanged(nameof(Test));
    }
}

视图

<ListBox x:Name="listBox" Height="100" ItemsSource="{Binding Path=Test}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Path=MyData.Value}" Margin="0,5,5,0"/>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

一切都开始工作..除了内容绑定,因为我不能超过1级属性路径。所以我必须覆盖Data中的ToString()方法。

我应该如何解决一切问题?我能像这样绑定ItemSource吗?为什么我不能比CheckBox中的1 lvl属性绑定更深入了?

2 个答案:

答案 0 :(得分:0)

您可以通过以下方式轻松实现:

public ObservableCollection<CheckedData> SelectedData 
{ 
   get 
   { 
        return Mapping[Obj.SelectedItem.Id];
   } 
} 

进入

public Data SelectedItem
{
    get { return selectedItem; }
    set
    {
        if (value == selectedItem)
            return;
        selectedItem = value;
        RaisePropertyChanged(nameof(SelectedData)); // add this. 
    }
}

现在,在XAML中,您可以轻松:

<ListBox x:Name="listBox" Height="100" ItemsSource="{Binding Path=Obj.SelectedData}">

答案 1 :(得分:0)

  

我能像这样绑定ItemSource吗?

不,XAML不支持这种绑定:

Binding Path=Mapping[Obj.SelectedItem.Id]. 

您必须使用Obj.SelectedItem.Id之类的常量键值替换1,或绑定到返回项目集合的其他属性。

  

一切都开始工作了......除了内容绑定

您只能绑定到公共属性,因此Value必须是属性而不是字段:

class Data
{
    public long Id { get; set; }
    public object Value { get; set; }
}