WPF 从父级覆盖 IsEnabled

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/22248943/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:08:59  来源:igfitidea点击:

WPF override IsEnabled from Parent

c#wpfdependency-properties

提问by LionAM

I just searched for a way to enable a child control while the parent control has IsEnabled = false. All answers that I have found up to now say that it is not possible - one has to enable the parent and disable the child controls except the ones that should still be enabled.

我只是寻找一种方法来启用子控件而父控件具有IsEnabled = false. 到目前为止,我找到的所有答案都说这是不可能的 - 必须启用父控件并禁用子控件,但仍应启用的控件除外。

However, by overriding the Metadata for the IsEnabledProperty in the App.xaml.cs file, I was able to change this default behavior:

但是,通过覆盖 App.xaml.cs 文件中 IsEnabledProperty 的元数据,我能够更改此默认行为:

protected override void OnStartup(StartupEventArgs e)
{
    UIElement.IsEnabledProperty.OverrideMetadata(typeof(FrameworkElement),
             new UIPropertyMetadata(true,IsEnabledChanged, CoerceIsEnabled));
}

private void IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var childrenCount = VisualTreeHelper.GetChildrenCount(d);
    for (int i = 0; i < childrenCount; ++i)
    {
        var child = VisualTreeHelper.GetChild(d, i);
        child.CoerceValue(UIElement.IsEnabledProperty);
    }
}
private object CoerceIsEnabled(DependencyObject d, object basevalue)
{
    var parent = VisualTreeHelper.GetParent(d) as FrameworkElement;
    if (parent != null && parent.IsEnabled == false)
    {
        if (d.ReadLocalValue(UIElement.IsEnabledProperty) == DependencyProperty.UnsetValue)
        {
            return false;
        }
    }
    return basevalue;
}

Now you can manually set the IsEnabledproperty on a child, which overrides the parent value.

现在您可以手动设置子项的IsEnabled属性,该属性会覆盖父项值。

Are there any drawbacks of this approach?

这种方法有什么缺点吗?

回答by user1568891

This worked for my situation on a control used several times with some slight modifications.

这适用于我多次使用的控件的情况,并稍作修改。

Placing here to help any future web searchers in a similar situation:

放在这里是为了帮助未来遇到类似情况的网络搜索者:

  • placed it in a static constructor instead of an event, otherwise it tried to set it multiple times and threw a "PropertyMetadata is already registered for type '{type}'." exception.
  • Changed the type to match the control
  • 将其放置在静态构造函数而不是事件中,否则它尝试多次设置它并抛出“PropertyMetadata 已为类型 '{type}' 注册”。例外。
  • 更改了类型以匹配控件

Code:

代码:

Make sure to find and replace [CustomControl]with the type name of your control.

确保找到并替换[CustomControl]为您的控件的类型名称。

static [CustomControl]()
{
    UIElement.IsEnabledProperty.OverrideMetadata(typeof([CustomControl]), new UIPropertyMetadata(true, [CustomControl]_IsEnabledChanged, CoerceIsEnabled));
}

private static void [CustomControl]_IsEnabledChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var childrenCount = VisualTreeHelper.GetChildrenCount(d);
    for (int i = 0; i < childrenCount; ++i)
    {
        var child = VisualTreeHelper.GetChild(d, i);
        child.CoerceValue(UIElement.IsEnabledProperty);
    }
}

private static object CoerceIsEnabled(DependencyObject d, object basevalue)
{
    var parent = VisualTreeHelper.GetParent(d) as FrameworkElement;
    if (parent != null && parent.IsEnabled == false)
    {
        if (d.ReadLocalValue(UIElement.IsEnabledProperty) == DependencyProperty.UnsetValue)
        {
            return false;
        }
    }
    return basevalue;
}

回答by Eric

Another option is to override the FrameworkPropertyMetadataOptions to remove the Inherits property. I had a similar problem with the FontSize and this worked well:

另一种选择是覆盖 FrameworkPropertyMetadataOptions 以删除 Inherits 属性。我在 FontSize 上遇到了类似的问题,并且效果很好:

FontSizeProperty.OverrideMetadata(
   typeof(YourControl), 
   new FrameworkPropertyMetadata(8.0, 
      FrameworkPropertyMetadataOptions.None, changed));

回答by eldor

The drawback is at least, that you break the basic concept, and the IsEnabled is not used for the intended scope. This workaround also makes maintenance a bit more complex (the developer has to understand first, why it works differently).

缺点至少是,您打破了基本概念,并且 IsEnabled 未用于预期范围。这种变通方法也使维护变得更加复杂(开发人员必须首先了解为什么它的工作方式不同)。

As it is suggested in comments, I would say, that a redesign of this window would help. Especially, if I would like to forbid only the editing (data modification) in the form, I would use other properties like IsReadOnly.

正如评论中所建议的那样,我想说,重新设计这个窗口会有所帮助。特别是,如果我只想禁止表单中的编辑(数据修改),我会使用其他属性,如 IsReadOnly。