0

I want to cache public properties that depend on one or more DependencyProperty values, such that they only get recalculated when the DependencyProperty changes. My class inherits from FrameworkElement and INotifyPropertyChanged. I've followed some portions the answer here Implementing INotifyPropertyChanged. Simplified class:

public class ElementBase : FrameworkElement, INotifyPropertyChanged {
    static ElementBase() {
        WidthProperty.OverrideMetadata(typeof(ElementBase), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCalculatedValueChanged)));
        HeightProperty.OverrideMetadata(typeof(ElementBase), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnCalculatedValueChanged)));
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged([CallerMemberName] string propertyName = null) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));

    private static void OnCalculatedValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        // how can property's string name be avoided
        switch (e.Property.ToString())  { // force update of non-dependency properties 
            case "Height": // is there a better way to force the recalculations?
                ((ElementBase)d).HalfHeight = 0.0; // set overwrites with calculated value 
                ((ElementBase)d).Center = new Point(0, 0);  // set overwrites with calculated value 
                break;
            case "Width": 
                ((ElementBase)d).HalfWidth = 0.0;  // set overwrites with calculated value 
                ((ElementBase)d).Center = new Point(0, 0);  // set overwrites with calculated value  
                break;
            default: break;
        }
    }

    // Caching of the public properties.  
    private double halfWidth; // cached calculated half width
    public double HalfWidth { get => halfWidth; set { halfWidth = Width / 2.0; } }

    private double halfHeight; // cached calculated half height
    public double HalfHeight { get => halfHeight; set { halfHeight = Height / 2.0; } }

    private Point center; // cached calculated center point
    public Point Center { get => center; set { center = new Point(HalfWidth, HalfHeight); } }
}

What I didn't see is:

  1. How to attach to PropertyChangedEventHandler events, so related non DependencyProperty properties to be recalculated?
  2. How to avoid use of DependencyProperty string names?
  3. PropertyChangedCallback entries for OverRideMetadata of the DependencyProperty work, but is that the best way?
codebender
  • 469
  • 1
  • 6
  • 23
  • "What I didn't see is how to attach changes to cause related non DependencyProperty properties to be recalculated." Unless they get some flavor of change notificaiton, the only way to be aware of changes is polling. The whole ViewModel layer of MVVM exists because you do not always control the model and often have to wrap it in something you do control. Note that DependancyProperties are primarily tehre for GUI elements. For code behind you should generally use INotifyPropertyChanged. It is simpler. – Christopher Nov 14 '18 at 01:23
  • 1
    @codebender: PropertyChangedCallbacks are the best way to subscribe to dependency property changes. I don't think I understand what your actual issue is here. Where do you want events to be attached? – mm8 Nov 14 '18 at 10:45

1 Answers1

1

I think what you might be looking for is CoerceValue which was intended just for this. Look it up here.

Robert
  • 2,407
  • 1
  • 24
  • 35