简体   繁体   中英

Dependency Property Inheritance

i need my control to inherit the UIElement.IsEnabledProperty from an Ancestor of type Grid (Optionally Window or any other element i could wrap my grid with )

CS : below i override the meta data of UIElement.IsEnabledProperty and set it with Change and Coerce delegates .

    static PipeControl()
    {
        PipeControl.IsEnabledProperty.OverrideMetadata(typeof(PipeControl), new FrameworkPropertyMetadata(false, OnIsEnabledPropertyChanged, OnIsEnabledPropertyCoerce));
    }

    private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var isEnabled = (bool)e.NewValue;
    }

    private static object OnIsEnabledPropertyCoerce(DependencyObject d, object baseValue)
    {
        var valueSource = DependencyPropertyHelper.GetValueSource(d, PipeControl.IsEnabledProperty);

        var pipeContorl = d as PipeControl;
        if (pipeContorl == null) return baseValue;

        return (bool)baseValue && pipeContorl.IsMyPipe;
    }

XAML :

    <Grid IsEnabled="{Binding IsMyCondition , Mode=OneWay}">        
         <game:PipeControl Grid.Row="2"  />            
         <game:PipeControl  Grid.Row="2" Grid.Column="1" />
    </Grid> 

each time IsMyCondition changes OnIsEnabledPropertyCoerce is called in each PipeContorl , OnIsEnabledPropertyChanged is never called , the ValueSource in OnIsEnabledProerty Coerce is "Default" (show the Coerce always gets the default false value).

i must of missed something in the manner in which i need to use Inheritance , i would expect the value source the be "Inherited" and the OnIsEnabledPropertyChanged to be called.

UIElement has a virtual property IsEnabledCore which should(?) be used to coerce IsEnabled property. This is how, for example, Button or MenuItem coerce IsEnabled property depending on their CanExecute properties. In your custom control, you can override the property as:

    protected override bool IsEnabledCore
    {
        get
        {
            return ( base.IsEnabledCore && IsMyPipe );
        }
    }

The important thing is to call CoerceValue when any of the properties ( ex. IsMyPipe) on which IsEnabled depends changes.

So the custom control implementation would be:

    static PipeControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata( typeof( PipeControl ), new FrameworkPropertyMetadata( typeof( PipeControl ) ) );
    }

    public bool IsMyPipe
    {
        get { return ( bool )GetValue( IsMyPipeProperty ); }
        set { SetValue( IsMyPipeProperty, value ); }
    }

    public static readonly DependencyProperty IsMyPipeProperty =
            DependencyProperty.Register(
                    "IsMyPipe",
                    typeof( bool ),
                    typeof( UIElement ),
                    new PropertyMetadata(
                            true,
                            new PropertyChangedCallback( OnIsMyPipeChanged ) ) );

    private static void OnIsMyPipeChanged( DependencyObject d, DependencyPropertyChangedEventArgs e )
    {
        d.CoerceValue( UIElement.IsEnabledProperty );
    }

Hope this helps, and any comments on the solution are more than welcome.

with Adnan's answer above , and this answer :

How can I add logic to an existing dependency-property callback?

I comprised a full answer .

CS :

    static PipeControl()
    {
        PipeControl.IsEnabledProperty.OverrideMetadata(typeof(PipeControl), new UIPropertyMetadata(new PropertyChangedCallback(OnIsEnabledPropertyChanged)));
    }



    private static void OnIsEnabledPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {           
        var isEnabled = (bool)e.NewValue;
    }


    protected override bool IsEnabledCore
    {
        get
        {
            return (base.IsEnabledCore && IsMyPipe);
        }
    }

IsEnabledCore returns the value to the Callback , so the Coercion happens there , and then the CallBack .

FYI , setting a local default value seems to override the inherited , so if overriding an Inherited Property's Metadata do nut give a default local value , like so :

  PipeControl.IsEnabledProperty.OverrideMetadata(typeof(PipeControl), new UIPropertyMetadata(false,new PropertyChangedCallback(OnIsEnabledPropertyChanged)));   

in addition , if you only need to add coercion logic you can just override IsEnabledCore , and do nothing else with the Metadata of IsEnabledProperty .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM