WPF:DataTemplateSelector设置控件不同的样式
原文 WPF:DataTemplateSelector设置控件不同的样式
最近想实现这么个东西,一个ListBox, 里面的ListBoxItem可能是文本框、下拉框、日期选择控件等等。
很自然的想到了DataTemplateSelector,并且事先定义好各类DataTemplate以显示不同的控件。
先定义好各类资源
<Window.Resources>
<DataTemplate x:Key="textBox">
<Border BorderBrush="Gray" BorderThickness="1">
<TextBox Text="{Binding CombinedValue}"></TextBox>
</Border>
</DataTemplate>
<DataTemplate x:Key="comboBox">
<Border BorderBrush="Gray" BorderThickness="1">
<ComboBox ItemsSource="{Binding CombinedValue}"></ComboBox>
</Border>
</DataTemplate>
<DataTemplate x:Key="dateTime">
<Border BorderBrush="Gray" BorderThickness="1">
<DatePicker Text="{Binding CombinedValue}" ></DatePicker>
</Border>
</DataTemplate>
</Window.Resources>
然后在ListBox中设置ItemDataTemplateSelector
<ListBox ItemsSource="{Binding}">
<ListBox.ItemTemplateSelector>
<local:DataTypeTemplateSelector TextBoxTemplate="{StaticResource textBox}"
ComboBoxTemplate="{StaticResource comboBox}"
DateTimeTemplate="{StaticResource dateTime}"></local:DataTypeTemplateSelector>
</ListBox.ItemTemplateSelector>
</ListBox>
新建一个类继承DataTemplateSelector
public class DataTypeTemplateSelector:DataTemplateSelector
{
public DataTemplate TextBoxTemplate { get; set; }
public DataTemplate ComboBoxTemplate { get; set; }
public DataTemplate DateTimeTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
CombinedEntity entity = item as CombinedEntity; //CombinedEnity为绑定数据对象
string typeName = entity.TypeName;
if (typeName == "TextBox")
{
return TextBoxTemplate;
}
if (typeName == "ComboBox")
{
return ComboBoxTemplate;
}
if (typeName == "DateTime")
{
return DateTimeTemplate;
}
return null;
}
}
设置好DataContext,即可运行
public partial class CombinedControl : Window
{
public List<CombinedEntity> entities;
public CombinedControl()
{
InitializeComponent();
entities = new List<CombinedEntity>()
{
new CombinedEntity{ CombinedValue=new List<string>{"","",""}, TypeName="ComboBox"},
new CombinedEntity{ CombinedValue ="Test", TypeName="TextBox"},
new CombinedEntity{ CombinedValue=DateTime.Now, TypeName="DateTime"}
};
this.DataContext = entities;
}
}
public class CombinedEntity
{
/// <summary>
/// 绑定数据的值
/// </summary>
public object CombinedValue
{
get;
set;
}
/// <summary>
/// 数据的类型
/// </summary>
public string TypeName
{
get;
set;
}
}
如果运行成功,我们可以看到一个下拉框,一个文本框,一个日期选择控件都做为ListBox的子项显示在窗口中。
但是,我发现,在DataTypeTemplateSelector对象的SelectTemplate 方法中,居然需要把item对象转换成我们的绑定数据对象
CombinedEntity entity = item as CombinedEntity; //CombinedEnity为绑定数据对象
这意味着前台需要引入后端的业务逻辑,代码的味道相当不好,不过没有关系,我们有强大的反射工具,重构下代码:
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Type t = item.GetType();
string typeName = null;
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties)
{
if (pi.Name == "TypeName")
{
typeName = pi.GetValue(item, null).ToString();
break;
}
}
if (typeName == "TextBox")
{
return TextBoxTemplate;
}
if (typeName == "ComboBox")
{
return ComboBoxTemplate;
}
if (typeName == "DateTime")
{
return DateTimeTemplate;
}
return null;
}
这样,我们就无需引入后端的实体(Model)对象,保证了前端的干净。
运行起来,还是没有问题,仔细看DataTypeTemplateSelector对象的SelectTemplate
方法,还是有点丑陋,这里把CombinedEntity的TypeName属性硬编码,万一TypeName改成ControlName或其他名字,控
件则无法按照预期显示。
再次重构,首先修改绑定对象CombinedEntity
public class CombinedEntity
{
/// <summary>
/// 绑定数据的值
/// </summary>
public object CombinedValue
{
get;
set;
}
/// <summary>
/// 显示控件的类型
/// </summary>
public Type ControlType
{
get;
set;
}
}
修改ListBox绑定数据源
entities = new List<CombinedEntity>()
{
new CombinedEntity{ CombinedValue=new List<string>{"","",""}, ControlType = typeof(ComboBox)},
new CombinedEntity{ CombinedValue ="Test", ControlType = typeof(TextBox)},
new CombinedEntity{ CombinedValue=DateTime.Now, ControlType = typeof(DatePicker)}
};
this.DataContext = entities;
最后再次修改DataTypeTemplateSelector对象的SelectTemplate 方法
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
Type t = item.GetType();
Type controlType = null;
PropertyInfo[] properties = t.GetProperties();
foreach (PropertyInfo pi in properties)
{
if (pi.PropertyType == typeof(Type))
{
controlType = (Type)pi.GetValue(item, null);
break;
}
}
if (controlType == typeof(TextBox))
{
return TextBoxTemplate;
}
if (controlType == typeof(ComboBox))
{
return ComboBoxTemplate;
}
if (controlType == typeof(DatePicker))
{
return DateTimeTemplate;
}
return null;
}
这样,要显示不同的控件,在ControlType里面定义即可,然后在XAML添加DataTemplate,在DataTemplateSelector对象中根据不同的ControlType返回不同的DataTemplate,而且实现的方式看上去比较优雅。
WPF:DataTemplateSelector设置控件不同的样式的更多相关文章
- WPF 4 DataGrid 控件(自定义样式篇)
原文:WPF 4 DataGrid 控件(自定义样式篇) 在<WPF 4 DataGrid 控件(基本功能篇)>中我们已经学习了DataGrid 的基本功能及使用方法.本篇将继续 ...
- [转]设置控件全局显示样式appearance proxy
转自:huifeidexin_1的专栏 appearance是apple在iOS5.0上加的一个协议,它让程序员可以很轻松地改变某控件的全局样式(背景) @selector(appearance) 支 ...
- 设置控件全局显示样式 appearance
iOS5及其以后提供了一个比较强大的工具UIAppearance,我们通过UIAppearance设置一些UI的全局效果,这样就可以很方便的实现UI的自定义效果又能最简单的实现统一界面风格,它提供如下 ...
- WPF 定义Lookless控件的默认样式、 OnApplyTemplate 如何使用(实现方式、如何工作的)!
写的非常详细: 作者地址:https://www.cnblogs.com/atskyline/archive/2012/11/16/2773806.html 参考资料: http://www.code ...
- WPF 4 DataGrid 控件(进阶篇一)
原文:WPF 4 DataGrid 控件(进阶篇一) 上一篇<WPF 4 DataGrid 控件(自定义样式篇)>中,我们掌握了DataGrid 列表头.行表头.行.单元格相关的 ...
- WPF 4 DataGrid 控件(进阶篇二)
原文:WPF 4 DataGrid 控件(进阶篇二) 上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...
- WPF设置控件获取键盘焦点时的样式FocusVisualStyle
控件获取焦点除了用鼠标外,可以通过键盘来获取,比如Tab键或者方向键等,需要设置控件获取键盘焦点时的样式,可以通过设置FrameworkElemnt.FocusVisualStyle属性, 因为几乎所 ...
- WPF自定义分页控件,样式自定义,简单易用
WPF自定义分页控件 做了许久伸手党,终于有机会贡献一波,搜索一下WPF分页控件,还是多,但是不太通用,主要就是样式问题,这个WPF很好解决,还有一个就是分页控件嘛,只关心几个数字的变动就行了,把页码 ...
- WPF Calendar 日历控件 样式自定义
原文:WPF Calendar 日历控件 样式自定义 粗略的在代码上做了些注释 blend 生成出来的模版 有的时候 会生成 跟 vs ui界面不兼容的代码 会导致可视化设计界面 报错崩溃掉 但是确不 ...
随机推荐
- 在systemd(CentOS7)自启动zookeeper
zookeeper的自启动脚本,如果是 sysV 模式(CeontOS6或以下版本),可以直接使用下载版本中的 src 目录下对应的 sysV 自启动包,再chkconfig即可.老方法,简单,就不说 ...
- The document "ViewController.xib" could not be opened. Could not read archive.
The document "ViewController.xib" could not be opened. Could not read archive. Please use ...
- DBV-00111: OCI failure (3722) (ORA-01002: fetch out of sequence解决
在使用DBV检测segment的时候出现 DBV-00111: OCI failure (3722) (ORA-01002: fetch out of sequence)错误: 在寻找原因过程中发现相 ...
- Android中GridView的使用——使用自带的SimpleAdapter(简单适配器)
GridView一直是一个系统登录后以九宫格方式展现功能子模块的最佳选择,经过试验和网上资料的查阅,现把实现方式总结一下: 一直是通过自定义Adapter方式,在getView()方法中设置图片的显示 ...
- Zookeeper 在Hadoop中的应用
Zookeeper 简单介绍 Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目.它主要是用来解决分布式应用中常常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集 ...
- js 效果样式大全
设置 滑动图片背景模糊度 <style type='text/css'>/*透明20%*/.opacity-20 {filter:alpha(opacity=20); /*支持IE浏览器的 ...
- BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )
找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...
- eclipse导出doc文档
选中需要导出的项目, 1 点击eclipse上面的Project,选择Generate javadoc..., 2 然后配置 javadoc command,比如我本地的路径为: C:\Program ...
- 转: seajs手册与文档之 -- 模块标识
目录 模块标识 相对标识 顶级标识 普通路径 文件后缀的提示 模块标识 模块标识是一个字符串,用来标识模块.在 require. require.async 等加载函数中,第一个参数都是模块标识.de ...
- Maxicode码
Maxicode的缘起和发展 1980年代晚期,美国知名的UPS(United Parcel Service)快递公司认知到利用机器辨读资讯可有效改善作业效率.提高服务品质,故从1987年开始着手於机 ...