将集合绑定到自定义控件属性 [英] Binding a collection to a custom control property

查看:173
本文介绍了将集合绑定到自定义控件属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我没有运气试图绑定数据集合到我的自定义控件的属性。我已经实现了这个控件的字符串属性的机制(从这里一个小帮助),并希望集合类型是容易的。

I am having no luck trying to bind a collection of data to my custom control its property. I already have implemented the mechanism for a string property of this control (with a small help from here) and expected the collection type to be as easy. However I cannot make it work again.

Here is my custom control view

这是我的自定义控制视图

<UserControl x:Class="BadaniaOperacyjne.Controls.Matrix" mc:Ignorable="d" Name="CustomMatrix" d:DesignHeight="300" d:DesignWidth="300"> <Grid> <Grid.RowDefinitions> <!-- ... --> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <!-- ... --> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding ElementName=CustomMatrix, Path=Title}"/> <Grid Grid.Row="2" Grid.Column="1" Name="contentGrid"> <ListBox ItemsSource="{Binding ElementName=CustomMatrix, Path=ItemsList}"> <ListBox.ItemTemplate> <DataTemplate> <TextBlock Text="{Binding}"/> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </Grid> </Grid> </UserControl>

及其代码隐藏

#region ItemsList Property
public static readonly DependencyProperty ItemsListProperty =
    DependencyProperty.Register("ItemsList", typeof(ObservableCollection<object>), typeof(Matrix), new PropertyMetadata(new ObservableCollection<object>(), new PropertyChangedCallback(ItemsListChanged)));
public ObservableCollection<object> ItemsList
{
    get { return GetValue(ItemsListProperty) as ObservableCollection<object>; }
    set { SetValue(ItemsListProperty, value); }
}
private void ItemsListChanged(object value)
{
    System.Diagnostics.Debug.WriteLine("matrix: items list changed " + value);
    if (ItemsList != null)
    {
        ItemsList.CollectionChanged += ItemsList_CollectionChanged;
        System.Diagnostics.Debug.WriteLine("got " + string.Join(",", ItemsList.ToList()));
    }
    else
    {
        System.Diagnostics.Debug.WriteLine("got null");
    }
}

void ItemsList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
    System.Diagnostics.Debug.WriteLine("matrix: current items list collection changed");
}
private static void ItemsListChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    // a breakpoint
    ((Matrix)d).ItemsListChanged(e.NewValue);
}
#endregion

// showing the Title property implementation just to state that
// it is done the same way as for ItemsList
#region Title Property
public static readonly DependencyProperty TitleProperty = 
    DependencyProperty.Register("Title", typeof(string), typeof(Matrix), new PropertyMetadata("", new PropertyChangedCallback(TitleChanged)));
public string Title
{
    get { return (string)GetValue(TitleProperty); }
    set { SetValue(TitleProperty, value); }
}
private void TitleChanged(string title)
{
    System.Diagnostics.Debug.WriteLine("matrix: title changed to: " + title);
}
private static void TitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    ((Matrix)d).TitleChanged((string)e.NewValue);
}
#endregion

这里是我试图绑定到控制

And here's how I am trying to bind to that control

<custom:Matrix x:Name="customMatrix" DockPanel.Dock="Top" Title="{Binding Title}" ItemsList="{Binding Items}"/>

并且主页的代码隐藏是

//internal ObservableCollection<List<int>> ItemsList { get; set; }
public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ViewModel()
    {
        Items = new ObservableCollection<int> { 1, 2, 3, 4, 5, 6};
    }

    void Items_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        System.Diagnostics.Debug.WriteLine("problem manager: items list changed " + e.NewItems.Count);
    }

    public ObservableCollection<int> Items { get; set; }

    protected string title;
    public string Title
    {
        get { return title; }
        set
        {
            if (title != value)
            {
                title = value;
                NotifyPropertyChanged("Title");
            }
        }
    }

    protected void NotifyPropertyChanged(string name)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(name));
        }
    }
}

public ViewModel VM { get; private set; }

// this is the window constructor
private ProblemManager() 
{
    VM = new ViewModel();

    DataContext = VM;
    InitializeComponent();

    VM.Title = "title";
}

private int i = 0;
private void btnAddRow_Click(object sender, RoutedEventArgs e)
{
    // when doing either of these two lines below, 
    // the control breakpoint is never hit
    VM.Items.Add(++i);
    VM.Items = new ObservableCollection<int> { 2, 3 };

    // however, when directly assigning to the control's property, 
    // the event is raised and the breakpoint is hit and the UI is updated
    customMatrix.ItemsList = new ObservableCollection<object> { 1, 2, 3 };
    customMatrix.ItemsList.Add(66);
    // and this of course makes the control's title update
    VM.Title = (++i).ToString();
}

两个 DependencyProperty 对于控件的标题 ItemsList ,我相信,创建了相同的方式。尽管如此,绑定可能不工作,因为 ItemsListChanged 事件不是由该绑定引发的。
所以,问题是我不能通过XAML绑定我的窗口的 ViewModel.Items 集合到控件的 ItemsList 集合。正在为一个控件中的集合创建 DependencyProperty DependencyProperty 不同的一个简单的字符串 c> DependencyProperty

Both DependencyPropertys for the control's Title and ItemsList are, I believe, created the same way. Nonetheless, the binding is probably not working as the ItemsListChanged event is not raised by that binding. So, the problem is that I cannot bind my window's ViewModel.Items collection via XAML to the control's ItemsList collection. Is creating a DependencyProperty for a collection within a control any different from DependencyProperty for a simple string property?

推荐答案

c>注册。 协同方差不适用于通用名单,即您不能这样做 -

Problem is in your DependencyProperty registration. Co-variance is not applicable for generic lists i.e. you cannot do this -

ObservableCollection<object> objects = new ObservableCollection<int>();

您已将DP的类型声明为 ObservableCollection< object> ,但绑定类型 ObservableCollection< int> 的列表

You have declared type of DP as ObservableCollection<object> but binding it with list of type ObservableCollection<int>.

您应该将DP的类型更改为ObservableCollection< int> 将更改绑定集合类型更改为ObservableCollection< object>

public ViewModel()
{
    Items = new ObservableCollection<object> { 1, 2, 3, 4, 5, 6};
}

public ObservableCollection<object> Items { get; set; }

这篇关于将集合绑定到自定义控件属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