WPF 一种带有多个子集的类ComBox 解决方法
在最近的工作中遇到很多,类似这种layUI风格的Combox:

因为WPF原本的控件,并不具备这种功能,尝试重写Combox的模板,发现无从下手。
于是尝试从多个控件组合来实现这个功能。
这里使用了Popup 来存放数据,发现还不错。
将popup分为三列,每个列的列宽设置位自动,当点击其中一个选项的时候,检索所选,根据字典查到数据,再加载其他列。
即可实现这种效果
代码如下:
UI:

<Button x:Name="btn1"
Height="54"
Margin="0,10,0,0"
Click="Button_Click">
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Border
Background="Transparent"
CornerRadius="15"
BorderBrush="#6B778D"
BorderThickness="1">
<Grid>
<TextBlock
Text="▼"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="White"
FontSize="20" />
<TextBlock
Text="{Binding Shell6PageModel.DetailedAddress}"
Margin="10,0,0,0"
VerticalAlignment="Center"
Foreground="White"
FontSize="32" />
</Grid>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Popup x:Name="pop1"
Width="{Binding ElementName=btn1, Path=ActualWidth}"
Height="260"
AllowsTransparency="True"
IsOpen="False"
Placement="Bottom"
PlacementTarget="{Binding ElementName=btn1}"
PopupAnimation="Slide"
StaysOpen="False">
<Grid>
<Border
Background="Gray"
Opacity="0.9"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="8" /> <Border>
<Grid HorizontalAlignment="Center">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> <Grid Grid.Column="0">
<ListBox
ItemsSource="{Binding Countries}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
BorderThickness="0"> <ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Border x:Name="bord1" />
<ContentPresenter />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bord1" Property="Background" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle> <ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding DetailedCountry}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Shell6Page}}, Path=DataContext.countryCommand}"
CommandParameter="{Binding}"
Width="100"
Height="35"
Margin="0,5,0,5"
VerticalAlignment="Center"
Foreground="White"
FontSize="36"
GroupName="0" />
</DataTemplate>
</ListBox.ItemTemplate> </ListBox> </Grid> <Grid Grid.Column="1">
<ListBox
ItemsSource="{Binding Shengs}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
BorderThickness="0"> <ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Grid>
<Border x:Name="bord1" />
<ContentPresenter VerticalAlignment="Center" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bord1" Property="Background" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle> <ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding DetailedSheng}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Shell6Page}}, Path=DataContext.shengCommand}"
CommandParameter="{Binding}"
Width="100"
Height="35"
Margin="0,5,0,5"
VerticalAlignment="Center"
Foreground="White"
FontSize="36"
GroupName="1" />
</DataTemplate>
</ListBox.ItemTemplate> </ListBox> </Grid> <Grid Grid.Column="2">
<ListBox
ItemsSource="{Binding Cities}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid>
<Border x:Name="bord1" />
<ContentPresenter />
</Grid> <ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bord1" Property="Background" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle> <ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding DetailedCity}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Shell6Page}}, Path=DataContext.cityCommand}"
CommandParameter="{Binding}"
Width="100"
Height="35"
Margin="0,5,0,5"
VerticalAlignment="Center"
Foreground="White"
FontSize="36"
GroupName="2" />
</DataTemplate>
</ListBox.ItemTemplate> </ListBox> </Grid> <Grid Grid.Column="3">
<ListBox
ItemsSource="{Binding Areas}"
ScrollViewer.VerticalScrollBarVisibility="Hidden"
BorderThickness="0">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid>
<Border x:Name="bord1" />
<ContentPresenter />
</Grid> <ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="bord1" Property="Background" Value="Transparent" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle> <ListBox.ItemTemplate>
<DataTemplate>
<RadioButton
Content="{Binding DetailedArea}"
Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:Shell6Page}}, Path=DataContext.areaCommand}"
CommandParameter="{Binding}"
Width="100"
Height="35"
Margin="0,5,0,5"
Foreground="White"
FontSize="36"
Click="RadioButton_Click"
GroupName="3" />
</DataTemplate>
</ListBox.ItemTemplate> </ListBox> </Grid> </Grid> </Grid> </Border> </Grid>
</Popup>
Model:

