我有控制
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 ,而不是操纵和增强他们。查看ItemsControl和 WPF Content Model了解更多。
关于c# - WPF - 在 UserControl 中绑定(bind) ObservableCollection 依赖属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2771407/