为图表用户控件创建项目 DP
Creating Items DP for charting user control
我正忙于创建具有一些基本 charting/graph 功能的用户控件。本质上,我希望有一个 "Items" 依赖项 属性 控件的用户可以绑定到该依赖项。然后该控件将显示对源所做的所有项目和更新。
到目前为止我所做的是在我的用户控件中创建一个 "Items" DP,代码隐藏。
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items",
typeof(ObservableCollection<Polyline>),
typeof(RPGraph),
new FrameworkPropertyMetadata(
new ObservableCollection<Polyline>(),
new PropertyChangedCallback(OnItemsChanged)));
public ObservableCollection<Polyline> Items
{
get { return (ObservableCollection<Polyline>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
我的第一个绊脚石是 "OnItemsChanged" 在我的集合更改时没有被调用。几个小时后,我发现了一个 Whosebug post 解释了原因 (ObservableCollection dependency property does not update when item in collection is deleted)。遵循此建议解决了我的部分问题。现在我可以将新项目(折线)添加到 ObservableCollection 列表中。但是,如果我在 Polyline 中添加了一个额外的点或修改了一个点会怎样。凭借对上一个问题的了解,我找到了 Points.Changed 事件。然后我订阅了它并将更新代码放在那里。
这终于奏效了,但是伙计,必须有更好或更优雅的方法来实现这一点(如顶部所述),我认为这一切都归结为不使用 ObservableCollection?有什么建议吗?
下面是有效的 OnItemChanged 方法(请原谅草稿代码,我只是想让它工作:-):
public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as RPGraph;
foreach (Polyline poly in thisControl.Items)
thisControl.manager.Items.Add(poly.Points.ToArray());
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
// Unsubscribe from CollectionChanged on the old collection
coll.CollectionChanged -= Items_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<Polyline>)e.NewValue;
// Subscribe to CollectionChanged on the new collection
coll.CollectionChanged += (o, t) => {
ObservableCollection<Polyline> items = o as ObservableCollection<Polyline>;
thisControl.manager.Items.Add(items[t.NewStartingIndex].Points.ToArray());
foreach (Polyline poly in items)
{
poly.Points.Changed += (n, m) => {
for (int i = 0; i < thisControl.manager.Items.Count; i++)
thisControl.manager.Items[i] = thisControl.Items[i].Points.ToArray();
thisControl.manager.DrawGraph(thisControl.graphView);
};
}
thisControl.manager.DrawGraph(thisControl.graphView);
};
}
thisControl.manager.DrawGraph(thisControl.graphView);
}
您完全正确,ObservableCollection
不会在其任何项目更改其 属性 值时发出通知。
您可以扩展 ObservableCollection
的功能,为这些情况添加通知。
它可能看起来像这样:
public sealed class ObservableNotifiableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public event ItemPropertyChangedEventHandler ItemPropertyChanged;
public event EventHandler CollectionCleared;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
base.OnCollectionChanged(args);
if (args.NewItems != null)
{
foreach (INotifyPropertyChanged item in args.NewItems)
{
item.PropertyChanged += this.OnItemPropertyChanged;
}
}
if (args.OldItems != null)
{
foreach (INotifyPropertyChanged item in args.OldItems)
{
item.PropertyChanged -= this.OnItemPropertyChanged;
}
}
}
protected override void ClearItems()
{
foreach (INotifyPropertyChanged item in this.Items)
{
item.PropertyChanged -= this.OnItemPropertyChanged;
}
base.ClearItems();
this.OnCollectionCleared();
}
private void OnCollectionCleared()
{
EventHandler eventHandler = this.CollectionCleared;
if (eventHandler != null)
{
eventHandler(this, EventArgs.Empty);
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs args)
{
ItemPropertyChangedEventHandler eventHandler = this.ItemPropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new ItemPropertyChangedEventArgs(sender, args.PropertyName));
}
}
}
然后您可以订阅 ItemPropertyChanged
活动并做您的事情。
我正忙于创建具有一些基本 charting/graph 功能的用户控件。本质上,我希望有一个 "Items" 依赖项 属性 控件的用户可以绑定到该依赖项。然后该控件将显示对源所做的所有项目和更新。
到目前为止我所做的是在我的用户控件中创建一个 "Items" DP,代码隐藏。
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items",
typeof(ObservableCollection<Polyline>),
typeof(RPGraph),
new FrameworkPropertyMetadata(
new ObservableCollection<Polyline>(),
new PropertyChangedCallback(OnItemsChanged)));
public ObservableCollection<Polyline> Items
{
get { return (ObservableCollection<Polyline>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
}
我的第一个绊脚石是 "OnItemsChanged" 在我的集合更改时没有被调用。几个小时后,我发现了一个 Whosebug post 解释了原因 (ObservableCollection dependency property does not update when item in collection is deleted)。遵循此建议解决了我的部分问题。现在我可以将新项目(折线)添加到 ObservableCollection 列表中。但是,如果我在 Polyline 中添加了一个额外的点或修改了一个点会怎样。凭借对上一个问题的了解,我找到了 Points.Changed 事件。然后我订阅了它并将更新代码放在那里。
这终于奏效了,但是伙计,必须有更好或更优雅的方法来实现这一点(如顶部所述),我认为这一切都归结为不使用 ObservableCollection?有什么建议吗?
下面是有效的 OnItemChanged 方法(请原谅草稿代码,我只是想让它工作:-):
public static void OnItemsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var thisControl = d as RPGraph;
foreach (Polyline poly in thisControl.Items)
thisControl.manager.Items.Add(poly.Points.ToArray());
if (e.OldValue != null)
{
var coll = (INotifyCollectionChanged)e.OldValue;
// Unsubscribe from CollectionChanged on the old collection
coll.CollectionChanged -= Items_CollectionChanged;
}
if (e.NewValue != null)
{
var coll = (ObservableCollection<Polyline>)e.NewValue;
// Subscribe to CollectionChanged on the new collection
coll.CollectionChanged += (o, t) => {
ObservableCollection<Polyline> items = o as ObservableCollection<Polyline>;
thisControl.manager.Items.Add(items[t.NewStartingIndex].Points.ToArray());
foreach (Polyline poly in items)
{
poly.Points.Changed += (n, m) => {
for (int i = 0; i < thisControl.manager.Items.Count; i++)
thisControl.manager.Items[i] = thisControl.Items[i].Points.ToArray();
thisControl.manager.DrawGraph(thisControl.graphView);
};
}
thisControl.manager.DrawGraph(thisControl.graphView);
};
}
thisControl.manager.DrawGraph(thisControl.graphView);
}
您完全正确,ObservableCollection
不会在其任何项目更改其 属性 值时发出通知。
您可以扩展 ObservableCollection
的功能,为这些情况添加通知。
它可能看起来像这样:
public sealed class ObservableNotifiableCollection<T> : ObservableCollection<T> where T : INotifyPropertyChanged
{
public event ItemPropertyChangedEventHandler ItemPropertyChanged;
public event EventHandler CollectionCleared;
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
{
base.OnCollectionChanged(args);
if (args.NewItems != null)
{
foreach (INotifyPropertyChanged item in args.NewItems)
{
item.PropertyChanged += this.OnItemPropertyChanged;
}
}
if (args.OldItems != null)
{
foreach (INotifyPropertyChanged item in args.OldItems)
{
item.PropertyChanged -= this.OnItemPropertyChanged;
}
}
}
protected override void ClearItems()
{
foreach (INotifyPropertyChanged item in this.Items)
{
item.PropertyChanged -= this.OnItemPropertyChanged;
}
base.ClearItems();
this.OnCollectionCleared();
}
private void OnCollectionCleared()
{
EventHandler eventHandler = this.CollectionCleared;
if (eventHandler != null)
{
eventHandler(this, EventArgs.Empty);
}
}
private void OnItemPropertyChanged(object sender, PropertyChangedEventArgs args)
{
ItemPropertyChangedEventHandler eventHandler = this.ItemPropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new ItemPropertyChangedEventArgs(sender, args.PropertyName));
}
}
}
然后您可以订阅 ItemPropertyChanged
活动并做您的事情。