2

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

CS:下面我覆盖 UIElement.IsEnabledProperty 的元数据并使用 Change 和 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> 

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

我必须以我需要使用 Inheritance 的方式错过一些东西,我希望值源是“Inherited”并且 OnIsEnabledPropertyChanged 被调用。

4

2 回答 2

6

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

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

希望这会有所帮助,并且非常欢迎对解决方案提出任何意见。

于 2013-04-10T15:18:23.347 回答
2

上面有阿德南的回答,这个回答:

如何向现有的依赖属性回调添加逻辑?

我包含了一个完整的答案。

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 。

仅供参考,设置本地默认值似乎会覆盖继承,因此如果覆盖继承属性的元数据,请务必提供默认本地值,如下所示:

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

此外,如果您只需要添加强制逻辑,您可以覆盖 IsEnabledCore ,而不用 IsEnabledProperty 的元数据做任何其他事情。

于 2013-04-10T18:25:49.390 回答