views:

28

answers:

2

We have a custom panel class that animates its children via an internal DoubleAnimation object. However, we want to expose the animation's Duration dependency property as a public property of our panel so the user can change it in their XAML when using our panel. But we don't want to expose any other part of the animation object, just the duration.

The first thing that keeps getting suggested to me is to use the PropertyChanged notification, but that would only work for the setter, not the getter. We also can't simply create a .NET property since XAML bypasses the .NET property altogether.

A co-worker of mine had a clever idea... use two-way data binding between the outer property and the internal object's property, which actually seems like a pretty neat solution. However, data binding aside, is there another/a better way to do this... exposing an internal object's dependency property via it's containing object's public interface?

Updated:

Looks like two-way DataBinding was the way to go. (Thanks @Jeff!) To that end, here's what I found to be the best way to set up the outer DP so it's a perfect match--metadata, defaults and all--for the inner object's DP! Then use Jeff's binding trick and you're done!

public Duration Duration {
    get { return (Duration)GetValue(DurationProperty); }
    set { SetValue(DurationProperty, value); }
}

public static readonly DependencyProperty DurationProperty = DoubleAnimation.DurationProperty.AddOwner(
    typeof(SlideContentPanel));
A: 

Something strikes me as odd about your "problem", so here are some thoughts that may clear things up.

A dependency property can be both read and set by your code. Why not just use that instead of this internal storage?

If you want to use the internal storage value for performance reasons, use the property changed notification that you already said would work. When the property changes, update your internal value. When YOU change the property internally, call the dependency property setter at appropriate intervals to update everyone else (ignoring the property change event you would receive from that).

Maybe your situation requires something other than this, but the second option ought to be as complicated as something like this should get.

John Fisher
As you stated above, property changed only handles the setter, thus making *you* responsible in keeping the two in sync if you change the value on the internal object. That's a lot of extra work if there are a lot of touch-points where it can be changed. As for your comment of using a d-prop instead of the internal object I think you've missed the point. That internal object is what makes this panel work! Look at it another way... all we're trying to do is expose a property of that internal animation object so a user may customize that value in XAML. Make sense?
MarqueIV
I updated the question and explanation to be more clear.
MarqueIV
It sounds like you went with a variation of the first option. I'm glad you figured out how to do that simply.
John Fisher
+2  A: 

Try this... Create equivilant dependency properties on the outside objects, then bind from the inside object to the outside object. This will work in both directions.

Binding durationBinding = new Binding(){
    Source = _doubleAnimation,
    Path   = new PropertyPath("Duration"),
    Mode   = BindingMode.TwoWay
};
BindingOperations.SetBinding(this, SlideContentPanel.DurationProperty, durationBinding);

For the xaml lovers

<UserControl x:Class=”Controls.DataGrid.DataGrid2"
Name="rootControl">

<Grid>       
    <xcdg:DataGridControl Grid.Row="0"
       Name="internalDataGrid" 
       SelectedItem="{Binding ElementName=rootControl, Path=SelectedItem}"
       EditTriggers="{Binding ElementName=rootControl, Path=EditTriggers}"
 />
jeff
Nice! (The code-only version.) This looks just like what I need. And glad to see I was wrong about needing the ElementName. I thought that was kind of odd!
MarqueIV
See the 'Update!' in my revised question for another cool tip!
MarqueIV