绑定到IEnumerable <object>依赖项属性

时间:2015-10-29 10:46:48

标签: c# wpf dependency-properties

我创建了一个名为SearchableCheckBoxList的自定义控件(源自UserControl)。在此控件中,我有一个ItemsControl,其中包含Entry类型的项目,如下所示:

public class Entry : BindableBase
{
    public Entry(object content)
        : this(content, false)
    { }

    public Entry(object content, bool isChecked)
    {
        Content = content;
        IsChecked = isChecked;
    }

    private bool _isChecked;
    public bool IsChecked
    {
        get { return _isChecked; }
        set { this.SetProperty(ref this._isChecked, value); }
    }

    private object _content;
    public object Content
    {
        get { return _content; }
        set { SetProperty(ref _content, value); }
    }

}

在我的代码中,我还有DependencyProperty名为ItemsSource(类型为IEnumerable),其中包含任意类型的项目集合并将其转换为{{ 1}}类型。也就是说,对于集合中的每个元素,我正在创建一个新的Entry项并将该元素存储在Entry项的Content属性中,如下所示:

Entry

我这样做是因为在foreach (var item in ItemsSource) itemsControl.Items.Add(new Entry(item)); 我的每个项目旁边都有一个复选框,用户可以点击一个或多个复选框来选择多个项目,这些项目将反映每个{{1}的IsChecked属性1}}项目。

我的代码后面有另一个依赖属性,名为ItemsControl,定义如下:

Entry

每次在我的itemscontrol中选中或取消选中某个项目时,我都会更新上述DP:

SelectedItems

在我的主程序中,我正在使用此控件:

public IEnumerable<object> SelectedItems
{
    get { return (IEnumerable<object>)GetValue(SelectedItemsProperty); }
    set { SetValue(SelectedItemsProperty, value); }
}
public static readonly DependencyProperty SelectedItemsProperty = DependencyProperty.Register("SelectedItems", typeof(IEnumerable<object>), typeof(SearchableCheckBoxList), 
                                                                    new PropertyMetadata(default(IEnumerable<object>)));

在我的视图模型private void checkBox_CheckChanged(object sender, RoutedEventArgs e) { var checkBox = (CheckBox)sender; // Get entry from the content presenter var entry = ((Entry)(((ContentPresenter)checkBox.Content).DataContext)); // Set its checked value based on the checkbox's checked value entry.IsChecked = (bool)checkBox.IsChecked; // Update selected items collection SelectedItems = itemsControl.Items.Cast<Entry>().Where(i => i.IsChecked).Select(i => i.Content).ToList(); } <controls:SearchableCheckBoxList SelectedItems="{Binding SelectedCities, Mode=TwoWay}" ItemsSource="{Binding CityCollection, Mode=OneTime}"/> 中定义如下:

SelectedCities

控件看起来像this

现在,所有这些工作正常,绑定正在按预期更新。我遇到的问题是,为了工作,必须将SelectedCities定义为CityCollection。我想将SelectedCities定义为private ObservableCollection<CityModel> _cityCollection; public ObservableCollection<CityModel> CityCollection { get { return _cityCollection; } set { SetProperty(ref _cityCollection, value); } } private List<object> _selectedCities = new List<object>(); public List<object> SelectedCities { get { return _selectedCities; } set { SetProperty(ref _selectedCities, value); } } ,但如果我这样做,我的属性的setter总是被调用,值为null。我似乎无法弄清楚为什么或做什么。

编辑根据要求,此处为SearchableCheckBoxList.xamlSearchableCheckBoxList.cs

1 个答案:

答案 0 :(得分:2)

我相信你的问题是C#中的收藏是不协变。 我的意思是你不能将List<Person>投射到List<object>,即

class Program
{
    static void Main(string[] args)
    {
        List<object> foo = new List<object>();
        List<Person> bar = new List<Person>();

        List<object> some = (List<object>) bar;
    }

    class Person { }
}

上面的程序不会编译。你的程序编译,因为施法是由&#34; SetProperty&#34;方法

我认为您应该使用泛型或制作List<IBaseClass>的集合,而不是&#34; List<object>&#34;并确保所有模型都继承自IBaseClass

<强>更新

还有一种方法 - 使您的DP属性类型成为对象。对于团队中的其他开发人员来说,如果有的话可能会让人感到困惑。如果DP中有某些逻辑,则必须手动检查类型并进行转换

 public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            var control = new myUserControl();
            myPersons = new List<Person>() { new Person() { Name = "some" } };
            control.SetBinding(myUserControl.MyPropertyProperty, new Binding() { Source = MyPersons });
        }

        private List<Person> myPersons { get; set; }
        public List<Person> MyPersons { get { return myPersons; } set { myPersons = value; } }
    }

    public class Person { public string Name; }

    public class myUserControl : UserControl
    {
        public object MyProperty
        {
            get { return (object)GetValue(MyPropertyProperty); }
            set { SetValue(MyPropertyProperty, value); }
        }

        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty MyPropertyProperty =
            DependencyProperty.Register("MyProperty", typeof(object), typeof(myUserControl), new PropertyMetadata(0));
    }