如何在 UserControl 中绑定集合依赖属性 [英] How to bind collection dependency property in UserControl

查看:96
本文介绍了如何在 UserControl 中绑定集合依赖属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这不是重复的!当我失败时,我尝试查看类似的帖子,但没有成功.我不明白为什么不调用 OnUCItemsSourceChanged?我很确定我错过了一些简单但找不到的东西.

我有包含 UserControl1Window,它附加了绑定到 WindowWindowCollection 的集合属性收藏.我希望在将项目添加到 WindowCollection 时调用 UserControl1.OnUCItemsSourceChanged.但它不会发生.

我想念什么?

Window1.xaml.cs

public 部分类 Window1 : Window{公共 ObservableCollection;WindowCollection { 获取;放;}公共窗口 1(){初始化组件();数据上下文 = 这个;WindowCollection = new ObservableCollection();}私有无效Button_Click(对象发送者,RoutedEventArgs e){WindowCollection.Add(1);WindowCollection.Add(2);}}

Window1.xaml

<uc:UserControl1 UCItemsSource="{绑定路径=WindowCollection}"/><Button Content="Refresh" Click="Button_Click"/></StackPanel>

UserControl1.xaml.cs

public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", typeof(IEnumerable), typeof(UserControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));公共 IEnumerable UCItemsSource{得到{返回(IEnumerable)GetValue(UCItemsSourceProperty);}set { SetValue(UCItemsSourceProperty, value);}}公共 ObservableCollectionUCItems { 得到;放;}私有静态无效 OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var control = d as UserControl1;var items = e.NewValue as ObservableCollection;foreach (var item in items){control.UCItems.Add(new MyItem(item));}}

UserControl1.xaml

更新这是链接到我的测试项目

解决方案

在这一行:

必须是 RelativeSource 和 FindAncestor,因为 UCItems 位于 UserControl 中:

用户控件

<小时><块引用>

我不明白为什么不调用 OnUCItemsSourceChanged?

如果添加 RelativeSource 构造,则 OnUCItemsSourceChanged 至少导致一次,因为 PropertyChangedCallback 每次为依赖属性设置新值时都会触发:

<块引用>

表示当依赖属性的有效属性值改变时调用的回调.

因为你曾经在这里设置了依赖属性的值:

<小时><块引用>

我希望在向 WindowCollection 添加项目时调用 UserControl1.OnUCItemsSourceChanged.

这是一个 ObservableCollection<T>.CollectionChanged 事件,其中包含对集合执行的行为的枚举:

<块引用>

在添加、删除、更改、移动项目或刷新整个列表时发生.

对于您的情况,它将是这样的:

CollectionChanged 的​​版本

主窗口

公共部分类 MainWindow : Window{公共 ObservableCollection;WindowCollection { 获取;放;}公共主窗口(){初始化组件();数据上下文 = 这个;WindowCollection = new ObservableCollection();WindowCollection.Add(1);WindowCollection.Add(2);}私有无效Button_Click(对象发送者,RoutedEventArgs e){WindowCollection.Add(3);WindowCollection.Add(4);}}

用户控件

公共部分类 UserControl1 : UserControl{#region 公共部分公共 ObservableCollection;UCItems { 得到;放;}公共静态 UserControl1 控件;#endregion公共用户控件1(){初始化组件();UCItems = new ObservableCollection();}#region UCItemsSource 属性public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource",类型(IEnumerable),类型(用户控制1),new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));公共 IEnumerable UCItemsSource{得到{返回(IEnumerable)GetValue(UCItemsSourceProperty);}set { SetValue(UCItemsSourceProperty, value);}}#endregion私有静态无效 OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){control = d as UserControl1;var items = e.NewValue as ObservableCollection;items.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);添加项目(控件,项目);}private static void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e){var items = sender as ObservableCollection;control.UCItems.Clear();if (e.Action == NotifyCollectionChangedAction.Add){添加项目(控件,项目);}}private static void AddItem(UserControl1 userControl, ObservableCollection 集合){if (collection.Count > 0){foreach(集合中的var 项目){userControl.UCItems.Add(item);}}}}

<小时><块引用>

此项目可在此link

替代版本

这个版本更简单,更正确.这里我们只引用包含集合的 UCItemsSource 属性,这里也有 RelativeSource 对齐:

UserControl

XAML

<ItemsControl ItemsSource="{绑定路径=UCItemsSource,相对来源={相对来源模式=FindAncestor,AncestorType={x:Type UserControl}}}"><ItemsControl.ItemTemplate><数据模板><TextBlock Text="{Binding}"/></数据模板></ItemsControl.ItemTemplate></ItemsControl></网格>

代码隐藏

公共部分类 UserControl1 : UserControl{#region 公共部分公共 ObservableCollectionUCItems { 得到;放;}#endregion公共用户控件1(){初始化组件();UCItems = new ObservableCollection();}#region UCItemsSource 属性public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource",类型(IEnumerable),typeof(UserControl1));公共 IEnumerable UCItemsSource{得到{返回(IEnumerable)GetValue(UCItemsSourceProperty);}set { SetValue(UCItemsSourceProperty, value);}}#endregion}

This is not a duplicate! When I failed I tried to look to similar posts but without success. I cannot understand why OnUCItemsSourceChanged is not called? I'm pretty sure that I miss something simple but I cannot find it.

I have Window that contains UserControl1 which has attached collection property that is bound to Window's WindowCollection collection. I expect UserControl1.OnUCItemsSourceChanged to be called when I add items to WindowCollection. But it doesn't happen.

What I miss?

Window1.xaml.cs

public partial class Window1 : Window
{
    public ObservableCollection<long> WindowCollection { get; set; }
    public Window1()
    {
        InitializeComponent();

        DataContext = this;

        WindowCollection = new ObservableCollection<long>();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        WindowCollection.Add(1);
        WindowCollection.Add(2);
    }
}

Window1.xaml

<StackPanel>
    <uc:UserControl1 UCItemsSource="{Binding Path=WindowCollection}" />
    <Button Content="Refresh" Click="Button_Click" />
</StackPanel>

UserControl1.xaml.cs

public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", typeof(IEnumerable), typeof(UserControl1), new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));

public IEnumerable UCItemsSource
{
    get { return (IEnumerable)GetValue(UCItemsSourceProperty ); }
    set { SetValue(UCItemsSourceProperty , value); }
}

public ObservableCollection<MyItem> UCItems { get; set; }

private static void OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var control = d as UserControl1;
    var items = e.NewValue as ObservableCollection<long>;

    foreach (var item in items)
   {
         control.UCItems.Add(new MyItem(item));
   }
}

UserControl1.xaml

<ItemsControl ItemsSource="{Binding UCItems}" ... />

UPDATE This is link to my test project

解决方案

In this line:

<ItemsControl ItemsSource="{Binding UCItems}" ... />

Must be RelativeSource with FindAncestor, because UCItems located in UserControl:

UserControl

<ItemsControl ItemsSource="{Binding Path=UCItems,
                                    RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}}" />


