原文 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. 在systemd(CentOS7)自启动zookeeper

    zookeeper的自启动脚本,如果是 sysV 模式(CeontOS6或以下版本),可以直接使用下载版本中的 src 目录下对应的 sysV 自启动包,再chkconfig即可.老方法,简单,就不说 ...

  2. 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 ...

  3. DBV-00111: OCI failure (3722) (ORA-01002: fetch out of sequence解决

    在使用DBV检测segment的时候出现 DBV-00111: OCI failure (3722) (ORA-01002: fetch out of sequence)错误: 在寻找原因过程中发现相 ...

  4. Android中GridView的使用——使用自带的SimpleAdapter(简单适配器)

    GridView一直是一个系统登录后以九宫格方式展现功能子模块的最佳选择,经过试验和网上资料的查阅,现把实现方式总结一下: 一直是通过自定义Adapter方式,在getView()方法中设置图片的显示 ...

  5. Zookeeper 在Hadoop中的应用

    Zookeeper 简单介绍 Zookeeper 分布式服务框架是 Apache Hadoop 的一个子项目.它主要是用来解决分布式应用中常常遇到的一些数据管理问题,如:统一命名服务.状态同步服务.集 ...

  6. js 效果样式大全

    设置 滑动图片背景模糊度 <style type='text/css'>/*透明20%*/.opacity-20 {filter:alpha(opacity=20); /*支持IE浏览器的 ...

  7. BZOJ 1880: [Sdoi2009]Elaxia的路线( 最短路 + dp )

    找出同时在他们最短路上的边(dijkstra + dfs), 组成新图, 新图DAG的最长路就是答案...因为两人走同一条路但是不同方向也可以, 所以要把一种一个的s,t换一下再更新一次答案 ---- ...

  8. eclipse导出doc文档

    选中需要导出的项目, 1 点击eclipse上面的Project,选择Generate javadoc..., 2 然后配置 javadoc command,比如我本地的路径为: C:\Program ...

  9. 转: seajs手册与文档之 -- 模块标识

    目录 模块标识 相对标识 顶级标识 普通路径 文件后缀的提示 模块标识 模块标识是一个字符串,用来标识模块.在 require. require.async 等加载函数中,第一个参数都是模块标识.de ...

  10. Maxicode码

    Maxicode的缘起和发展 1980年代晚期,美国知名的UPS(United Parcel Service)快递公司认知到利用机器辨读资讯可有效改善作业效率.提高服务品质,故从1987年开始着手於机 ...