c# - WPF - 在 UserControl 中绑定(bind) ObservableCollection 依赖属性

标签 c# wpf data-binding observablecollection dependency-properties

我有控制

class DragGrid : Grid { ... }

继承自原始网格并支持拖动和调整其子元素的大小。 我需要将名为 WorkItemsProperty 的自定义 DP 绑定(bind)到类型为 WorkItem 的可观察集合(实现 INotifyPropertyChanged )。网格中的每个元素都绑定(bind)到一个集合项。

每当用户在运行时动态添加新项目(项目不能在 XAML 中声明!),或从该集合中删除项目时,DragGrid 上的 WorkItems DP 应该更新,并且网格中的子项(其中每个子项代表一个 WorkItem 集合项)。

我的问题是 DP 如何通知控件网格中的哪个子元素必须删除更改(“更改”表示用户拖动了一个元素,或者用鼠标调整它的大小)或添加,以及我如何确定现有子项中的哪一个是需要删除或更改的子项。 我知道这就是 DependencyPropertyChangedCallback 出现的地方。但是只有在重新设置 DP 属性时才会调用它,而不是在集合中的某些内容发生更改时(如添加、删除项目)。那么最后,DragGrid 控件是否需要以某种方式订阅 CollectionChanged 事件?我应该在什么时候为此连接事件处理程序?

*编辑:: 首先使用 Grid 的原因是因为我希望能够在用户拖动或调整 Grid 中的控件大小时保持最小增量。一个控件代表一个时间跨度,每个网格列代表15min(这是最小值)。在带有 Thumbs 的 Canvas 中执行此操作很困难且存在错误。实现 DragGrid 解决了我的用户交互问题。此外,Canvas 不可扩展,因此必须始终重新计算时间跨度。使用网格,我没有问题,因为无论大小如何,列都会告诉我时间。**

最佳答案

回答您的实际问题:

如前所述,您应该添加一个 DepencyPropertyChanged 处理程序。在此处理程序中,您应该向新集合的 CollectionChanged 属性添加一个事件处理程序,并从旧集合中删除该处理程序,如下所示:

    public ObservableCollection<WorkItem> WorkItems
    {
        get { return (ObservableCollection<WorkItem>)GetValue(WorkItemsProperty); }
        set { SetValue(WorkItemsProperty, value); }
    }

    // Using a DependencyProperty as the backing store for WorkItems.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty WorkItemsProperty =
        DependencyProperty.Register("WorkItems", typeof(ObservableCollection<WorkItem>), typeof(DragGrid), new FrameworkPropertyMetadata(null, OnWorkItemsChanged));

    private static void OnWorkItemsChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        DragGrid me = sender as DragGrid;

        var old = e.OldValue as ObservableCollection<WorkItem>;

        if (old != null)
            old.CollectionChanged -= me.OnWorkCollectionChanged;

        var n = e.NewValue as ObservableCollection<WorkItem>;

        if (n != null)
            n.CollectionChanged += me.OnWorkCollectionChanged;
    }

    private void OnWorkCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Reset)
        {
            // Clear and update entire collection
        }

        if (e.NewItems != null)
        {
            foreach (WorkItem item in e.NewItems)
            {
                // Subscribe for changes on item
                item.PropertyChanged += OnWorkItemChanged;

                // Add item to internal collection
            }
        }

        if (e.OldItems != null)
        {
            foreach (WorkItem item in e.OldItems)
            {
                // Unsubscribe for changes on item
                item.PropertyChanged -= OnWorkItemChanged;

                // Remove item from internal collection
            }
        }
    }

    private void OnWorkItemChanged(object sender, PropertyChangedEventArgs e)
    {
        // Modify existing item in internal collection
    }

正如 gehho 所解释的,听起来您并没有像最初预期的那样使用 Grid 类,尽管您可能已经进入开发阶段太远以至于不想在此时重新开始。从 Panel 派生的类实际上只是为了在视觉上绘制/安排他们的 child ,而不是操纵和增强他们。查看ItemsControlWPF Content Model了解更多。

关于c# - WPF - 在 UserControl 中绑定(bind) ObservableCollection 依赖属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2771407/

相关文章:

wpf - 导入具有特定参数的类

wpf - 为什么无法在组合框中选择空值?

android - 从 ApplicationTest 启动时,DataBindingUtil 不得返回 null

c# - 使用 Azure CosmosDb 表 API 查询日期范围时出现 InvalidFilterException

c# - 如何在 C# 中创建类型化的 IEnumerable?

c# - 为什么在创建哈希时要将文本转换为字节

c# - 优化 Linq : IN operator with large data

DataGrid 中的 WPF 图像绑定(bind)

javascript - Angular 应用程序不显示 $scope 数据