如果我有一个包含控件A
的控件B
,则会继承属性Prop
。这意味着,如果B.Prop
未明确设置,A.Prop
将自动获取B.Prop
的值。据我所知,IsEnabled
就是这样的财产。
现在我的情况是我明确地设置了B.IsEnabled
的值,但它仍被A.IsEnabled
的值覆盖。 为什么会这样,我该如何纠正?
在这种情况下,A
是一个StackPanel,B
是一个TextBox:
<StackPanel>
<StackPanel.Style>
<Style TargetType="StackPanel">
<Setter Property="IsEnabled" Value="True"/>
<Style.Triggers>
<DataTrigger Binding="{Binding InDisableMode}" Value="True">
<Setter Property="IsEnabled" Value="False"/>
</DataTrigger>
</Style.Triggers>
</Style>
</StackPanel.Style>
<TextBox Text="some text">
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="IsEnabled" Value="False"/>
<Style.Triggers>
<DataTrigger Binding="{Binding InDisableMode}" Value="True">
<Setter Property="IsEnabled" Value="True"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
</StackPanel>
上面的XAML代码段将其DataContext设置为我的ViewModel。 ViewModel包含属性InDisableMode
,即bool
。当它为false
时,一切都符合预期:启用了StackPanel并禁用了TextBox。
但是当InDisableMode
为true
时,StackPanel和TextBox都被禁用,尽管两个触发器都应该触发!
注意:我知道我可以在两个控件中将IsEnabled
数据绑定到InDisableMode
(在TextBox中直接使用补充转换器在StackPanel中)。我还没有尝试过,因为我想用触发器来做这件事。
编辑:
禁用StackPanel的目的是轻松禁用所有子代(除了我想要启用的TextBox)。如何在不改变父子关系或创建新控件的情况下解决此任务的任何其他想法?目前,我看到的唯一方法是逐个禁用除TextBox之外的所有子项......
答案 0 :(得分:1)
如果禁用控件,则会禁用其子控件。由于StackPanel
不是交互式的,因此除了禁用其交互式子项外,没有理由禁用它。
如果要在禁用其父B的情况下启用控件A,则无法执行此操作。如果要在禁用B时启用A,则B不能是父级。
要获得变通方法,您可以将它们放在Grid
中,最后定义TextBox
,将TextBox
叠加在StackPanel
之上。然后它将在StackPanel
区域内,但它不会成为StackPanel
的孩子。
答案 1 :(得分:1)
这是因为UIElement.IsEnabled
属性通过从其父级继承值来使用值强制。这是通过使用CoerceValueCallback
来实现的。价值强制在Dependency Property Setting Precedence List.
因此,要覆盖此行为,我们有两个选项。首先,使用AddOwner()
将我们的类型注册为IsEnabled
属性的新所有者。其次,使用OverrideMetadata()
覆盖元数据。仅当您直接从UIElement
继承时,第二种方法才有效。
因此,假设我们希望我们的Button
行为不同,我们应该创建一个新的Button
,如下所示:
public class CButton : Button
{
public static readonly DependencyProperty IsEnabled;
static CButton()
{
IsEnabled = UIElement.IsEnabledProperty.AddOwner(typeof(CButton),
new FrameworkPropertyMetadata(true, FrameworkPropertyMetadataOptions.None,
UIElement.IsEnabledProperty.DefaultMetadata.PropertyChangedCallback,
new CoerceValueCallback(IsEnabledCoerceCallback)));
}
private static object IsEnabledCoerceCallback(DependencyObject d, object baseValue)
{
return (bool) baseValue;
}
}
在这里,我们将从IsEnabledCoerceCallback
返回指定值。在返回之前,您还可以介绍行为:如果用户没有为IsEnabled
提供任何值,则使用来自父项的继承值,否则使用CButton.IsEnabled
用户指定的值。
在旁注中,尝试设置null
代替new CoerceValueCallback(IsEnabledCoerceCallback)
,看看会发生什么。