【问题标题】:Binding in ListBox of checkboxes where ItemSource is collection在 ItemSource 为集合的复选框的 ListBox 中绑定
【发布时间】:2018-02-14 22:29:17
【问题描述】:

我有复选框的组合框和列表框。根据 ListBox 的 ComboBox ItemSource 的 SelectedItem 必须更改。我做了一个样本让事情变得更容易。代码如下:

视图模型

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 属性绑定?

【问题讨论】:

  • XAML 不支持这种绑定:绑定路径=映射[Obj.SelectedItem.Id]。您必须将 Obj.SelectedItem.Id 替换为像“1”这样的常量值。
  • 那么“深于 1 级”是什么意思?要将 Checkbox 绑定到什么属性?
  • @mm8, MyData.Value
  • 您只能绑定到属性,因此 Value 必须是属性。但是您必须为 ItemsSource 提供有效的绑定才能使其正常工作。看我的回答。

标签: c# wpf xaml data-binding listbox


【解决方案1】:

我可以这样绑定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; }
}

【讨论】:

  • 那是我的错。在主项目中,我有财产。
【解决方案2】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-03
    • 2018-02-22
    • 1970-01-01
    • 1970-01-01
    • 2011-02-10
    相关资源
    最近更新 更多