WPF从Parent中覆盖IsEnabled

Lio*_*nAM 16 c# wpf dependency-properties

我刚刚搜索了一种在父控件启用时启用子控件的方法IsEnabled = false.到目前为止我发现的所有答案都说不可能 - 必须启用父级并禁用子控件,除了应该仍然启用的子控件.

但是,通过覆盖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;
}
Run Code Online (Sandbox Code Playgroud)

现在,您可以IsEnabled在子项上手动设置属性,该属性将覆盖父值.

这种方法有什么缺点吗?

mar*_*iro 6

问题中提出的解决方案在某些情况下可能没问题。但是,更改应用程序中所有对象的默认框架行为UIElement可能会引入兼容性问题,并且将来可能很难理解行为更改的位置/原因。

另一种方法是保留框架的默认行为,并且仅在需要时在特定位置手动覆盖该行为。实现此目的的一种方法是创建一个简单的包装元素,以打破IsEnabled父元素的继承链。

框架的默认强制回调检查父IsEnabled值并继承它。该控件设置了一个新的强制回调,它只直接返回值而不检查继承。

public class ResetIsEnabled : ContentControl
{
    static ResetIsEnabled()
    {
        IsEnabledProperty.OverrideMetadata(
            typeof(ResetIsEnabled),
            new UIPropertyMetadata(
                defaultValue: true,
                propertyChangedCallback: (_, __) => { },
                coerceValueCallback: (_, x) => x));
    }
}
Run Code Online (Sandbox Code Playgroud)

可以这样使用

<ParentControl IsEnabled="False">
  <!-- Any elements here will have IsEnabled set to false, inherited from the parent -->
  <ResetIsEnabled>
    <!-- Any child elements here will have IsEnabled set to true (the default value) -->
  </ResetIsEnabled>
</ParentControl>
Run Code Online (Sandbox Code Playgroud)


小智 0

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

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