WPF 自定义ComboBox样式,自定义多选控件
一、ComboBox基本样式
ComboBox有两种状态,可编辑和不可编辑状态。通过设置IsEditable属性可以切换控件状态。
先看基本样式效果:
基本样式代码如下:
<!--ComboBox-->
<!--ComBoBox项选中背景色-->
<SolidColorBrush x:Key="ComboBoxSelectdBackground" Color="#ff8c69"/>
<!--ComBoBox项鼠标经过背景色-->
<SolidColorBrush x:Key="ComboBoxMouseOverBackground" Color="#ff3030"/>
<!--ComBoBox项选中前景色-->
<SolidColorBrush x:Key="ComboBoxSelectedForeground" Color="White"/>
<!--ComBoBox项鼠标经过前景色-->
<SolidColorBrush x:Key="ComboBoxMouseOverForegrond" Color="White"/>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ComboBoxItem">
<Setter Property="Height" Value="20"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Grid Height="{TemplateBinding Height}" Width="{TemplateBinding Width}">
<Border x:Name="_borderbg" Background="Transparent"/>
<TextBlock Margin="3 0 3 0" VerticalAlignment="Center" x:Name="_txt" Foreground="#333" Text="{Binding Content,RelativeSource={RelativeSource TemplatedParent}}"/>
<Border x:Name="_border" Background="White" Opacity="0"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="_borderbg" Property="Background" Value="{StaticResource ComboBoxSelectdBackground}" />
<Setter TargetName="_txt" Property="Foreground" Value="{StaticResource ComboBoxSelectedForeground}"/>
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="false"/>
<Condition Property="IsMouseOver" Value="true"/>
</MultiTrigger.Conditions>
<Setter TargetName="_borderbg" Property="Background" Value="{StaticResource ComboBoxMouseOverBackground}" />
<Setter TargetName="_txt" Property="Foreground" Value="{StaticResource ComboBoxMouseOverForegrond}"/>
</MultiTrigger> </ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBox}">
<Grid> <Grid.ColumnDefinitions>
<ColumnDefinition Width="0.7*"/>
<ColumnDefinition Width="0.3*" MaxWidth="30"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Grid.ColumnSpan="2" BorderThickness="1" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="1,0,0,1"/>
<ContentPresenter HorizontalAlignment="Left" Margin="3,3,0,3" x:Name="ContentSite" VerticalAlignment="Center" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" IsHitTestVisible="False"/> <!--ToggleButton 已数据绑定到 ComboBox 本身以切换 IsDropDownOpen-->
<ToggleButton Grid.Column="0" Grid.ColumnSpan="2" Template="{StaticResource ComboBoxToggleButton}" x:Name="ToggleButton" Focusable="false" IsChecked="{Binding Path=IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press"/>
<!--必须将 TextBox 命名为 PART_EditableTextBox,否则 ComboBox 将无法识别它-->
<TextBox Visibility="Hidden" BorderThickness="0" Margin="2 0 0 0" x:Name="PART_EditableTextBox" VerticalAlignment="Center" Focusable="True" Background="Transparent" IsReadOnly="{TemplateBinding IsReadOnly}"/> <!--Popup 可显示 ComboBox 中的项列表。IsOpen 已数据绑定到通过 ComboBoxToggleButton 来切换的 IsDropDownOpen-->
<Popup IsOpen="{TemplateBinding IsDropDownOpen}" Placement="Bottom" x:Name="Popup" Focusable="False" AllowsTransparency="True" PopupAnimation="Slide">
<Grid MaxHeight="150" MinWidth="{TemplateBinding ActualWidth}" x:Name="DropDown" SnapsToDevicePixels="True">
<Border x:Name="DropDownBorder" BorderBrush="#e8e8e8" BorderThickness="1 0 1 1"/>
<ScrollViewer Margin="1" SnapsToDevicePixels="True" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" CanContentScroll="True">
<!--StackPanel 用于显示子级,方法是将 IsItemsHost 设置为 True-->
<StackPanel IsItemsHost="True" KeyboardNavigation.DirectionalNavigation="Contained" Background="White"/>
</ScrollViewer>
</Grid>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEditable" Value="true">
<Setter TargetName="PART_EditableTextBox" Property="Visibility" Value="Visible" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
引用示例:
<ComboBox x:Name="combobox" Width="150" Margin="10" IsEditable="False" BorderBrush="#e8e8e8">
<CheckBox Content="上海" Tag="1"></CheckBox>
<CheckBox Content="北京" Tag="2"></CheckBox>
<CheckBox Content="天津" Tag="3"></CheckBox>
<CheckBox Content="广州" Tag="4"></CheckBox>
</ComboBox>
二、ComboBox扩展样式(多选控件)
ComBoBox能够单选选择数据,那么能不能实现多选的操作呢,答案是肯定的。这里多选的自定义控件参考了博主“梦里花落知多少”的内容。我对样式做了补充,使其能够更方便的进行移除多选的内容。同时也更好的展示了已选的内容,大家可以根据实际需求做出更好的展示效果。
先看效果:

