tags:

views:

37

answers:

2

I'm currently working on a problem with a custom UserControl, I want to expose certain properties of child controls as properties on the parent, I also want data binding to be possible. To make all this happen, I created Attached DependencyProperties on the parent:

    //TimeframeSelector.xaml.cs
    public static readonly DependencyProperty EnableEndFilterProperty =
        DependencyProperty.RegisterAttached(
        "EnableEndFilter", 
        typeof(bool), 
        typeof(TimeframeSelector), 
        new FrameworkPropertyMetadata(false, 
            FrameworkPropertyMetadataOptions.Inherits |
            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

    public static bool GetEnableEndFilter(DependencyObject obj)
    {
        return (bool)obj.GetValue(EnableEndFilterProperty);
    }

    public static void SetEnableEndFilter(DependencyObject obj, bool value)
    {
        obj.SetValue(EnableEndFilterProperty, value);
    }

    public bool EnableEndFilter
    {
        get { return (bool)GetValue(EnableEndFilterProperty); }
        set { SetValue(EnableEndFilterProperty, value); }
    } 

These Attached DPs are used in the xaml of that control:

//TimeframeSelector.xaml
<UserControl x:Class="EveTrader.Wpf.Controls.TimeframeSelector"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:ctrl="clr-namespace:EveTrader.Wpf.Controls"
             mc:Ignorable="d">

            <CheckBox IsChecked="{Binding 
             Path=(ctrl:TimeframeSelector.EnableEndFilter), 
             RelativeSource={RelativeSource Self}, Mode=TwoWay}"/>
</UserControl>

Now, the control is used in another control:

<ctrl:TimeframeSelector EnableEndFilter="{Binding ApplyEndFilter}" [...]/>

The ViewModel for this View supplies a value from user settings, which gets displayed correctly in the control, but any changes made in the control don't go back to the ViewModel.

So the question is: How do I get the control to work both ways? Something already has to work, otherwise the control would be empty (as it was before I added the Inherits flag to the DP).

A: 

Try changing your UserControl's XAML to:

<UserControl x:Name="uc" ...>
    <CheckBox IsChecked="{Binding ElementName=uc, Path=(ctrl:TimeFrameSelector.EnableEndFilter), Mode=TwoWay}"/>
</UserControl>
karmicpuppet
+1  A: 

Inherited values aren't the same as Bindings. When you set a value for a property that was inherited from a parent (as your TwoWay Binding is doing when it writes to the source) it overrides the value that was inherited. Inheritance is 10th out of the 11 possible value sources.

In this case using an attached property with inheritance isn't gaining you anything so you could simplify your XAML a little by just using a standard DP instead.

public static readonly DependencyProperty EnableEndFilterProperty =
    DependencyProperty.Register(
    "EnableEndFilter", 
    typeof(bool), 
    typeof(TimeframeSelector), 
    new FrameworkPropertyMetadata(false, 
        FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

You can use either an ElementName or RelativeSource Binding to use the parent UserControl directly as a Binding Source which will allow the Binding to work in both directions like you want.

<CheckBox IsChecked="{Binding Path=EnableEndFilter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ctrl:TimeFrameSelector}}}"/>

IsChecked is TwoWayByDefault so you can omit that from the Binding as well.

John Bowen
that worked out, thanks.
Femaref