tags:

views:

19

answers:

2

I'm having a problem with a piece of code that's starting to drive me out of my mind. I have a base class in WPF with a declared DependencyProperty:

public partial class AudioTimeControlBase : UserControl
{
    public static readonly DependencyProperty PlaybackPositionProperty = DependencyProperty.RegisterAttached(
        "PlaybackPosition", typeof(TimeSpan), typeof(AudioTimeControlBase),
        new FrameworkPropertyMetadata(TimeSpan.Zero, 
            FrameworkPropertyMetadataOptions.Inherits | 
            FrameworkPropertyMetadataOptions.AffectsRender |
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
            OnPlaybackPositionChanged, CoercePlaybackPosition));


    public TimeSpan PlaybackPosition
    {
        get { return (TimeSpan)this.GetValue(PlaybackPositionProperty); }
        set { this.SetValue(PlaybackPositionProperty, value); }
    }

    private static void OnPlaybackPositionChanged(object sender, DependencyPropertyChangedEventArgs e)
    {
        AudioTimeControlBase control = sender as AudioTimeControlBase;
        if (control != null)
            control.OnPlaybackPositionChanged(e);
    }

    protected virtual void OnPlaybackPositionChanged(DependencyPropertyChangedEventArgs e)
    {
    }

    private static object CoercePlaybackPosition(DependencyObject d, object value)
    {
        TimeSpan t = (TimeSpan)value;
        if(t < TimeSpan.Zero)
            return TimeSpan.Zero;
        return t;
    }

}

Then a derived control:

public partial class WaveViewerControl : AudioTimeControlBase
{
    public WaveViewerControl()
    {
        InitializeComponent();
    }

    void playbackControl_PositionChanged(object sender, EventArgs e)
    {
        PlaybackPosition = ConvertFromPosition(playbackControl.Position);
    }
 }

I've taken out a fair amount of stuff but I really think I've isolated the offending bits to this. The problem is that when playbackControl_PositionChanged happens (as a result of user action), it breaks the (previously working) binding to the PlaybackPositionProperty and the control receives no subsequent updates. If anyone has any thoughts or leads at all I would be eternally grateful. Thanks!

UPDATE: I realize I left some potentially critical information out of this - this control is not being directly represented in my XMAL but is being programmatically added to a parent control. However, per the "Inhert" option, the bindings of that parent are being correctly inherited. It's not until the SetValue call that they are apparently overridden. Does this suggest that two-way binding is not supported by inherited properties?

A: 

According to WPF Unleashed, setting a value directly removes the binding. (page 261) so what you have described is by design.

Aliostad
Thanks, but I'm not sure I'm following...why would passing a struct here break the binding or callback?
Jeff
Sorry ignore my previous comment.
Aliostad
A: 

If you call SetValue on a property that is set to a binding expression that is not two-way or one-way to source, then it will replace the binding expression with the new value. You have PlaybackPositionProperty set to bind two-way by default, but the Binding could still be manually set to Mode=OneWay.

Check the XAML where WaveViewerControl is being used, and see whether the binding on PlaybackPosition has Mode=OneWay. You can also check the binding at run-time by calling BindingOperations.GetBinding(this, PlaybackPositionProperty).Mode in your event handler.


Based on your update, yes, that is correct behavior. You cannot update a two-way binding expression that is set by property value inheritance. You are setting a local value, which will override the inherited value. See Dependency Property Value Precedence.

Quartermeister
The binding mode is not set in the XAML but I'll check out the second suggestion, thanks.
Jeff
I think I understand, thank you!
Jeff