2.1、添加自定义控件MultiComboBox
public class MultiComboBox : ComboBox
{
static MultiComboBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(MultiComboBox), new FrameworkPropertyMetadata(typeof(MultiComboBox)));
} private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
d.SetValue(e.Property, e.NewValue);
} /// <summary>
/// 选中项列表
/// </summary>
public ObservableCollection<MultiCbxBaseData> ChekedItems
{
get { return (ObservableCollection<MultiCbxBaseData>)GetValue(ChekedItemsProperty); }
set { SetValue(ChekedItemsProperty, value); }
} public static readonly DependencyProperty ChekedItemsProperty =
DependencyProperty.Register("ChekedItems", typeof(ObservableCollection<MultiCbxBaseData>), typeof(MultiComboBox), new PropertyMetadata(new ObservableCollection<MultiCbxBaseData>(), OnPropertyChanged)); /// <summary>
/// ListBox竖向列表
/// </summary>
private ListBox _ListBoxV; /// <summary>
/// ListBox横向列表
/// </summary>
private ListBox _ListBoxH; public override void OnApplyTemplate()
{
base.OnApplyTemplate();
_ListBoxV = Template.FindName("PART_ListBox", this) as ListBox;
_ListBoxH = Template.FindName("PART_ListBoxChk", this) as ListBox;
_ListBoxH.ItemsSource = ChekedItems;
_ListBoxV.SelectionChanged += _ListBoxV_SelectionChanged;
_ListBoxH.SelectionChanged += _ListBoxH_SelectionChanged; if (ItemsSource != null)
{
foreach (var item in ItemsSource)
{
MultiCbxBaseData bdc = item as MultiCbxBaseData;
if (bdc.IsCheck)
{
_ListBoxV.SelectedItems.Add(bdc);
}
}
}
} private void _ListBoxH_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.RemovedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData; for (int i = ; i < _ListBoxV.SelectedItems.Count; i++)
{
MultiCbxBaseData datachklist = _ListBoxV.SelectedItems[i] as MultiCbxBaseData;
if (datachklist.ID == datachk.ID)
{
_ListBoxV.SelectedItems.Remove(_ListBoxV.SelectedItems[i]);
}
}
}
} void _ListBoxV_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.AddedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData;
datachk.IsCheck = true;
if (ChekedItems.IndexOf(datachk) < )
{
ChekedItems.Add(datachk);
}
} foreach (var item in e.RemovedItems)
{
MultiCbxBaseData datachk = item as MultiCbxBaseData;
datachk.IsCheck = false;
ChekedItems.Remove(datachk);
}
} public class MultiCbxBaseData
{
private int _id;
/// <summary>
/// 关联主键
/// </summary>
public int ID
{
get { return _id; }
set { _id = value; }
} private string _viewName;
/// <summary>
/// 显示名称
/// </summary>
public string ViewName
{
get { return _viewName; }
set
{
_viewName = value;
}
} private bool _isCheck;
/// <summary>
/// 是否选中
/// </summary>
public bool IsCheck
{
get { return _isCheck; }
set { _isCheck = value;}
}
}
}
2.2、定义MultiComboBox控件的样式
 <ControlTemplate x:Key="ComboBoxToggleButton" TargetType="{x:Type ToggleButton}">
        <Grid Height="25">
            <Border Grid.Column="1" Background="White" Opacity="0"   Cursor="Hand"/>
            <Path x:Name="Arrow" Grid.Column="1"   Data="M 0 0  6 6 12 0 Z"  VerticalAlignment="Center" HorizontalAlignment="Center" Stretch="None" Fill="#B1B1B1" />
        </Grid>
        <ControlTemplate.Triggers>
            <Trigger Property="IsChecked" Value="true">
                <Setter TargetName="Arrow" Property="RenderTransform">
                    <Setter.Value>
                        <RotateTransform   CenterX="6" CenterY="3" Angle="180"></RotateTransform>
                    </Setter.Value>
                </Setter>
                <Setter TargetName="Arrow" Property="Margin" Value="0 0 0 2"/>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    <!--MultiComboBox普通样式-->
    <Style  TargetType="{x:Type local:MultiComboBox}">
        <Setter Property="Width" Value="200" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
        <Setter Property="SnapsToDevicePixels" Value="True" />
        <Setter Property="MaxDropDownHeight" Value="400" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:MultiComboBox}">
                    <Grid>
                        <Border x:Name="Bg" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"  Width="{TemplateBinding Width}" Height="{TemplateBinding Height}" BorderBrush="#eaeaea" BorderThickness="1"  >
                            <Grid x:Name="PART_Root">
                                <Grid x:Name="PART_InnerGrid" Margin="0">
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*" />
                                        <ColumnDefinition Width="0.3*" MaxWidth="30" />
                                    </Grid.ColumnDefinitions>
                                    <ListBox x:Name="PART_ListBoxChk"  SelectionMode="Multiple" BorderThickness="0" ScrollViewer.VerticalScrollBarVisibility="Disabled">
                                        <ListBox.ItemsPanel>
                                            <ItemsPanelTemplate>
                                                <VirtualizingStackPanel Orientation="Horizontal" VirtualizingStackPanel.IsVirtualizing="True" />
                                            </ItemsPanelTemplate>
                                        </ListBox.ItemsPanel>
                                        <ListBox.ItemContainerStyle>
                                            <Style TargetType="ListBoxItem">
                                                <Setter Property="BorderThickness" Value="0"/>
                                                <Setter Property="IsSelected" Value="True"/>
                                                <Setter Property="Template">
                                                    <Setter.Value>
                                                        <ControlTemplate TargetType="ListBoxItem">
                                                            <CheckBox BorderThickness="0"  VerticalAlignment="Center" HorizontalAlignment="Center"  Content="{Binding ViewName}" IsChecked="{Binding Path=IsSelected,RelativeSource={RelativeSource TemplatedParent},Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"/>
                                                        </ControlTemplate>
                                                    </Setter.Value>
                                                </Setter>
                                            </Style>
                                        </ListBox.ItemContainerStyle>
                                    </ListBox>
                                    <!--下拉按钮-->
                                    <ToggleButton x:Name="PART_DropDownToggle" IsTabStop="False"
                                         IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
                                         Grid.Column="1" Template="{StaticResource ComboBoxToggleButton}" />
                                </Grid>
                            </Grid>
                        </Border>
                        <!--弹出多选列表-->
                        <Popup x:Name="PART_Popup" AllowsTransparency="True"  Focusable="False" StaysOpen="False"
                               IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}"
                               PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
                            <Grid Width="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}"  MaxHeight="{Binding MaxDropDownHeight, RelativeSource={RelativeSource TemplatedParent}}" >
                                <ListBox x:Name="PART_ListBox" SelectionMode="Multiple" BorderThickness="1 0 1 1" Background="White" ItemsSource="{Binding ItemsSource,RelativeSource={RelativeSource TemplatedParent}}"
                                             MaxHeight="{TemplateBinding MaxDropDownHeight}" BorderBrush="#eaeaea"  >
                                    <ListBox.ItemContainerStyle>
                                        <Style  TargetType="ListBoxItem">
                                            <Setter Property="Template">
                                                <Setter.Value>
                                                    <ControlTemplate TargetType="{x:Type ListBoxItem}" >
                                                        <Grid  Height="22">
                                                            <Border x:Name="bg" BorderBrush="#eaeaea" BorderThickness="0"/>
                                                            <ContentPresenter x:Name="content"  />
                                                            <Border Background="White"  Opacity="0"/>
                                                        </Grid>
                                                        <ControlTemplate.Triggers>
                                                            <Trigger Property="IsSelected" Value="True">
                                                                <Setter  TargetName="bg"  Property="Background" Value="#ADD6FF" />
                                                            </Trigger>
                                                            <MultiTrigger>
                                                                <MultiTrigger.Conditions>
                                                                    <Condition Property="IsMouseOver" Value="true" />
                                                                    <Condition Property="IsSelected" Value="false"/>
                                                                </MultiTrigger.Conditions>
                                                                <Setter TargetName="bg" Property="Background" Value="#009BDB" />
                                                                <Setter TargetName="bg" Property="Opacity" Value="0.7"/>
                                                                <Setter   Property="Foreground" Value="White" />
                                                            </MultiTrigger>
                                                            <Trigger Property="IsEnabled" Value="False">
                                                                <Setter TargetName="bg" Property="Opacity" Value="0.3" />
                                                                <Setter   Property="Foreground" Value="Gray" />
                                                            </Trigger>
                                                        </ControlTemplate.Triggers>
                                                    </ControlTemplate>
                                                </Setter.Value>
                                            </Setter>
                                        </Style>
                                    </ListBox.ItemContainerStyle>
                                    <ListBox.ItemTemplate>
                                        <DataTemplate>
                                            <Grid>
                                                <CheckBox x:Name="chk" Visibility="Hidden"  IsChecked="{Binding IsCheck,Mode=TwoWay}" VerticalAlignment="Center"/>
                                                <CheckBox VerticalAlignment="Center"  Foreground="{Binding Foreground,RelativeSource={RelativeSource AncestorType=ListBoxItem}}" IsChecked="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected,Mode=TwoWay}"  Content="{Binding Path=ViewName}" />
                                            </Grid>
                                            <DataTemplate.Triggers>
                                                <DataTrigger   Binding="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="true">
                                                    <Setter  TargetName="chk"  Property="IsChecked" Value="true"/>
                                                </DataTrigger>
                                                <DataTrigger   Binding="{Binding  RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=IsSelected}" Value="false">
                                                    <Setter     TargetName="chk" Property="IsChecked" Value="false"/>
                                                </DataTrigger>
                                            </DataTemplate.Triggers>
                                        </DataTemplate>
                                    </ListBox.ItemTemplate>
                                </ListBox>
                            </Grid>
                        </Popup>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
