wpf ContentPresenter 不会启用/禁用
我已经重写了 ComboBox,以便在组合的末尾添加一个额外的按钮 - 我使用它来帮助导航我的应用程序。
它是一个 MV-VM 应用程序,具有编辑-保存/取消机制,可根据用户是否处于“编辑模式”来禁用或启用控件。 我希望无论视图是启用还是禁用,我的导航按钮始终可用。
为了实现此目的,我将 ToggleButton
和 ContentPresenter
绑定到模型上的 IsEditable
属性。
切换按钮按预期启用和禁用,但组合的文本保持启用状态。
由于文本是由 ContentPresenter
传递的,并且 ContentPresenter
有一个 IsEnabled
属性,我不明白为什么它不会禁用?
有人可以帮忙吗? 谢谢安迪
<Style TargetType="local:EntityCombo">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="FontSize" Value="12" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:EntityCombo" >
<Grid>
<ToggleButton
IsEnabled="{Binding IsEditable}"
Name="ToggleButton"
Template="{DynamicResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<Button Grid.Column="2" Style="{DynamicResource EntitySelectedButton}" Command="{TemplateBinding EntitySelected}" CommandParameter="{TemplateBinding SelectedItem}"></Button>
<ContentPresenter
IsEnabled="{Binding IsEditable}"
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{DynamicResource SelectionBoxItem}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid
Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="1"
BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="DarkGray"/>
</Trigger>
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
I've overridden a ComboBox
in order to add an extra button at the end of the combo - i'm using this to help navigate round my application.
Its a M-V-VM App that has an Edit-Save/Cancel mechanism that disables or enables the controls depending on whether or not the user is in 'edit mode'. I wanted my navigation button to always be available whether the View is enabled or disabled.
To achieve this I'm binding the ToggleButton
and the ContentPresenter
to a IsEditable
property on my Model.
The toggle button enables and disables as expected but the Text of the combo stays enabled.
As the text is delivered by the ContentPresenter
and the ContentPresenter
has an IsEnabled
property I can't understand why it wont disable?
Can anyone assist? Thanks Andy
<Style TargetType="local:EntityCombo">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="MinWidth" Value="120"/>
<Setter Property="MinHeight" Value="20"/>
<Setter Property="FontSize" Value="12" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="local:EntityCombo" >
<Grid>
<ToggleButton
IsEnabled="{Binding IsEditable}"
Name="ToggleButton"
Template="{DynamicResource ComboBoxToggleButton}"
Grid.Column="2"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
ClickMode="Press">
</ToggleButton>
<Button Grid.Column="2" Style="{DynamicResource EntitySelectedButton}" Command="{TemplateBinding EntitySelected}" CommandParameter="{TemplateBinding SelectedItem}"></Button>
<ContentPresenter
IsEnabled="{Binding IsEditable}"
Name="ContentSite"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{DynamicResource SelectionBoxItem}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
Margin="3,3,23,3"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<Popup
Name="Popup"
Placement="Bottom"
IsOpen="{TemplateBinding IsDropDownOpen}"
AllowsTransparency="True"
Focusable="False"
PopupAnimation="Slide">
<Grid
Name="DropDown"
SnapsToDevicePixels="True"
MinWidth="{TemplateBinding ActualWidth}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<Border
x:Name="DropDownBorder"
Background="{StaticResource WindowBackgroundBrush}"
BorderThickness="1"
BorderBrush="{StaticResource SolidBorderBrush}"/>
<ScrollViewer Margin="4,6,4,6" SnapsToDevicePixels="True">
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter TargetName="DropDownBorder" Property="MinHeight" Value="95"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="DarkGray"/>
</Trigger>
<Trigger Property="IsEnabled" Value="true">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger SourceName="Popup" Property="Popup.AllowsTransparency" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
这是一个棘手的问题,但我已经深入 WPF 足够长的时间了,所以非常坚持。 :)
在我上次评论中建议这一点后,我的疯狂驱使我测试它,这确实是问题所在:
模板基于
ComboBox.IsEnabled
设置ComboBox.Foreground
,但是你想要基于DataContext.IsEnabled
设置内容样式,因此您需要设置ContentPresenter
本身的样式。 但您无法设置ContentPresenter
的样式,因为它继承自FrameworkElement
,而不是 Control。 但是您可以将ContentPresenter
替换为ContentControl
,并使用适合您的禁用外观的触发器来设置其样式。This is a tricky one, but I've been knee-deep in WPF long enough to be very persistent. :)
After suggesting this in my last comment my insanity drove me to test it out and it is indeed the problem:
The template sets
ComboBox.Foreground
based onComboBox.IsEnabled
, but you want to style the content based onDataContext.IsEnabled
, so you would need to style theContentPresenter
itself. But you cannot styleContentPresenter
because it inherits fromFrameworkElement
, not Control. But you can replace theContentPresenter
with aContentControl
and style it with the appropriate triggers for your disabled appearance.