添加集合项时,OnRender不会调用?

时间:2014-09-24 18:43:57

标签: c# wpf xaml wpf-controls dependency-properties

我有一个用于执行动态数据呈现的自定义控件。此控件包含DataPoint个对象的集合,每个DataPoint基于其位置在控件中呈现(这些点在OnRender方法中绘制)。

自定义控件包含许多会影响渲染图像的DependencyProperties,因此,FrameworkPropertyMetadata描述了属性更改时应该呈现控件:

public static readonly DependencyProperty DataPointsProperty = 
    DependencyProperty.Register(
        "DataPoints",                                      //Property Name
        typeof(List<DataPoint>),                           //CLR-Property Type
        typeof(MyCustomControl),                           //Custom Control Type
        new FrameworkPropertyMetadata(
            new List<DataPoint>(),                         //Default Value.
            FrameworkPropertyMetadataOptions.AffectsRender //Re-render if changed
        )
    );

不幸的是,当新的DataPoint 添加到此集合时,重新渲染会发生 NOT

如何配置我的自定义控件,以便在添加新的OnRender时调用DataPoint方法?

除了程序的运行时间之外,还必须在WPF设计器中进行重新渲染。

1 个答案:

答案 0 :(得分:4)

首先,List<T>不支持更改通知,而 支持更改通知的WPF内置集合并非来自List<T>。我建议您使用IList<T>IEnumerable<T>作为您的媒体资源类型。

其次,只要将新集合分配给DataPoints(在验证它实现INotifyCollectionChanged之后),就需要添加集合更改处理程序,并使用该处理程序调用{​​{1}}。最简单的方法是在注册InvalidateVisual()依赖项属性时指定属性更改回调。

DataPoints

最后,不要为默认属性值指定集合实例:这将导致所有实例共享同一个集合(除非分配了新集合)。而是在构造函数中初始化属性:

public static readonly DependencyProperty DataPointsProperty = 
    DependencyProperty.Register(
        "DataPoints",                                       //Property Name
        typeof(IList<DataPoint>),                            //CLR-Property Type
        typeof(MyCustomControl),                            //Custom Control Type
        new FrameworkPropertyMetadata(
            default(IList<DataPoint>),                      //Default Value.
            FrameworkPropertyMetadataOptions.AffectsRender, //Re-render if changed,
            OnDataPointsPropertyChanged
        )
    );

private static void OnDataPointsPropertyChanged(
    DependencyObject d,
    DependencyPropertyChangedEventArgs e)
{
    var control = (MyCustomControl)d;

    var oldValue = e.OldValue as INotifyCollectionChanged;
    var newValue = e.NewValue as INotifyCollectionChanged;

    if (oldValue != null)
        oldValue.CollectionChanged -= control.OnDataPointsCollectionChanged;

    if (newValue != null)
        newValue.CollectionChanged += control.OnDataPointsCollectionChanged;
}

private void OnDataPointsCollectionChanged(
    object s,
    NotifyCollectionChangedEventArgs e)
{
    this.InvalidateVisual();
}