2.3、引用示例:
<local:MultiComboBox x:Name="multiCmb" Margin="10" Width="200"/>
2.4、后台代码(初始化绑定数据):
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
MultiComboBoxList = new ObservableCollection<MultiCbxBaseData>()
{
new MultiCbxBaseData(){
ID=,
ViewName="张三",
IsCheck=false
},
new MultiCbxBaseData(){
ID=,
ViewName="李四",
IsCheck=false
},
new MultiCbxBaseData(){
ID=,
ViewName="王五",
IsCheck=false
},
new MultiCbxBaseData(){
ID=,
ViewName="马六",
IsCheck=false
},
new MultiCbxBaseData(){
ID=,
ViewName="赵七",
IsCheck=false
},
};
this.multiCmb.ItemsSource = MultiComboBoxList;
} private ObservableCollection<MultiCbxBaseData> MultiComboBoxList;
}
所有代码已经上传到github:https://github.com/cmfGit/WpfDemo.git
WPF 自定义ComboBox样式,自定义多选控件的更多相关文章
- WPF 自定义ComboBox样式
		
一.ComboBox基本样式 ComboBox有两种状态,可编辑和不可编辑状态.通过设置IsEditable属性可以切换控件状态. 先看基本样式效果: 基本样式代码如下: <!--ComboBo ...
 - WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
		
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...
 - 【转】WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
		
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要内容: 下拉选择控件ComboBox的自定义样式及扩展: 自定义多选控件Mul ...
 - WPF自定义行为Behavior,实现双击控件复制文本
		
