依赖属性继承

时间:2013-04-10 06:13:29

标签: wpf inheritance custom-controls dependency-properties

我需要我的控件从Grid类型的祖先继承UIElement.IsEnabledProperty(可选Window或任何其他我可以用我的网格包裹的元素)

CS:下面我覆盖了UIElement.IsEnabledProperty的元数据,并使用Change和Coerce委托进行设置。

    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> 

每次IsMyCondition更改OnIsEnabledPropertyCoerce在每个PipeContorl中调用, 永远不会调用OnIsEnabledPropertyChanged, OnIsEnabledProerty中的ValueSource Coerce为“Default”(显示Coerce始终获取默认的false值)。

我必须以我需要使用继承的方式错过某些东西, 我希望价值来源是“继承” 和要调用的OnIsEnabledPropertyChanged。

2 个答案:

答案 0 :(得分:4)

UIElement有一个虚拟属性IsEnabledCore,它应该(?)用于强制IsEnabled属性。例如,这就是Button或MenuItem强制IsEnabled属性的方式,具体取决于它们的CanExecute属性。 在自定义控件中,您可以将属性覆盖为:

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

重要的是当IsEnabled所依赖的任何属性(例如IsMyPipe)发生变化时调用CoerceValue。

因此自定义控件实现将是:

    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 );
    }

希望这会有所帮助,对此解决方案的任何评论都非常受欢迎。

答案 1 :(得分:2)

上面有Adnan的答案,答案是:

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

我写了一个完整的答案。

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将值返回给Callback,因此强制在那里发生, 然后是CallBack。

仅供参考,设置本地默认值似乎会覆盖继承,因此如果覆盖一个Inherited 属性的元数据确实给出了一个默认的本地值,如下所示:

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

另外,如果你只需要添加强制逻辑,你可以覆盖IsEnabledCore, 并且对IsEnabledProperty的元数据不做任何其他操作。