Wpf 如何有条件地仅对组合框的选定项中的文本设置样式?
我有一种情况,我需要对组合框中的所选项目进行不同的样式设置(使文本加粗),当它是除一个值之外的所有项目之一时。例如,在标签为“您最喜欢的原色是什么?”的下拉框中,我有四个选项:Wpf 如何有条件地仅对组合框的选定项中的文本设置样式?,wpf,Wpf,我有一种情况,我需要对组合框中的所选项目进行不同的样式设置(使文本加粗),当它是除一个值之外的所有项目之一时。例如,在标签为“您最喜欢的原色是什么?”的下拉框中,我有四个选项:无首选项,红色,绿色,和蓝色。ComboBox项目只是带有默认样式的文本,没有图像或任何其他花哨的东西,是C#类,没有包装在ComboBoxItems中 当用户从列表中指定首选项时,我希望通过将折叠列表中选定项的文本设置为粗体来突出显示该选项。如果用户选择无首选项,字体重量应保持正常 通过将ComboBox上的FontWe
无首选项
,红色
,绿色
,和蓝色
。ComboBox项目只是带有默认样式的文本,没有图像或任何其他花哨的东西,是C#类,没有包装在ComboBoxItems中
当用户从列表中指定首选项时,我希望通过将折叠列表中选定项的文本设置为粗体来突出显示该选项。如果用户选择无首选项
,字体重量应保持正常
通过将ComboBox上的FontWeight属性设置为粗体,并将DataTrigger定义为SelectedItem!=没有首选项
。但是,这会设置组合框项目列表中所有项目的样式,包括下拉列表中的所有项目。我希望这些项目总是以正常的字体显示
这可能吗
编辑
我一直在尝试@crazyarabian用MultiTrigger设计ComboBoxItem样式的方法。样式定义为:
<Style x:Key="SelectedItemStyle">
<Setter Property="ComboBoxItem.FontWeight" Value="Normal" />
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ComboBoxItem.IsSelected" Value="True" />
<Condition Binding="{Binding IsNoPreferenceSelected,Mode=OneWay}" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="ComboBoxItem.FontWeight" Value="Bold" />
</MultiTrigger>
</Style.Triggers>
</Style>
应用程序因NullReferenceException
而死亡,该异常在上述InvalidOperationException之后抛出(或者可能导致该异常,我无法破译输出)。我能想到的唯一可能导致这种情况的原因是在我的第二个MultiTrigger条件下解析绑定中的属性,但我根本没有得到任何绑定错误。下面是堆栈顶部的跟踪,以防也有帮助:
InvalidOperationException:'System.InvalidOperationException: Must have non-null value for 'Property'.
at System.Windows.Condition.Seal(ValueLookupType type)
at System.Windows.ConditionCollection.Seal(ValueLookupType type)
at System.Windows.MultiTrigger.Seal()
at System.Windows.TriggerCollection.Seal()
at System.Windows.Style.Seal()
at System.Windows.StyleHelper.UpdateStyleCache(FrameworkElement fe, FrameworkContentElement fce, Style oldStyle, Style newStyle, Style& styleCache)
at System.Windows.FrameworkElement.OnStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
at System.Windows.Controls.ItemsControl.ApplyItemContainerStyle(DependencyObject container, Object item)
我不是WPF方面的专家,但在Windows窗体中,答案称为“OwnerDraw”。这意味着您的代码负责绘制控件,而不是依赖默认行为。当您自己绘制时,您可以应用任何您想要的样式,包括使用不同样式绘制不同项目的能力
我在网上快速搜索了“combobox ownerdraw”,点击率超过1000000。你不是唯一一个需要这样做的人,所以你肯定会很快找到一个像样的教程。没有必要像owner draw那么卑鄙——我们这里谈论的是WPF,而不是WinForms。在WinForms中,唯一的解决方案是编写更多代码。在WPF中,我们可以用几个非常简单的自定义模板来解决这个问题。对于这个示例,我使用了一个免费的轻量级XAML编辑器。不需要代码隐藏Kaxaml附带了一系列称为简单样式的“入门”样式。我使用了ComboBox简单样式,并对其进行了修改。所以,虽然这看起来像很多XAML,但我实际上只是从样板一开始,并添加了几行代码 您可能会想到更优雅的方式来触发字体的重量变化;我使用了
SelectedIndex
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<DataTemplate x:Key="SelectionBoxTextTemplate">
<TextBlock FontWeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=FontWeight}" Text="{Binding}"/>
</DataTemplate>
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
Background="#C0C0C0"
BorderBrush="#404040"
BorderThickness="1"
CornerRadius="2"/>
<Border
Grid.Column="0"
Margin="1"
Background="#FFFFFF"
BorderBrush="#404040"
BorderThickness="0,0,1,0"
CornerRadius="2,0,0,2"/>
<Path
x:Name="Arrow"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="#404040"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="#808080"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="#E0E0E0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="#EEEEEE"/>
<Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA"/>
<Setter Property="Foreground" Value="#888888"/>
<Setter TargetName="Arrow" Property="Fill" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
<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="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton
Name="ToggleButton"
Grid.Column="2"
ClickMode="Press"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
Template="{StaticResource ComboBoxToggleButton}">
</ToggleButton>
<ContentPresenter
Name="ContentSite"
HorizontalAlignment="Left"
Margin="3,3,23,3"
VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{StaticResource SelectionBoxTextTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
IsHitTestVisible="False"/>
<TextBox
x:Name="PART_EditableTextBox"
HorizontalAlignment="Left"
Margin="3,3,23,3"
VerticalAlignment="Center"
Background="Transparent"
Focusable="False"
IsReadOnly="{TemplateBinding IsReadOnly}"
Style="{x:Null}"
Visibility="Hidden"/>
<Popup
Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid
Name="DropDown"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
Background="#FFFFFF"
BorderBrush="#888888"
BorderThickness="1"/>
<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="#888888"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="Popup.AllowsTransparency" SourceName="Popup" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="1">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="2">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="3">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="Border" Padding="2" SnapsToDevicePixels="true">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="#DDDDDD"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Margin="5" Text="What is your favorite primary colour?"/>
<ComboBox Width="150" SelectedIndex="0">
<ComboBoxItem>No Preference</ComboBoxItem>
<ComboBoxItem>Red</ComboBoxItem>
<ComboBoxItem>Green</ComboBoxItem>
<ComboBoxItem>Blue</ComboBoxItem>
</ComboBox>
</StackPanel>
</Page>
无偏好
红色
绿色
蓝色
我在组合框中使用了ContentPresenter
的ContentTemplate
属性来添加自定义数据模板(selectionboxtextmplate
)。该TextBlock
从祖先组合框中获取其fontwweight
。然后,我为各个项目添加了一个模板,强制它们使用正常的字体大小。这得到了您想要的结果:
您需要将触发器应用于ComboBoxItem本身。除非更改了ComboBox的行为,否则所有项目都显示在容器(用于应用样式和模板)中,并且ComboBox使用的默认容器是ComboBoxItem
<Style TargetType="ComboBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>
您需要添加现有触发器,以补偿在没有首选项时未加粗的选择。使用所有者绘制控件,任何事情都是可能的。这是一种痛苦,因为你必须复制所有的d
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Page.Resources>
<DataTemplate x:Key="SelectionBoxTextTemplate">
<TextBlock FontWeight="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ComboBox}}, Path=FontWeight}" Text="{Binding}"/>
</DataTemplate>
<ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
<Border
x:Name="Border"
Grid.ColumnSpan="2"
Background="#C0C0C0"
BorderBrush="#404040"
BorderThickness="1"
CornerRadius="2"/>
<Border
Grid.Column="0"
Margin="1"
Background="#FFFFFF"
BorderBrush="#404040"
BorderThickness="0,0,1,0"
CornerRadius="2,0,0,2"/>
<Path
x:Name="Arrow"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z"
Fill="#404040"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsMouseOver" Value="true">
<Setter TargetName="Border" Property="Background" Value="#808080"/>
</Trigger>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="Background" Value="#E0E0E0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="#EEEEEE"/>
<Setter TargetName="Border" Property="BorderBrush" Value="#AAAAAA"/>
<Setter Property="Foreground" Value="#888888"/>
<Setter TargetName="Arrow" Property="Fill" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
<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="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid>
<ToggleButton
Name="ToggleButton"
Grid.Column="2"
ClickMode="Press"
Focusable="false"
IsChecked="{Binding Path=IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}"
Template="{StaticResource ComboBoxToggleButton}">
</ToggleButton>
<ContentPresenter
Name="ContentSite"
HorizontalAlignment="Left"
Margin="3,3,23,3"
VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{StaticResource SelectionBoxTextTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}"
IsHitTestVisible="False"/>
<TextBox
x:Name="PART_EditableTextBox"
HorizontalAlignment="Left"
Margin="3,3,23,3"
VerticalAlignment="Center"
Background="Transparent"
Focusable="False"
IsReadOnly="{TemplateBinding IsReadOnly}"
Style="{x:Null}"
Visibility="Hidden"/>
<Popup
Name="Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Slide">
<Grid
Name="DropDown"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
MinWidth="{TemplateBinding ActualWidth}"
SnapsToDevicePixels="True">
<Border
x:Name="DropDownBorder"
Background="#FFFFFF"
BorderBrush="#888888"
BorderThickness="1"/>
<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="#888888"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
<Trigger Property="Popup.AllowsTransparency" SourceName="Popup" Value="true">
<Setter TargetName="DropDownBorder" Property="CornerRadius" Value="4"/>
<Setter TargetName="DropDownBorder" Property="Margin" Value="0,2,0,0"/>
</Trigger>
<Trigger Property="IsEditable" Value="true">
<Setter Property="IsTabStop" Value="false"/>
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible"/>
<Setter TargetName="ContentSite" Property="Visibility" Value="Hidden"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="1">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="2">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
<Trigger Property="SelectedIndex" Value="3">
<Setter Property="FontWeight" Value="Bold"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type ComboBoxItem}" TargetType="{x:Type ComboBoxItem}">
<Setter Property="SnapsToDevicePixels" Value="true"/>
<Setter Property="OverridesDefaultStyle" Value="true"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="Border" Padding="2" SnapsToDevicePixels="true">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="Border" Property="Background" Value="#DDDDDD"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="#888888"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Page.Resources>
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock Margin="5" Text="What is your favorite primary colour?"/>
<ComboBox Width="150" SelectedIndex="0">
<ComboBoxItem>No Preference</ComboBoxItem>
<ComboBoxItem>Red</ComboBoxItem>
<ComboBoxItem>Green</ComboBoxItem>
<ComboBoxItem>Blue</ComboBoxItem>
</ComboBox>
</StackPanel>
</Page>
<Style TargetType="ComboBoxItem">
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="FontWeight" Value="Bold" />
</Trigger>
</Style.Triggers>
</Style>