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 ...
随机推荐
- zTree设置异步加载后展开
//不能直接配置展开属性 因为没有数据,需要添加回调函数,异步加载成功展开 callback: { onAsyncSuccess: zTreeOnAsyncSuccess } //异步加载成功回调函数 ...
- 【转】数据分析与处理之二(Leveldb 实现原理)
郑重声明:本篇博客是自己学习 Leveldb 实现原理时参考了郎格科技系列博客整理的,原文地址:http://www.samecity.com/blog/Index.asp?SortID=12,只是为 ...
- SCCM2012安装、配置
1.sql server2012,排序规则选择:SQL_Latin1_General_CP1_CI_AS1.扩展AD架构2.打开ad用户和计算机,高级--system 容器授予 sccm服务器 完全控 ...
- PowerShell管理SCOM_批量设置维护模式(上 )
#定义存储需要置为维护模式的计算机名称列表 $serverlist = "C:\scomm\servers.txt" #定义脚本执行结果的输出位置 $server_maintena ...
- 解决Oracle11g密码180天过期,账号锁住的问题
1.查看用户的proifle是哪个,一般是default: sql>SELECT username,PROFILE FROM dba_users; 2.查看指定概要文件(如default)的密码 ...
- grafana的安装与设置(一)
zabbix3.4.9和grafana5.1.3的整合 官方文档:http://docs.grafana.org/installation/rpm/ 本次介绍两种安装方法,其他的方法请查看官方文档: ...
- Ardunio控制RGB的LED灯显示彩虹渐变色.
由于我使用的是共阴极的RGB LED,如果你的是共阳极的,接线的时候要注意一下. 其他没什么不同 //定义RGB色彩的输出I/O ; ; ; //标记颜色变化的方式,增加值还是减小值 bool red ...
- 为什么ConcurrentHashMap是弱一致的
为什么ConcurrentHashMap是弱一致的 本文将用到Java内存模型的happens-before偏序关系(下文将简称为hb)以及ConcurrentHashMap的底层模型相关的知识.ha ...
- 【错误记录】flask mysql 死锁
最近使用flask-sqlalchemy时,进行测试的时候发现日志中打印出了MySql死锁错误,查看Mysql日志发现是因为有俩条sql出现了死锁: Deadlock found when tryin ...
- Android开发经验02:Android 项目开发流程
Android开发完整流程: 一.用户需求分析 用户需求分析占据整个APP开发流程中最重要的一个环节.一款APP开发的成功与否很大程度都决定于此.这里所说的用户需求分析指的是基于用户的要求所进行的 ...