我有一个关于如何优雅地覆盖控件可视树内的任意元素的问题。我也试图用几种不同的方式解决它,但我遇到了几个问题。通常当我尝试三条不同的路径并且每一路都失败时,我会下楼去喝咖啡,并问一个比我更聪明的人。我在这里。
具体细节:
我想要压缩组合框的样式,这样它就不会引起对自身的注意。我希望它类似于Windows.Forms.ComboBox的FlatStyle我希望它在Windows 7和XP上看起来一样。
主要是,我想改变ComboBox的ToggleButton的外观。
我可以使用Blend并撕掉控件模板的内核并手动更改它们。这对我来说听起来不是很开心。
我尝试使用样式来覆盖ToggleButton的背景,但事实证明整个ComboBox控件实际上是ToggleButton的前端。
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ComboBoxExpiriment2.MainWindow"
x:Name="Window"
xmlns:Microsoft_Windows_Themes="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="204" Height="103">
<Grid x:Name="LayoutRoot">
<ComboBox HorizontalAlignment="Left" Margin="32,26.723,0,0" Width="120" VerticalAlignment="Top" Height="21.277">
<ComboBox.Style>
<Style>
<Setter Property="ToggleButton.Background" Value="Green" />
</Style>
</ComboBox.Style>
</ComboBox>
</Grid>
所以我放弃了并使用Blend将其撕掉。我发现它实际上是一个名为ComboBoxTransparentButtonStyle的Style,目标类型为ToggleButton。该样式设置一个ControlTemplate,它使用一个DockPanel,其右侧设置了“Microsoft_Windows_Themes:ClassicBorderDecorator”类型,而是我们实际想要控制的内容。 (到目前为止你和我在一起吗?)
这是图片:
<Style x:Key="ComboBoxTransparentButtonStyle" TargetType="{x:Type ToggleButton}">
<Setter Property="MinWidth" Value="0"/>
<Setter Property="MinHeight" Value="0"/>
<Setter Property="Width" Value="Auto"/>
<Setter Property="Height" Value="Auto"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="BorderBrush" Value="{x:Static Microsoft_Windows_Themes:ClassicBorderDecorator.ClassicBorderBrush}"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<DockPanel SnapsToDevicePixels="true" Background="{TemplateBinding Background}" LastChildFill="false">
<Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Border" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" DockPanel.Dock="Right" Background="Green" BorderBrush="{TemplateBinding BorderBrush}" BorderStyle="None" BorderThickness="{TemplateBinding BorderThickness}">
<Path Fill="{TemplateBinding Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="{StaticResource DownArrowGeometry}"/>
</Microsoft_Windows_Themes:ClassicBorderDecorator>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="IsChecked" Value="true">
<Setter Property="BorderStyle" TargetName="Border" Value="AltPressed"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}"/>
</Trigger>
</Style.Triggers>
</Style>
精氨酸。 WPF不是爆炸性的吗?
所以我提取了样式ComboBoxTransparentButtonStyle并将其放到另一个项目的application.resources中。问题是我无法将该样式应用于ComboBox,因为我提取的样式的targetType为ToggleButton,因此TargeTypes不匹配。
你会怎么做呢?答案 0 :(得分:3)
没有一个优雅的解决方案。您可以做的最好是覆盖整个ComboBox的样式,以便您可以更改它为ToggleButton设置的样式。
您可以使用Blend来获取样式,但这可能不是最简单的方法。如果安装了Blend,请转到“[程序文件或安装Blend的位置] \ SystemThemes \ WPF \ areo.normalcolor.xaml”。
答案 1 :(得分:2)
嗨,这种风格满足您的需求,随时可以根据需要进行编辑:
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="White" />
<SolidColorBrush x:Key="MainColor" Color="DeepSkyBlue"/>
<SolidColorBrush x:Key="MainColorLight" Color="LightSkyBlue"/>
<SolidColorBrush x:Key="MainColorDark" Color="#00A7DF"/>
<SolidColorBrush x:Key="BorderMainBrush" Color="LightGray"/>
<SolidColorBrush x:Key="BorderDarkMainBrush" Color="#C0C0C0"/>
<SolidColorBrush x:Key="BackgroundGrayDark" Color="#FFEFEFEF"/>
<SolidColorBrush x:Key="BackgroundGrayLight" Color="#F5F5F5"/>
<SolidColorBrush x:Key="ForegroundDisabledBrush" Color="DimGray"/>
<SolidColorBrush x:Key="ForegroundBrush" Color="Black"/>
<LinearGradientBrush x:Key="FormBackgroundBrush"
EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFFFFD" Offset="0.31" />
<GradientStop Color="#FFF8F8F8" Offset="1" />
</LinearGradientBrush>
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="ToggleButton">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Pressed"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Border x:Name="Border" SnapsToDevicePixels="True" Grid.ColumnSpan="2" Background="{DynamicResource BackgroundGrayDark}" BorderBrush="{DynamicResource BorderDarkMainBrush}" BorderThickness="1" />
<Border x:Name="Border2" Grid.Column="0" SnapsToDevicePixels="True" Margin="1" Background="{StaticResource WindowBackgroundBrush}" BorderBrush="{DynamicResource BorderDarkMainBrush}" BorderThickness="0,0,1,0" />
<Path x:Name="Arrow" Grid.Column="1" Data="M 0 0 L 4 4 L 8 0 Z" Fill="DimGray" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColor}" />
<Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColor}" />
<Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColor}" />
<Setter Property="Fill" TargetName="Arrow" Value="White" />
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColorDark}" />
<Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColorDark}" />
<Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColorDark}" />
<Setter Property="Fill" TargetName="Arrow" Value="White" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" TargetName="Border" Value="{DynamicResource BackgroundGrayLight}" />
<Setter Property="BorderBrush" TargetName="Border" Value="{StaticResource BorderMainBrush}" />
<Setter Property="Foreground" Value="{StaticResource ForegroundDisabledBrush}" />
</Trigger>
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
<Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColorLight}" />
<Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColorLight}" />
<Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColorLight}" />
<Setter Property="Fill" TargetName="Arrow" Value="White" />
</DataTrigger >
</ControlTemplate.Triggers>
</ControlTemplate>
<ControlTemplate x:Key="ComboBoxTextBox" TargetType="TextBox">
<Border x:Name="PART_ContentHost" Background="{TemplateBinding Background}" Focusable="False" />
</ControlTemplate>
<Style TargetType="ComboBox">
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}" />
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="OverridesDefaultStyle" Value="true" />
<Setter Property="IsEditable" Value="True"/>
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto" />
<Setter Property="ScrollViewer.CanContentScroll" Value="true" />
<Setter Property="Margin" Value="2" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Disabled"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<ToggleButton x:Name="ToggleButton" Grid.Column="2" ClickMode="Press" Focusable="false"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
Template="{StaticResource ComboBoxToggleButton}"/>
<ContentPresenter Margin="3,3,23,3" Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
HorizontalAlignment="Left" IsHitTestVisible="False" x:Name="ContentSite"
VerticalAlignment="Center" />
<TextBox Style="{x:Null}" x:Name="PART_EditableTextBox" Margin="3,3,23,3" Background="Transparent"
Focusable="True" HorizontalAlignment="Left" IsReadOnly="{TemplateBinding IsReadOnly}"
Template="{StaticResource ComboBoxTextBox}" VerticalAlignment="Center" Visibility="Hidden" />
<Popup AllowsTransparency="True" Focusable="False" IsOpen="{TemplateBinding IsDropDownOpen}" x:Name="Popup" Placement="Bottom" PopupAnimation="Fade">
<Grid MaxHeight="{TemplateBinding MaxDropDownHeight}" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True">
<Border x:Name="DropDownBorder" Background="White" BorderBrush="{StaticResource BorderDarkMainBrush}" BorderThickness="1" CornerRadius="0" />
<ScrollViewer Margin="2" SnapsToDevicePixels="True">
<StackPanel KeyboardNavigation.DirectionalNavigation="Contained" IsItemsHost="True" TextBlock.Foreground="Black" />
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="HasItems" Value="false">
<Setter Property="MinHeight" TargetName="DropDownBorder" Value="95" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false" />
<Setter Property="Visibility" TargetName="PART_EditableTextBox" Value="Visible" />
<Setter Property="Visibility" TargetName="ContentSite" Value="Hidden" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
</Style.Triggers>
</Style>
注意切换按钮样式中的DataTrigger
部分,它挂钩到其模板化父项的IsKeyboardFocusWithin
属性,而不是IsFocused
属性,因为如果设置了最后一个属性,则无效正如我在这种风格中所做的那样ComboBox.IsEditable
到True
。
<DataTrigger Binding="{Binding IsKeyboardFocusWithin, RelativeSource={RelativeSource Mode=TemplatedParent}, Mode=OneWay}" Value="True">
<Setter Property="Background" TargetName="Border" Value="{DynamicResource MainColorLight}" />
<Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource MainColorLight}" />
<Setter Property="BorderBrush" TargetName="Border2" Value="{DynamicResource MainColorLight}" />
<Setter Property="Fill" TargetName="Arrow" Value="White" />
</DataTrigger >