【问题标题】:Dependency Property Inheritance依赖属性继承
【发布时间】:2013-04-01 20:21:42
【问题描述】:

我需要我的控件从 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 更改 OnIsEnabledPropertyCoerce 在每个 PipeContorl 中调用, OnIsEnabledPropertyChanged 永远不会被调用, OnIsEnabledProerty Coerce 中的 ValueSource 为“默认”(显示 Coerce 始终获取默认的 false 值)。

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

【问题讨论】:

    标签: wpf inheritance custom-controls dependency-properties


    【解决方案1】:

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

    希望这会有所帮助,并且非常欢迎任何有关该解决方案的 cmets。

    【讨论】:

    • 我稍后会检查这个,10x
    • 很好,但还有一件事,我仍然希望在 PipeControl 的 IsEnabledProperty 更改时收到通知,并从那里强制转换值。如果没有像 IsMyPipe 的回调通知这样的不同通知,我可以这样做吗
    【解决方案2】:

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

    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 的元数据做任何其他事情。

    【讨论】:

    • 您说您不应该提供默认的本地值,但是您将false 指定为new UIPropertyMetadata(false, ... ) 中的默认值。我是不是不理解过度或误解了你的话?
    • 我不确定,这么久之后很难记住......在这个依赖对象中设置的默认值将是它使用的那个是合乎逻辑的。并将覆盖默认值。也许我不是你应该注意不要使用继承的值。我相信这是“真实的”
    猜你喜欢
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 2018-06-07
    相关资源
    最近更新 更多