我创建了一个名为SearchableCheckBoxList的自定义控件(派生自UserControl).在这个控件中,我有一个ItemsControl,它包含Entry类型的Items,如下所示:
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); }
}
}
在我的代码背后,我还有一个名为ItemsSource(类型为IEnumerable)的DependencyProperty,它接受一组项目(任何类型)并将它们转换为Entry类型.也就是说,对于集合中的每个元素,我正在创建一个新的Entry项并将该元素存储在Entry项的Content属性中,如下所示:
foreach (var item in ItemsSource)
itemsControl.Items.Add(new Entry(item));
我这样做是因为在我的ItemsControl中,每个项目旁边都有一个复选框,用户可以单击一个或多个复选框来选择多个项目,这些项目将反映每个Entry项目的IsChecked属性.
我的代码后面有另一个依赖属性,名为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>)));
每次在我的itemscontrol中选中或取消选中某个项目时,我都会更新上述DP:
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}"/>
在我的viewmodel中,SelectedCities和CityCollection定义如下:
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); }
}
控件看起来像this.
现在,所有这些工作正常,绑定正在按预期更新.我遇到的问题是,为了工作,必须将SelectedCities定义为List< object>.我想将SelectedCities定义为List< CityModel>,但是如果我这样做,我的属性的setter总是被调用,值为null.我似乎无法弄清楚为什么或做什么.
编辑根据要求,这是SearchableCheckBoxList.xaml和SearchableCheckBoxList.cs
最佳答案 我相信你的问题是C#中的集合不是协变的.
我的意思是你不能投射List< Person>列出< 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 { }
}
上面的程序将无法编译.您的程序编译,因为转换是通过“SetProperty”方法间接发生的.
我认为您应该使用泛型或制作List< IBaseClass>的集合.而不是“List< object>”并确保所有模型都继承自IBaseClass
UPDATE
还有一种方法 – 使您的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));
}