views:

416

answers:

3

Is there a way to know the first time a Dependency Property is accessed through XAML binding so I can actually "render" the value of the property when needed?

I have an object (class derived from Control) that has several PointCollection Dependency Properties that may contain 100's or 1000's of points. Each property may arrange the points differently for use in different types shapes (Polyline, Polygon, etc - its more complicated then this, but you get the idea). Via a Template different XAML objects use TemplateBinding to access these properties. Since my object uses a Template I never know what XAML shapes may be in use for my object - so I never know what Properties they may or may not bind to. I'd like to only fill-in these PointCollections when they are actually needed.

Normally in .NET I'd but some logic in the Property's getter, but these are bypassed by XAML data binding.

I need a WPF AND Silverlight compatible solution.

I'd love a solution that avoids any additional complexities for the users of my object.


Update

One why that I've found to do this is using Value Converters. In my situation I had multiple point collections. There was a main dep. property that contained the usual shape of the data. Two alternate shapes were needed for re-skinning.

At first I had 3 dep. props. But, I could have just had one property (the usual shape) and used a value converted to transform the points into my other 2 desired shapes. Doing this I only make the one set of points in the control. The expense of transforming points to the secondary shapes is only incurred when used. Now my main control doesn't need to anticipate how data needs to look for every possible template thrown at the control - now its the template designers problem.

A: 

Hey Aardvark.

If I paraphrase your question to

How do I get notified when dependency property is changed?

will this be correct? I draw this from your phrase "Normally in .NET I'd but some logic in the Property's getter, but these are bypassed by XAML data binding".

If I'm correct, then you can register your own property changed callback. It's always called. Doesn't matter who caused the change binding, style or trigger. The following code snippet is taken from MSDN Article "Dependency Property Callbacks and Validation":

public static readonly DependencyProperty CurrentReadingProperty = 

    DependencyProperty.Register(
        "CurrentReading",
        typeof(double),
        typeof(Gauge),
        new FrameworkPropertyMetadata(
            Double.NaN,
            FrameworkPropertyMetadataOptions.AffectsMeasure,
            new PropertyChangedCallback(OnCurrentReadingChanged),
            new CoerceValueCallback(CoerceCurrentReading)
        ),
        new ValidateValueCallback(IsValidReading)
    );
    public double CurrentReading
    {
      get { return (double)GetValue(CurrentReadingProperty); }
      set { SetValue(CurrentReadingProperty, value); }
    }

Your takeaway here is OnCurrentReadingChanged() method. Hope this helps :).

Anvaka
I'm pretty sure the question is about how to "lazy load" the value of a dependency property first time it is accessedin an object and not how to get notified when the dependency property is changed.
Martin Liversage
What Martin said...
Aardvark
+2  A: 

You don't necessarily have to use dependency properties to enable data-binding. However, you then have to implement INotifyPropertyChanged if changes at the source should be propagated to the target of the binding. A "normal" .NET property is easy to lazy load perhaps like this:

PointCollection points

public PointCollection Points {
  get {
    return this.points ?? (this.points = CreatePoints());
  }
}

PointCollection CreatePoints() {
  // ...
}

I'm not sure how you can fit INotifyPropertyChanged into your control, but it sounds a bit strange that your control supplies data to other parts of the system. Perhaps you need to create a view-model containing the data that you then can let your control data-bind to.

Martin Liversage
I'm still trying to figure out why this solution isn't working in my situation. Maybe this doesn't work when binding in a template?
Aardvark
A: 

Hi Aardvark. Did you ever figure this out? I'm in the same situation currently.

Thanks, Durkin.

durkin
I'll update my question with one way I found to work around this. By the way welcome to SO - in the future (and when you have rep to do this) this kind of question ("did you figure this out?") should have been a comment on the question - not an "answer".
Aardvark