I cannot understand why OnUCItemsSourceChanged is not called?

If you add RelativeSource construction, then OnUCItemsSourceChanged causing at least once because PropertyChangedCallback triggered every time then you set new value for the dependency property:

Represents the callback that is invoked when the effective property value of a dependency property changes.

Since you once sets the value for dependency property here:

<uc:UserControl1 UCItemsSource="{Binding Path=WindowCollection}" />


I expect UserControl1.OnUCItemsSourceChanged to be called when I add items to WindowCollection.

For this is an ObservableCollection<T>.CollectionChanged event, in that contains the enumeration of acts performed on the collection:

Occurs when an item is added, removed, changed, moved, or the entire list is refreshed.

For your case it will be something like this:

Version with CollectionChanged

MainWindow

public partial class MainWindow : Window
{
    public ObservableCollection<long> WindowCollection { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        DataContext = this;

        WindowCollection = new ObservableCollection<long>();

        WindowCollection.Add(1);
        WindowCollection.Add(2);            
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        WindowCollection.Add(3);
        WindowCollection.Add(4);
    }
}

UserControl

public partial class UserControl1 : UserControl
{
    #region Public Section

    public ObservableCollection<long> UCItems { get; set; }
    public static UserControl1 control;

    #endregion

    public UserControl1()
    {
        InitializeComponent();
        UCItems = new ObservableCollection<long>();            
    }

    #region UCItemsSource Property

    public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", 
                                                                                                  typeof(IEnumerable), 
                                                                                                  typeof(UserControl1),
                                                                                                  new PropertyMetadata(null, new PropertyChangedCallback(OnUCItemsSourceChanged)));

    public IEnumerable UCItemsSource
    {
        get { return (IEnumerable)GetValue(UCItemsSourceProperty); }
        set { SetValue(UCItemsSourceProperty, value); }
    }

    #endregion

    private static void OnUCItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        control = d as UserControl1;
        var items = e.NewValue as ObservableCollection<long>;

        items.CollectionChanged += new NotifyCollectionChangedEventHandler(CollectionChanged);
        AddItem(control, items);
    }

    private static void CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        var items = sender as ObservableCollection<long>;
        control.UCItems.Clear();

        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            AddItem(control, items);
        }
    }

    private static void AddItem(UserControl1 userControl, ObservableCollection<long> collection) 
    {
        if (collection.Count > 0)
        {
            foreach (var item in collection)
            {
                userControl.UCItems.Add(item);
            }
        }
    }
}


This project available in this link

Alternative version

This version is simpler and more correct. Here we just reference to UCItemsSource property that contain collection, also here RelativeSource justified:

UserControl

XAML

<Grid>
    <ItemsControl ItemsSource="{Binding Path=UCItemsSource, 
                                        RelativeSource={RelativeSource Mode=FindAncestor,
                                                                       AncestorType={x:Type UserControl}}}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBlock Text="{Binding}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</Grid>

Code-behind

public partial class UserControl1 : UserControl
{
    #region Public Section

    public ObservableCollection<long> UCItems { get; set; }

    #endregion

    public UserControl1()
    {
        InitializeComponent();

        UCItems = new ObservableCollection<long>();
    }

    #region UCItemsSource Property

    public static readonly DependencyProperty UCItemsSourceProperty = DependencyProperty.Register("UCItemsSource", 
                                                                                                  typeof(IEnumerable), 
                                                                                                  typeof(UserControl1));                                                                                                      

    public IEnumerable UCItemsSource
    {
        get { return (IEnumerable)GetValue(UCItemsSourceProperty); }
        set { SetValue(UCItemsSourceProperty, value); }
    }

    #endregion
}

这篇关于如何在 UserControl 中绑定集合依赖属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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