我刚刚搜索了一种在父控件具有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;
}
现在,您可以在子项上手动设置IsEnabled
属性,该属性将覆盖父值。
这种方法有什么缺点吗?
答案 0 :(得分:4)
这适用于我使用控件的情况多次使用稍作修改。
放置此处以帮助处于类似情况的未来网络搜索者:
代码:
确保使用控件的类型名称查找并替换[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;
}
答案 1 :(得分:0)
缺点是至少,你打破了基本概念,并且IsEnabled不用于预期的范围。这种解决方法还使维护变得更复杂(开发人员必须首先理解,为什么它的工作方式不同)。
正如评论中所建议的,我会说,重新设计这个窗口会有所帮助。特别是,如果我只想禁止表单中的编辑(数据修改),我会使用其他属性,如IsReadOnly。
答案 2 :(得分:0)
另一种选择是覆盖FrameworkPropertyMetadataOptions以删除Inherits属性。我在FontSize上遇到了类似的问题,这很有效:
FontSizeProperty.OverrideMetadata(
typeof(YourControl),
new FrameworkPropertyMetadata(8.0,
FrameworkPropertyMetadataOptions.None, changed));
答案 3 :(得分:0)
问题中提出的解决方案在某些情况下可能没问题。但是,更改应用程序中所有 UIElement
的默认框架行为可能会引入兼容性问题,并且将来可能难以了解行为发生更改的位置/原因。
另一种方法是保留框架的默认行为,并仅在需要时在特定位置手动覆盖该行为。实现此目的的一种方法是创建一个简单的包装元素,该元素会中断 IsEnabled
与父元素的继承链。
框架的默认强制回调检查父 IsEnabled
值并继承它。这个控件设置了一个新的强制回调,直接返回值而不检查继承。
public class ResetIsEnabled : ContentControl
{
static ResetIsEnabled()
{
IsEnabledProperty.OverrideMetadata(
typeof(ResetIsEnabled),
new UIPropertyMetadata(
defaultValue: true,
propertyChangedCallback: (_, __) => { },
coerceValueCallback: (_, x) => x));
}
}
可以这样使用
<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>