public class Shell6PageModel:ViewModelBase
{
private string detailedAddress;
/// <summary>
/// 详细地址
/// </summary>
public string DetailedAddress
{
get { return detailedAddress; }
set
{
detailedAddress = value; }
} private string area;
/// <summary>
/// 所在地区
/// </summary>
public string Area
{
get { return area; }
set { area = value; }
}
}
ViewModel:

public class Shell6PageViewModel : ViewModelBase
{
Dictionary<string, string> AddressCity = new Dictionary<string, string>();
Dictionary<string, string> AddressArea = new Dictionary<string, string>();
Dictionary<string, string> AddressSheng = new Dictionary<string, string>();
Dictionary<string, string> AddressCountry = new Dictionary<string, string>();
string[] ad; public Shell6PageViewModel()
{
countryCommand = new RelayCommand<Country>(t => GetCountry(t));
shengCommand = new RelayCommand<Sheng>(t => GetSheng(t));
cityCommand = new RelayCommand<City>(t => GetCity(t));
areaCommand = new RelayCommand<Area>(t => GetArea(t)); Shell6PageModel = new Shell6PageModel()
{
Area = EAppEnvironment.informationInfo.Area, DetailedAddress = EAppEnvironment.informationInfo.DetailedAddress };
InitDictionary();
} private void GetArea(Area t)
{
ad[3] = t.DetailedArea;
Shell6PageModel.DetailedAddress = "";
foreach (var item in ad)
{
Shell6PageModel.DetailedAddress += item;
} } private void GetCity(City t)
{
Areas.Clear(); ad[2] = t.DetailedCity;
Shell6PageModel.DetailedAddress = "";
foreach (var item in ad)
{
Shell6PageModel.DetailedAddress += item;
} foreach (var item in AddressArea)
{
if (t.DetailedCity == item.Value)
{
Areas.Add(new Area { DetailedArea = item.Key }); }
}
} private void GetSheng(Sheng t)
{
Cities.Clear();
Areas.Clear();
ad[1] = t.DetailedSheng;
Shell6PageModel.DetailedAddress = "";
foreach (var item in ad)
{
Shell6PageModel.DetailedAddress += item;
}
foreach (var item in AddressCity)
{
if (t.DetailedSheng == item.Value)
{
Cities.Add(new City() { DetailedCity = item.Key }); }
} } private void GetCountry(Country t)
{
Shengs.Clear();
Cities.Clear();
Areas.Clear();
ad = null;
ad = new string[4];
ad[0] = t.DetailedCountry;
Shell6PageModel.DetailedAddress = "";
foreach (var item in ad)
{
Shell6PageModel.DetailedAddress += item;
}
foreach (var item in AddressSheng)
{
if (t.DetailedCountry == item.Value)
{
Shengs.Add(new Sheng() { DetailedSheng = item.Key });
}
}
} private Shell6PageModel shell6PageModel; public Shell6PageModel Shell6PageModel
{
get { return shell6PageModel; }
set { shell6PageModel = value; RaisePropertyChanged(); }
} public RelayCommand<Sheng> shengCommand { get; set; } public RelayCommand<Country> countryCommand { get; set; } public RelayCommand<City> cityCommand { get; set; }
public RelayCommand<Area> areaCommand { get; set; } private ObservableCollection<Country> countries; public ObservableCollection<Country> Countries
{
get { return countries; }
set { countries = value; RaisePropertyChanged(); }
} private ObservableCollection<Sheng> shengs; public ObservableCollection<Sheng> Shengs
{
get { return shengs; }
set { shengs = value; RaisePropertyChanged(); }
} private ObservableCollection<City> cities; public ObservableCollection<City> Cities
{
get { return cities; }
set { cities = value; RaisePropertyChanged(); }
} private ObservableCollection<Area> areas; public ObservableCollection<Area> Areas
{
get { return areas; }
set { areas = value; RaisePropertyChanged(); }
} public void InitDictionary()
{
Countries = new ObservableCollection<Country>();
Shengs = new ObservableCollection<Sheng>();
Cities = new ObservableCollection<City>();
Areas = new ObservableCollection<Area>(); Countries.Add(new Country() { DetailedCountry = "中国" });
Countries.Add(new Country() { DetailedCountry = "国外" }); AddressSheng.Add("湖北1", "中国");
AddressSheng.Add("湖北2", "中国");
AddressSheng.Add("湖北3", "中国");
AddressSheng.Add("湖北4", "中国");
AddressSheng.Add("湖北5", "中国");
AddressSheng.Add("湖北6", "中国");
AddressSheng.Add("湖北7", "中国");
AddressSheng.Add("湖北8", "中国");
AddressSheng.Add("纽约1", "国外");
AddressSheng.Add("纽约2", "国外");
AddressSheng.Add("纽约3", "国外");
AddressSheng.Add("纽约4", "国外");
AddressSheng.Add("纽约5", "国外");
AddressSheng.Add("纽约6", "国外");
AddressSheng.Add("纽约7", "国外");
AddressSheng.Add("纽约8", "国外"); AddressCity.Add("孝感", "湖北1");
AddressCity.Add("武汉", "湖北1");
AddressCity.Add("襄阳", "湖北1");
AddressCity.Add("十堰", "湖北1");
AddressCity.Add("仙桃", "湖北1");
AddressCity.Add("鄂州", "湖北2");
AddressCity.Add("黄冈", "湖北2");
AddressCity.Add("神农架", "湖北2");
AddressCity.Add("黄石", "湖北2");
AddressCity.Add("恩施", "湖北2");
AddressCity.Add("湖南1", "湖北3");
AddressCity.Add("湖南2", "湖北3");
AddressCity.Add("湖南3", "湖北3");
AddressCity.Add("湖南4", "湖北3");
AddressCity.Add("湖南5", "湖北3");
AddressCity.Add("湖南6", "湖北3");
AddressCity.Add("湖南7", "湖北3"); AddressArea.Add("孝感1", "孝感");
AddressArea.Add("孝感2", "孝感");
AddressArea.Add("孝感3", "孝感");
AddressArea.Add("孝感4", "孝感");
AddressArea.Add("孝感5", "孝感");
AddressArea.Add("孝感6", "孝感");
AddressArea.Add("孝感7", "孝感");
AddressArea.Add("孝感8", "孝感"); }
}
WPF 一种带有多个子集的类ComBox 解决方法的更多相关文章
- 16种C语言编译警告(Warning)类型的解决方法
当编译程序发现程序中某个地方有疑问,可能有问题时就会给出一个警告信息.警告信息可能意味着程序中隐含的大错误,也可能确实没有问题.对于警告的正确处理方式应该是:尽可能地消除之.对于编译程序给出的每个警告 ...
- WebService中使用自定义类的解决方法(5种)
转自:http://www.cnblogs.com/lxinxuan/archive/2007/05/24/758317.html Demo下载:http://files.cnblogs.com/lx ...
- CodedUI Test 测试WPF程序,无法获取控件属性值的解决方法
注意注意!ItemStatus 在VS2010的CUIT里面是没有的!需要2013以上的版本才可使用. 公司新程序使用WPF制作,但使用CodedUI Test进行自动化测试的时候,很多控件抓取不到其 ...
- WPF 四种尺寸单位
原文:WPF 四种尺寸单位 像素 px 默认单位可以省略 厘米cm 英寸 in 点 pt 1in = 96px 1cm=96/2.42px 1pt=96/72px
- WPF 平板上按钮点击不触发,鼠标点击触发的两种解决方法
今天运行在windows平板上的程序,有个功能是弹出子窗体,点弹出窗体的关闭按钮,要点好几次才能触发.网上找了找,也有人与我类似的情形. 解决方法如下: public static void Disa ...
- WPF WebBrowser Memory Leak 问题及临时解决方法
首先介绍一下内存泄漏(Memory Leak)的概念,内存泄露是指程序中已动态分配的堆内存由于某种原因未释放或者无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果. 最近在使用W ...
- Ubuntu几种常见乱码解决方法
一.网页中的flash乱码: ubuntu默认浏览器是Firefox,但是Ubuntu默认不安装像flash这种带版权的软件,所以当你浏览像youku或网页播放器时,这种带有 flash ...
- Spring Boot Maven Plugin打包异常及三种解决方法:Unable to find main class
[背景]spring-boot项目,打包成可执行jar,项目内有两个带有main方法的类并且都使用了@SpringBootApplication注解(或者另一种情形:你有两个main方法并且所在类都没 ...
- PowerDesigner生成Oracle表名带有引号的解决方法
PowerDesigner生成表名带有引号,如下: /*==============================================================*/ /* Tabl ...
随机推荐
- 关于echarts中的noDataLoadingOption——loading动画的问题
在最近的一个项目中用到echarts这个插件,其中关于noDataLoadingOption配置项的问题让我困惑了好长时间.经过蛋疼的查找下,终于搞明白是版本的原因. 且看官网的介绍:ECharts, ...
- 在Docker下搭建MySQL双主双重集群(单机展示,与多机原理一致)
前言 Docker的安装部署&在Docker下MySQL的安装与配置 https://www.cnblogs.com/yumq/p/14253360.html 在Docker进行单机主从复制M ...
- tp where使用数组条件,如何设置or,and
1 //where条件数组拼接 2 $where['status'] = 1; 3 $maps['id'] = ['in', implode(',', $r_ids)]; 4 $maps['uid'] ...
- 算法历练之路——传纸条(JAVA)
传纸条 时间限制: 1Sec 内存限制: 128MB 提交: 36 解决: 16 题目描述小渊和小轩是好朋友也是同班同学,他们在一起 总有谈不完的话题.一次素质拓展活动中,班上同学安排做成一个m行n列 ...
- Socket粘包问题终极解决方案—Netty版(2W字)!
上一篇我们讲了<Socket粘包问题的3种解决方案>,但没想到评论区竟然炸了.介于大家的热情讨论,以及不同的反馈意见,本文就来做一个扩展和延伸,试图找到问题的最优解,以及消息通讯的最优解决 ...
- 浅谈 Checkbox Group 的双向数据绑定
前言 不曾想在忙碌的工作面前,写一篇技术博客也成了奢求. Checkbox 作为表单中最常见的一类元素,使用方式分为单值和多值,其中单值的绑定很简单,就是 true 和 false,但是多值(Chec ...
- Docker 镜像基础(三)
基于Dockerfile制作yum版本nginx镜像 [root@node-2 ~]# mkdir /opt/nginx [root@node-2 ~]# cd /opt/nginx/ ## 创建Do ...
- MyBatis初级实战之二:增删改查
欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...
- Tippy.js - 免费开源且高度可定制的气泡提示独立组件
推荐一个非常优秀的 web 气泡提示独立UI组件. 介绍 Tippy.js 是一款用于Web的完整工具提示,弹出菜单,下拉菜单和菜单解决方案.适用于鼠标,键盘和触摸输入. 特点 超轻量的纯 javas ...
- cut和tr命令的联合使用
cut的-d选项只能是单个字符,而对于多个连续相同字符分隔的字段,单凭cut命令是达不到想要的效果的,特别是多个连续空格分隔时. 但借助tr -s的压缩重复字符功能,可以将多个连续空格压缩为一个空格, ...