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界面不兼容的代码 会导致可视化设计界面 报错崩溃掉 但是确不 ... 
随机推荐
- Android系统设置— android.provider.Settings
			android.provider.Settings Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS); sta ... 
- 输出1到最大的N位数
			题目:输入数字n,按顺序输出从1最大的n位10进制数.比如输入3,则输出1.2.3一直到最大的3位数即999. 分析:这是一道很有意思的题目.看起来很简单,其实里面却有不少的玄机. 应聘者在解决这个问 ... 
- Laravel后台 + AngularJS前端 的网站构建与维护
			最近维护的报修网站,采用Laravel+AngularJS框架搭建,还有很多东西需要熟悉掌握,现将修复的Bug或添加的功能中值得记录的地方总结如下. 其中,需要注意的问题基本是原因不明且不是太严重的问 ... 
- [置顶] perl脚本中defined,exists和delete关键字的用法和区别
			刚学习perl脚本的时候,喜欢频繁使用defined关键字判断一个hash中某个key是否存在,后来程序出了问题才去perl官方文档查看关于defined关键字的准确使用方法.因此,这里我把perl中 ... 
- 过河(bfs)
			Problem 2188 过河I Accept: 112 Submit: 277 Time Limit: 3000 mSec Memory Limit : 32768 KB Proble ... 
- cocos2d-x新手学习之Helloworld(第三篇)[版本号:cocos2d-x-3.1.1]
			上篇中,能够正常执行NDK中的样例.可是由cocos2d-x生成的项目,不能编译成功.上一篇戳这里: http://blog.csdn.net/xjjjjjjjjjjj/article/details ... 
- 微软正式公布Visual Studio 2013 Update 3 (2013.3) RTM
			 昨天微软的Visual Studio 2013 Update 3(Visual Studio 2013.3)正式公布(RTM)了,做为微软认证金牌合作的葡萄城控件,我们组织力量第一时间进行翻译. ... 
- 如何在自己的Activity中去控制EditText的焦点
			在进入一个Activity时,如果这个Activity中有EditText,则这个EditText会自动获取焦点,然后就会弹出软键盘,这样给用户体验不是很好.所以一般会通过代码控制让EditText不 ... 
- Qt5官方demo分析集11——Qt Quick Particles Examples - Affectors
			在这个系列中的所有文章都可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集10--Qt ... 
- ubuntu下vpn无反应的解决办法
			mv ~/.gconf ~/.gcongbk0 sudo reboot 