WPF引用xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity& ...
 - WPF自定义控件(二)の重写原生控件样式模板
		
话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式. 开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么 ...
 - Android 自定义View 三板斧之一——继承现有控件
		
通常情况下,Android实现自定义控件无非三种方式. Ⅰ.继承现有控件,对其控件的功能进行拓展. Ⅱ.将现有控件进行组合,实现功能更加强大控件. Ⅲ.重写View实现全新的控件 本文重点讨论继承现有 ...
 - Kotlin 第一弹:自定义 ViewGroup 实现流式标签控件
		
古人学问无遗力, 少壮工夫老始成.纸上得来终觉浅, 绝知此事要躬行. – 陆游 <冬夜读书示子聿> 上周 Google I/O 大会的召开,宣布了 Kotlin 语言正式成为了官方开发语言 ...
 - WPF知识点全攻略05- XAML内容控件
		
此处简单列举出布局控件外,其他常用的控件: Window:WPF窗口 UserControl:用户控件 Page:页 Frame:用来浏览Page页 Border:嵌套控件,提供边框和背景. Butt ...
 - WPF教程002 - 实现Step步骤条控件
		
原文:WPF教程002 - 实现Step步骤条控件 在网上看到这么一个效果,刚好在用WPF做控件,就想着用WPF来实现一下 1.实现原理 1.1.该控件分为2个模块,类似ComboBox控件分为Ste ...
 
