Question on MVVM pattern on WPF?

2019-08-06 03:20发布

问题:

I have a user control let say UC1 . This user control have viewmodel UC1_vm.

In the usercontrol UC1 I have a canvas in which drawing curve logic is implemented. This drawing curve logic is based on the data points property in the view model ( UC1_vm).

The data points property inside the view model change with different condition. The generation of data points is written in the View Model.

I want to bind the data points property in the view model to the draw curve logic inside the User control (view). I want whenever the data point property is changed in the view model , the canvas calls the draw curve method.

Can I set the set any property of canvas which when changed it calls the on paint logic auto matically?

Please suggest me the approach of implementing this scenario!!

回答1:

It sounds like you have a DependencyProperty that is the collection of points in your UserControl. When you register it, use the FrameworkPropertyMetadata metadata, and specify the FrameworkPropertyMetadataOptions.AffectsRender in the metadata constructor. Note that this will only work if the entire collection is replaced (if you raise PropertyChanged for the collection, but the collection instance hasn't changed, your paint still won't get called).

If your collection implements INotifyCollectionChanged, then you can wire up a collection changed event handler that invalidates the visual:

public static DependencyProperty PointsProperty = DependencyProperty.Register(
    "Points",
    typeof(IEnumerable<Point>),
    typeof(UC1),
    new FrameworkPropertyMetadata(null, 
        FrameworkPropertyMetadataOptions.AffectsRender,
        OnPointsChanged));

public IEnumerable<Point> Points
{
    get { return (IEnumerable<Point>)GetValue(PointsProperty); }
    set { SetValue(PointsProperty, value); }
}

private static void OnPointsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    UC1 ctrl = d as UC1;
    if (e.NewValue != null && e.NewValue is INotifyCollectionChanged)
        ((INotifyCollectionChanged)e.NewValue).CollectionChanged += ctrl.PointsChanged;

    if (e.OldValue != null && e.OldValue is INotifyCollectionChanged)
        ((INotifyCollectionChanged)e.OldValue).CollectionChanged -= ctrl.PointsChanged;
}

private void PointsChanged(object sender, NotifyCollectionChangedEventArgs e)
{
    InvalidateVisual();
}


回答2:

EDIT: Thanks @Ray Burns for a rather valid point!

If your list implements the INotifyCollectionChanged interface (e.g. ObservableCollection<Point>, see ObservableCollection@msdn) or the objects implement INotifyPropertyChanged (see INotifyPropertyChanged @msdn) and you are binding the points to the view then it should sort itself out (as long as the binding is correct of course!)

I mention that because you indicated you were using a List which depending on how things are set up may work once but never update.

Can you update the question with sample code, e.g. the class/WPF markup/view model code etc to get more guidance. There is a lot of room to move in this space...

PK :-)