我想自定义从ComboBox下拉的面板。
例如,用于添加搜索功能或其他功能。
我了解EssentialObjects,这正是我所需要的,但是我想知道自己如何做。
小草稿
<ComboBox ...>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<!-- This is how i can customize container for items. But it's not the way -->
<!-- <UniformGrid Columns="2" /> -->
<!-- But i need something like this -->
<Grid>
<!-- Whatever i want -->
<TextBox ... />
<Button ... />
<Button ... />
<!-- Container for items -->
<UniformGrid Columns="2"/>
</Grid>
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
是否可以调整标准ComboBox,还是必须创建自己的控件?
答案 0 :(得分:2)
我的建议是创建自己的ComboBox
,以扩展标准版本。让我们看看如何。首先是控件类:
public class CustomComboBox : ComboBox
{
public static readonly DependencyProperty HeaderTemplateProperty =
DependencyProperty.Register("HeaderTemplate", typeof(DataTemplate), typeof(CustomComboBox), new PropertyMetadata(null));
public static readonly DependencyProperty FooterTemplateProperty =
DependencyProperty.Register("FooterTemplate", typeof(DataTemplate), typeof(CustomComboBox), new PropertyMetadata(null));
static CustomComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomComboBox), new FrameworkPropertyMetadata(typeof(CustomComboBox)));
}
public DataTemplate HeaderTemplate
{
get { return (DataTemplate)GetValue(HeaderTemplateProperty); }
set { SetValue(HeaderTemplateProperty, value); }
}
public DataTemplate FooterTemplate
{
get { return (DataTemplate)GetValue(FooterTemplateProperty); }
set { SetValue(FooterTemplateProperty, value); }
}
}
我们只是添加两个dependecy属性来管理页眉和页脚。现在,使用ILSpy可以检索默认的ComboBox样式。我们需要使用我们的控制模板:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cbd="clr-namespace:Microsoft.Windows.Themes;assembly=PresentationFramework.Classic"
xmlns:local="clr-namespace:WpfApp1">
<Geometry x:Key="Û">M 0 0 L 3.5 4 L 7 0 Z</Geometry>
<Style x:Key="Ü" TargetType="{x:Type ToggleButton}">
<Setter Property="FrameworkElement.MinWidth" Value="0" />
<Setter Property="FrameworkElement.MinHeight" Value="0" />
<Setter Property="FrameworkElement.Width" Value="Auto" />
<Setter Property="FrameworkElement.Height" Value="Auto" />
<Setter Property="Control.Background" Value="#00FFFFFF" />
<Setter Property="Control.BorderBrush" Value="{x:Static cbd:ClassicBorderDecorator.ClassicBorderBrush}" />
<Setter Property="Control.BorderThickness" Value="2" />
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<DockPanel Background="{TemplateBinding Control.Background}" LastChildFill="False" SnapsToDevicePixels="True">
<cbd:ClassicBorderDecorator x:Name="Border" BorderStyle="AltRaised" DockPanel.Dock="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Background="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="{TemplateBinding Control.BorderBrush}">
<Path Fill="{TemplateBinding Control.Foreground}" HorizontalAlignment="Center" VerticalAlignment="Center" Data="{StaticResource Û}" />
</cbd:ClassicBorderDecorator>
</DockPanel>
<ControlTemplate.Triggers>
<Trigger Property="ToggleButton.IsChecked" Value="true">
<Setter TargetName="Border" Property="cbd:ClassicBorderDecorator.BorderStyle" Value="AltPressed" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="Control.Foreground" Value="{DynamicResource {x:Static SystemColors.ControlDarkBrushKey}}" />
</Trigger>
</Style.Triggers>
</Style>
<Style BasedOn="{StaticResource {x:Type ComboBox}}" TargetType="{x:Type local:CustomComboBox}">
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Border Background="{TemplateBinding Control.Background}" BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="{TemplateBinding Control.BorderBrush}" SnapsToDevicePixels="True">
<Grid>
<cbd:ClassicBorderDecorator x:Name="Border" Background="{TemplateBinding Control.Background}" BorderBrush="{x:Static cbd:ClassicBorderDecorator.ClassicBorderBrush}" BorderThickness="2" BorderStyle="Sunken">
<Popup Name="PART_Popup" AllowsTransparency="True" Placement="Bottom" IsOpen="{TemplateBinding ComboBox.IsDropDownOpen}" Focusable="False" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}">
<cbd:SystemDropShadowChrome x:Name="Shdw" Color="Transparent" MaxHeight="{TemplateBinding ComboBox.MaxDropDownHeight}" MinWidth="{Binding ElementName=Border, Path=ActualWidth}">
<Border Name="DropDownBorder" Background="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" BorderThickness="1" BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}">
<ScrollViewer Name="DropDownScrollViewer">
<Grid RenderOptions.ClearTypeHint="Enabled">
<Canvas Height="0" Width="0" HorizontalAlignment="Left" VerticalAlignment="Top">
<Rectangle Name="OpaqueRect" Height="{Binding ElementName=DropDownBorder, Path=ActualHeight}" Width="{Binding ElementName=DropDownBorder, Path=ActualWidth}" Fill="{Binding ElementName=DropDownBorder, Path=Background}" />
</Canvas>
<StackPanel>
<ContentPresenter Margin="1,1,1,1" ContentTemplate="{TemplateBinding local:CustomComboBox.HeaderTemplate}" />
<ItemsPresenter Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
<ContentPresenter Margin="1,1,1,1" ContentTemplate="{TemplateBinding local:CustomComboBox.FooterTemplate}" />
</StackPanel>
</Grid>
</ScrollViewer>
</Border>
</cbd:SystemDropShadowChrome>
</Popup>
</cbd:ClassicBorderDecorator>
<DockPanel Margin="2">
<FrameworkElement DockPanel.Dock="Right" Width="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" />
<Border Name="SelectedItemBorder" Margin="{TemplateBinding Control.Padding}">
<ContentPresenter Margin="1,1,1,1" Content="{TemplateBinding ComboBox.SelectionBoxItem}" ContentTemplate="{TemplateBinding ComboBox.SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemsControl.ItemTemplateSelector}" ContentStringFormat="{TemplateBinding ComboBox.SelectionBoxItemStringFormat}" VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>
</DockPanel>
<ToggleButton Margin="2" MinWidth="0" MinHeight="0" Width="Auto" Focusable="False" Style="{StaticResource Ü}" ClickMode="Press" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ComboBox.IsSelectionBoxHighlighted" Value="True" />
<Condition Property="ComboBox.IsDropDownOpen" Value="False" />
</MultiTrigger.Conditions>
<Setter Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}" Property="Control.Foreground" />
</MultiTrigger>
<Trigger Property="ComboBox.IsSelectionBoxHighlighted" Value="True">
<Setter TargetName="SelectedItemBorder" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" Property="Border.Background" />
</Trigger>
<Trigger Property="ItemsControl.HasItems" Value="False">
<Setter TargetName="DropDownBorder" Property="FrameworkElement.MinHeight" Value="95" />
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" Property="Control.Foreground" />
<Setter Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Property="Control.Background" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="ItemsControl.IsGrouping" Value="True" />
<Condition Property="VirtualizingPanel.IsVirtualizingWhenGrouping" Value="False" />
</MultiTrigger.Conditions>
<Setter Property="ScrollViewer.CanContentScroll" Value="False" />
</MultiTrigger>
<Trigger SourceName="PART_Popup" Property="Popup.HasDropShadow" Value="True">
<Setter TargetName="Shdw" Property="FrameworkElement.Margin" Value="0,0,5,5" />
<Setter TargetName="Shdw" Property="cbd:SystemDropShadowChrome.Color" Value="#71000000" />
</Trigger>
<Trigger SourceName="DropDownScrollViewer" Property="ScrollViewer.CanContentScroll" Value="False">
<Setter TargetName="OpaqueRect" Value="{Binding ElementName=DropDownScrollViewer, Path=VerticalOffset}" Property="Canvas.Top" />
<Setter TargetName="OpaqueRect" Value="{Binding ElementName=DropDownScrollViewer, Path=HorizontalOffset}" Property="Canvas.Left" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
我选择了 classic 主题,因此在这种情况下,需要将对PresentationFramework.classic的引用添加到项目中。
诀窍在于,我添加了两个ContentPresenter
(前一个和后一个)ItemPresenter
(称为 ItemsPresenter )。他们将显示我们的自定义DataTemplate
。
此样式应放置在Themes \ generic.xaml文件中(将其生成操作设置为 Page )。
现在我们可以使用CustomComboBox:
<StackPanel>
<local:CustomComboBox>
<local:CustomComboBox.HeaderTemplate>
<DataTemplate>
<TextBlock Text="HEADER" />
</DataTemplate>
</local:CustomComboBox.HeaderTemplate>
<local:CustomComboBox.FooterTemplate>
<DataTemplate>
<TextBlock Text="FOOTER" />
</DataTemplate>
</local:CustomComboBox.FooterTemplate>
<ComboBoxItem>One</ComboBoxItem>
<ComboBoxItem>Two</ComboBoxItem>
<ComboBoxItem>Three</ComboBoxItem>
</local:CustomComboBox>
</StackPanel>
希望它能对您有所帮助。