随机推荐
- Java动态代理和反射机制
			
反射机制 Java语言提供的一种基础功能,通过反射,我们可以操作这个类或对象,比如获取这个类中的方法.属性和构造方法等. 动态代理:分为JDK动态代理.cglib动态代理(spring中的动态代理). ...
 - maven问题总结
			
1.maven下载jar包速度慢 1.maven下载jar包速度慢(解决办法) 现在maven项目非常流行,因为它对jar实行了一个非常方便的管理,我们可以通过在pom.xml文件中做对应的配置即可将 ...
 - Hibernate 集成 Ehcache 开启二级缓存
			
一.将 Ehcache.xml 放到 classpath 下 <?xml version="1.0" encoding="UTF-8"?> < ...
 - 创建和修改 ExpressRoute 线路
			
本文介绍如何使用 Azure 门户和 Azure Resource Manager 部署模型创建 Azure ExpressRoute 线路. 以下步骤还说明如何查看线路状态,以及如何更新.删除和取消 ...
 - C# Redis的操作
			
Nuget添加StackExchange.Redis的引用 由于Redis封装类同时使用了Json,需要添加JSON.NET引用(Newtonsoft.Json) Redis封装类 /// <s ...
 - windows多线程同步
			
概述 任何单个应用程序都不能完全使该处理器达到满负荷.当一个线程遇到较长等待时间事件时,同步多线程还允许另一线程中的指令使用所有执行单元.例如,当一个线程发生高速缓存不命中,另一个线程可以继续执行.同 ...
 - Python学习---爬虫学习[requests模块]180411
			
模块安装 安装requests模块 pip3 install requests 安装beautifulsoup4模块 [更多参考]https://blog.csdn.net/sunhuaqiang1/ ...
 - 铁乐学python_day09_作业
			
练习题 1.整理函数相关知识点,写博客 2.写函数,检查获取传入列表或元组对象的所有奇数位索引对应的元素, 并将其作为新列表返回给调用者. def odd_index(l): lis = [] for ...
 - openoffice centos7.4 安装
			
其他是配置好java环境后操作 1.下载软件 http://www.openoffice.org/download/other.html 2.安装 tar xf Apache_OpenOffice_4 ...
 - Visual Studio 2013 Web开发新特性
			
微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Server 2013. ...