当 ObservableCollection 通过绑定更改时,自定义 UIElement 不会更新布局

Custom UIElement does not update layout when an ObservableCollection changes through binding

又遇到了一个(可能)简单的问题。

我想创建一个自定义 UIElement(一组保持正交的线)。 此 UIElement 在我的 MVVM 应用程序中用作视图。

这是我的代码:

class RaOrthogonalLine : Canvas, INotifyPropertyChanged
    {
        public RaOrthogonalLine()
        {
            Points.CollectionChanged += Points_CollectionChanged;
        }

        void Points_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            Paint();
        }

        void Paint()
        {
             //PaintingStuff! Here I would like to get in!
        }

        void newLine_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
        {
            if (LineClicked != null)
                LineClicked(sender, e);
        }

        public delegate void LineClickedEventHandler(object sender, MouseButtonEventArgs e);
        public event LineClickedEventHandler LineClicked;

        public ObservableCollection<RaPoint> Points
        {
            get
            {
                return (ObservableCollection<RaPoint>)GetValue(PointsProperty);
            }
            set
            {
                SetValue(PointsProperty, value);
                RaisePropertyChanged("Points");
            }
        }
        public static readonly DependencyProperty PointsProperty = DependencyProperty.Register("Points", typeof(ObservableCollection<RaPoint>), typeof(RaOrthogonalLine),
            new FrameworkPropertyMetadata(new ObservableCollection<RaPoint>(), new PropertyChangedCallback(PointsPropertyChanged))
        {
            BindsTwoWayByDefault = true,
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
        }
        );

        private static void PointsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            RaOrthogonalLine thisLine = (RaOrthogonalLine)d;
            thisLine.Paint();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        protected void RaisePropertyChanged(string name)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(name));
            }
        }

    }

在我的 XAML 中,我将 ViewModel 的 ObservableCollection 绑定到 UIElement(View) 中的 ObservableCollection。

效果很好。

我现在的问题是当集合发生变化时我没有收到通知 (Add/Remove/..) - 因为那时我需要重新绘制它。

我尝试获取 Points.CollectionChanged 事件,但它没有触发。

有人有想法吗?

谢谢!

问题是您在控件的构造函数中添加了 CollectionChanged 事件处理程序。在构造函数中,您的 Paint 属性 尚未绑定到正确的源(实际上它具有 PointsProperty 的默认值,即空集合)。

您应该在 PointsPropertyChanged 方法中添加和删除事件处理程序。看看这个示例代码:

public class RaOrthogonalLine : Canvas
{
    public INotifyCollectionChanged Points
    {
        get { return (INotifyCollectionChanged)GetValue(PointsProperty); }
        set { SetValue(PointsProperty, value); }
    }


    public static readonly DependencyProperty PointsProperty =
        DependencyProperty.Register("Points", typeof(INotifyCollectionChanged), typeof(RaOrthogonalLine),
        new FrameworkPropertyMetadata(null, new PropertyChangedCallback(PointsPropertyChanged))
        {
            BindsTwoWayByDefault = true,
            DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
        });

    void Points_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Paint();
    }

    private static void PointsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        RaOrthogonalLine raOrthogonalLine = (RaOrthogonalLine)d;
        INotifyCollectionChanged newValue = (INotifyCollectionChanged)e.NewValue;
        INotifyCollectionChanged oldValue = (INotifyCollectionChanged)e.OldValue;

        if (oldValue != null)
        {
            oldValue.CollectionChanged -= raOrthogonalLine.Points_CollectionChanged;
        }

        if (newValue != null)
        {
            newValue.CollectionChanged += raOrthogonalLine.Points_CollectionChanged;
        }
        raOrthogonalLine.Paint();
    }
}

希望对您的问题有所帮助。

这可能与依赖性有关属性,但这对我来说很好用。
您确定要在集合中添加和删除(而不是替换集合)吗?

public class Points
{
    void Strings_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        Debug.WriteLine("Strings_CollectionChanged");
    }
    private ObservableCollection<string> strings = new ObservableCollection<string>();
    // I think you are better off with just a get 
    public ObservableCollection<string> Strings { get { return strings; } }
    public Points()
    {
        Strings.CollectionChanged += new NotifyCollectionChangedEventHandler(Strings_CollectionChanged);
        Strings.Add("new one");
        Strings.Add("new two");
        Strings.RemoveAt(0);
    }
}