【问题标题】:Binding a ObservableCollection<int> to IEnumerable<object> of a custom control将 ObservableCollection<int> 绑定到自定义控件的 IEnumerable<object>
【发布时间】:2013-12-07 22:18:21
【问题描述】:

在一些帮助下,我最近在我的自定义控件工作中制作了绑定集合。然而,令我惊讶的是,我被告知要使自定义控件属性更灵活(可以与其他参数化集合绑定),我需要将自定义控件的属性设置为 IEnumerable&lt;object&gt; 类型,因为协变和逆变.但是,这似乎对我不起作用

这是控件的视图

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

它的代码隐藏在这里

#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

而消耗控件的Window如下

<custom:Matrix x:Name="customMatrix" DockPanel.Dock="Top" Title="{Binding Title}" 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> 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();
}

当我将ItemsList 控件的DependencyProperty 更改为ObservableCollection&lt;int&gt; 或至少ObservableCollection&lt;object&gt; 时,它工作正常。 真的有可能吗?如果是这样,那是我犯的错误吗?

【问题讨论】:

  • ItemsListChanged 不会被调用吗?
  • 删除所有代码并使用ItemsControl。不要试图重新发明轮子。它已经被发明出来了。
  • 它没有。这对我来说很奇怪,肯定需要解释或指出我的错误是什么。 @HighCore我不是想实现一个列表,这是更复杂的事情的开始。然而,在解决将集合绑定到自定义控件的问题时,我被告知这是使集合绑定更灵活的方法,但我无法完成这项工作。
  • @patryk 对不起,你说的是Custom Controls,但你在这里创建了一个UserControl。在概念上和代码/XAML 方面,它们是 2 个非常 不同的东西。同样,使用 ItemsControl。不要试图重新发明轮子。微软已经这样做了,而且他们比我们任何人都清楚。
  • 你说得有道理——直到现在我才发现这两者之间没有区别,谢谢。再说一次,如果我的目的是列出一个简单的集合,我就不会在这里寻求帮助。我不再重新发明任何类型的轮子了:)

标签: c# wpf data-binding collections


【解决方案1】:

Co-variance 允许用于 IEnumerable,但我只检查了它的唯一 allowed for reference types and not for value types (e.g. int)

如果您从string is reference type 开始绑定ObservableCollection&lt;string&gt;,您的版本将有效。

因此,您可以像这样使用 IEnumerable (non-generic version) 作为 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); }
}

【讨论】:

  • 使用IEnumerable作为控件的属性类型最终使它工作。谢谢!
猜你喜欢
  • 1970-01-01
  • 2011-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多