WPF:DataTemplateSelector设置控件不同的样式

简介: 原文 WPF:DataTemplateSelector设置控件不同的样式 最近想实现这么个东西,一个ListBox, 里面的ListBoxItem可能是文本框、下拉框、日期选择控件等等。 很自然的想到了DataTemplateSelector,并且事先定义好各类DataTemplate以显示不同的控件。

原文 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 {  getset; }
         public DataTemplate ComboBoxTemplate {  getset; }
         public DataTemplate DateTimeTemplate {  getset; }

         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>{ " 1 ", " 2 ", " 3 "}, 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>{ " 1 ", " 2 ", " 3 "}, 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,而且实现的方式看上去比较优雅。

目录
相关文章
|
1月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
5月前
|
C#
浅谈WPF之装饰器实现控件锚点
使用过visio的都知道,在绘制流程图时,当选择或鼠标移动到控件时,都会在控件的四周出现锚点,以便于修改大小,移动位置,或连接线等,那此功能是如何实现的呢?在WPF开发中,想要在控件四周实现锚点,可以通过装饰器来实现,今天通过一个简单的小例子,简述如何在WPF开发中,应用装饰器,仅供学习分享使用,如有不足之处,还请指正。
66 1
|
9月前
|
C# Windows
WPF技术之图形系列Polygon控件
WPF Polygon是Windows Presentation Foundation (WPF)框架中的一个标记元素,用于绘制多边形形状。它可以通过设置多个点的坐标来定义多边形的形状,可以绘制任意复杂度的多边形。
474 0
|
9月前
|
C# Windows
WPF技术之RichTextBox控件
WPF RichTextBox是Windows Presentation Foundation (WPF)中提供的一个强大的文本编辑控件,它可以显示富文本格式的文本,支持多种文本处理操作。
354 0
|
5月前
|
前端开发 C# 容器
浅谈WPF之控件拖拽与拖动
使用过office的visio软件画图的小伙伴都知道,画图软件分为两部分,左侧图形库,存放各种图标,右侧是一个画布,将左侧图形库的图标控件拖拽到右侧画布,就会生成一个新的控件,并且可以自由拖动。那如何在WPF程序中,实现类似的功能呢?今天就以一个简单的小例子,简述如何在WPF中实现控件的拖拽和拖动,仅供学习分享使用,如有不足之处,还请指正。
114 2
|
3月前
|
C#
浅谈WPF之样式与资源
WPF通过样式,不仅可以方便的设置控件元素的展示方式,给用户呈现多样化的体验,还简化配置,避免重复设置元素的属性,以达到节约成本,提高工作效率的目的,样式也是资源的一种表现形式。本文以一个简单的小例子,简述如何设置WPF的样式以及资源的应用,仅供学习分享使用,如有不足之处,还请指正。
46 0
|
9月前
|
数据挖掘 数据处理 C#
WPF技术之DataGrid控件
WPF DataGrid是一种可以显示和编辑数据的界面控件。它可以作为表格形式展示数据,支持添加、删除、修改、排序和分组操作。
186 0
|
1月前
|
C# 开发者 C++
一套开源、强大且美观的WPF UI控件库
一套开源、强大且美观的WPF UI控件库
139 0
|
6月前
|
算法 C# UED
浅谈WPF之控件模板和数据模板
WPF不仅支持传统的Windows Forms编程的用户界面和用户体验设计,同时还推出了以模板为核心的新一代设计理念。在WPF中,通过引入模板,将数据和算法的“内容”和“形式”进行解耦。模板主要分为两大类:数据模板【Data Template】和控件模板【Control Template】。
103 8
|
9月前
|
定位技术 C# UED
WPF技术之ScrollViewer控件
WPF ScrollViewer是WPF中常用的一个控件,它提供了滚动视图的功能,可用于显示超出容器可视区域的内容。ScrollViewer通常用于容纳大量内容的控件,以在有限的空间内显示这些内容,并允许用户通过滚动来查看隐藏的部分。
764 0