原文 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设置控件不同的样式的更多相关文章

  1. WPF 4 DataGrid 控件(自定义样式篇)

    原文:WPF 4 DataGrid 控件(自定义样式篇)      在<WPF 4 DataGrid 控件(基本功能篇)>中我们已经学习了DataGrid 的基本功能及使用方法.本篇将继续 ...

  2. [转]设置控件全局显示样式appearance proxy

    转自:huifeidexin_1的专栏 appearance是apple在iOS5.0上加的一个协议,它让程序员可以很轻松地改变某控件的全局样式(背景) @selector(appearance) 支 ...

  3. 设置控件全局显示样式 appearance

    iOS5及其以后提供了一个比较强大的工具UIAppearance,我们通过UIAppearance设置一些UI的全局效果,这样就可以很方便的实现UI的自定义效果又能最简单的实现统一界面风格,它提供如下 ...

  4. WPF 定义Lookless控件的默认样式、 OnApplyTemplate 如何使用(实现方式、如何工作的)!

    写的非常详细: 作者地址:https://www.cnblogs.com/atskyline/archive/2012/11/16/2773806.html 参考资料: http://www.code ...

  5. WPF 4 DataGrid 控件(进阶篇一)

    原文:WPF 4 DataGrid 控件(进阶篇一)      上一篇<WPF 4 DataGrid 控件(自定义样式篇)>中,我们掌握了DataGrid 列表头.行表头.行.单元格相关的 ...

  6. WPF 4 DataGrid 控件(进阶篇二)

    原文:WPF 4 DataGrid 控件(进阶篇二)      上一篇<WPF 4 DataGrid 控件(进阶篇一)>中我们通过DataGridTemplateColumn 类自定义编辑 ...

  7. WPF设置控件获取键盘焦点时的样式FocusVisualStyle

    控件获取焦点除了用鼠标外,可以通过键盘来获取,比如Tab键或者方向键等,需要设置控件获取键盘焦点时的样式,可以通过设置FrameworkElemnt.FocusVisualStyle属性, 因为几乎所 ...

  8. WPF自定义分页控件,样式自定义,简单易用

    WPF自定义分页控件 做了许久伸手党,终于有机会贡献一波,搜索一下WPF分页控件,还是多,但是不太通用,主要就是样式问题,这个WPF很好解决,还有一个就是分页控件嘛,只关心几个数字的变动就行了,把页码 ...

  9. WPF Calendar 日历控件 样式自定义

    原文:WPF Calendar 日历控件 样式自定义 粗略的在代码上做了些注释 blend 生成出来的模版 有的时候 会生成 跟 vs ui界面不兼容的代码 会导致可视化设计界面 报错崩溃掉 但是确不 ...

随机推荐

  1. type,isinstance判断一个变量的数据类型

    type,isinstance判断一个变量的数据类型 import types type(x) is types.IntType # 判断是否int 类型 type(x) is types.Strin ...

  2. kinect for windows - 手势识别之一,C++实现

    用C++来实现手势识别是比较困难的,所以在这个例子,我们只实现了握拳和松手的手势识别,其他没有实现. 先上个效果图: 在这个程序里,我们打开了kinect的RGB流,深度流,骨骼数据流和手势识别流.其 ...

  3. Hope

    透过希望的窗棂,在阴霾的罅隙里也可以寻找阳光,看到未来的春暖花开. ——forever97

  4. Candy Sharing Game(模拟搜索)

    Candy Sharing Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Other ...

  5. UC/0S2之基础总结

    堆栈,就是在存储器中按数据“后进先出(LIFO)[类比杯子]”的原则组织的连续存储空间,为了满足任务切换和响应中断保存CPU寄存器中的内容及存储任务私有数据的需要,每个任务都应该配有自己的堆栈, 注意 ...

  6. LeetCode 链表的插入排序

    Sort a linked list using insertion sort 创建一个新的链表,将旧链表的节点插入到正确的位置 package cn.edu.algorithm.huawei; pu ...

  7. Longest Substring Without Repeating Characters - 哈希与双指针

    题意很简单,就是寻找一个字符串中连续的最长包含不同字母的子串. 其实用最朴素的方法,从当前字符开始寻找,找到以当前字符开头的最长子串.这个方法猛一看是个n方的算法,但是要注意到由于字符数目的限制,其实 ...

  8. Java中常见的几种类型转换

    public class Main { public static void main(String[] args){ //Int型数字转换成字符串 int num1=123456; //方法1 St ...

  9. Clob对象转为字符串

    项目中遇到一个问题,对方公司把打印好的报表数据存到数据库中,实际上就是把html存在Oracle中,然后需要我们在社保系统里进行查询. 但是他们把数据存放在B数据库,而我们的社保系统用的数据库是B.A ...

  10. js的初始化

    在项目中遇到了类似于这样的js, myinit.js文件: var wyl_01 = { tip : function(msg){ alert('i am a tip,msg:'+msg); }, t ...