绑定一个ObservableCollection< int>到IEnumerable< object>的自定义控件 [英] Binding a ObservableCollection<int> to IEnumerable<object> of a custom control

查看:107
本文介绍了绑定一个ObservableCollection< int>到IEnumerable< object>的自定义控件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有了一些帮助,我最近在我的自定义控件工作中绑定集合。然而,令我惊讶的是,我被告知,为了使自定义控件属性更灵活(可能绑定到其他参数化集合),我需要使自定义控件的属性是 IEnumerable< object> 因为协方差和逆变。

 <$ c 

$ c>< UserControl x:Class =BadaniaOperacyjne.Controls.Matrix
mc:Ignorable =dName =CustomMatrix
d:DesignHeight =300d:DesignWidth = >
< Grid>
<! - ... - >
< Grid Grid.Row =2Grid.Column =1Name =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(IEnumerable< object>),typeof PropertyMetadata(new PropertyChangedCallback(ItemsListChanged)));
public IEnumerable< object> ItemsList
{
get {return GetValue(ItemsListProperty)as IEnumerable< 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)
{
((Matrix)d).ItemsListChanged(e.NewValue);
}
#endregion

并且使用控件的窗口如下

 < custom:Matrix x:Name =customMatrixDockPanel.Dock =TopTitle ={ ItemsList ={Binding Items}/> 

代码隐藏像

  public class ViewModel:INotifyPropertyChanged 
{
public event PropertyChangedEventHandler PropertyChanged;

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

Items.CollectionChanged + = Items_CollectionChanged;
}

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>项目{get;私人集}

protected string title;
public string标题
{
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 ProblemManager()
{
VM = new ViewModel();

DataContext = VM;
InitializeComponent();

VM.Title =title;
}

private int i = 0;
private void btnAddRow_Click(object sender,RoutedEventArgs e)
{
//VM.Items.Add(++i);
VM.Items [2] = 112;
//customMatrix.ItemsList = new ObservableCollection< object> {1,2,3};
//customMatrix.ItemsList.Add(66);
//////
VM.Title =(++ i).ToString();
}

当我改变 DependencyProperty Items 控制到 ObservableCollection< int> 或至少 ObservableCollection< object> ,它工作正常。
是真的可能吗?

解决方案

Co-variance 允许 IEnumerable 但我只是检查它的只有允许的引用类型,而不是值类型(例如int)



如果您使用 ObservableCollection< string> 绑定,因为字符串参考类型



所以你可以做的是使用 IEnumerable(非泛型版本)作为你的DP的返回类型,这样,它也将工作的值类型:

  public static readonly DependencyProperty ItemsListProperty = 
DependencyProperty.Register(ItemsList,typeof(IEnumerable),typeof(Matrix),
new PropertyMetadata(new PropertyChangedCallback(ItemsListChanged)))

public IEnumerable ItemsList
{
get {return(IEnumerable)GetValue(ItemsListProperty); }
set {SetValue(ItemsListProperty,value);} }
}


With some help, I recently made binding collections in my custom control work. However, to my surprise I was told that to make the custom control property more flexible (that is possible to be bound with other parametrized collections), I needed to make the custom control's property to be of type IEnumerable<object> because of covariance and contravariance. However, this seems not to work for me

This is the control's view

<UserControl x:Class="BadaniaOperacyjne.Controls.Matrix"
            mc:Ignorable="d" Name="CustomMatrix"
            d:DesignHeight="300" d:DesignWidth="300">
    <Grid>
            <!-- ... -->
        <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>

and its code-behind is here

#region ItemsList Property
public static readonly DependencyProperty ItemsListProperty =
    DependencyProperty.Register("ItemsList", typeof(IEnumerable<object>), typeof(Matrix), new PropertyMetadata(new PropertyChangedCallback(ItemsListChanged)));
public IEnumerable<object> ItemsList
{
    get { return GetValue(ItemsListProperty) as IEnumerable<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)
{
    ((Matrix)d).ItemsListChanged(e.NewValue);
}
#endregion

and the Window that consumes the control is the following

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

with the code-behind like

public class ViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

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

        Items.CollectionChanged += Items_CollectionChanged;
    }

    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; private 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; }

// the window's constructor
private ProblemManager()
{
    VM = new ViewModel();

    DataContext = VM;
    InitializeComponent();

    VM.Title = "title";
}

private int i = 0;
private void btnAddRow_Click(object sender, RoutedEventArgs e)
{
    //VM.Items.Add(++i);
    VM.Items[2] = 112;
    //customMatrix.ItemsList = new ObservableCollection<object> { 1, 2, 3 };
    //customMatrix.ItemsList.Add(66);
    //////
    VM.Title = (++i).ToString();
}

When I change the DependencyProperty of the ItemsList control to ObservableCollection<int> or at least ObservableCollection<object>, it works fine. Is it really possible? If so, then is the mistake I made?

解决方案

Co-variance is allowed for IEnumerable but i just checked its only allowed for reference types and not for value types (e.g. int).

Your version will work if you bind with ObservableCollection<string> since string is reference type.

So what you can do is use IEnumerable (non-generic version) as return type of your DP like this so that it will work for value types as well:

public static readonly DependencyProperty ItemsListProperty =
    DependencyProperty.Register("ItemsList", typeof(IEnumerable), typeof(Matrix),
        new PropertyMetadata(new PropertyChangedCallback(ItemsListChanged)));

public IEnumerable ItemsList
{
    get { return (IEnumerable)GetValue(ItemsListProperty); }
    set { SetValue(ItemsListProperty, value); }
}

这篇关于绑定一个ObservableCollection&lt; int&gt;到IEnumerable&lt; object&gt;的自定义控件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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