C# WPF DataGrid 数据绑定时的单元格编辑类型模板

DataGrid的DataSource绑定的ObservableCollection<UserType>属性如果在运行中会发生变动,则不能在xaml手动定义Columns,否则当该属性发生变动时,UI不会随之更新,需要使用以下方法来实现单元格编辑类型的替换:

一、

设置DataGrid的AutoGenerateColumns为True,自动生成列的同时在AutoGeneratingColumn事件的方法将e.Column属性替换为DataGridTemplateColumn实例。

xaml:

复制代码
    <DataGrid ItemsSource="{Binding DgvItemSource}" AutoGenerateColumns="True" AutoGeneratingColumn="DataGridAutoGeneratingColumn" />

cs:

复制代码
      private void DataGridAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
      {
          DataGrid dataGrid = sender as DataGrid;
          string columnName = e.PropertyName;
          DataGridTemplateColumn column = new DataGridTemplateColumn();
          e.Column = column;
          
      }

在定义的DataGridTemplateColumn实例的CellTemplate和CellEditingTemplate属性赋值新的DataTemplate实例, 创建FrameworkElementFactory实例给DataTemplate实例的VisualTree赋值;FrameworkElementFactory实例可以使用SetBinding方法绑定数据源,使用SetValue方法指定模板,模板可定义在App.xaml里,通过Application.Current.FindResource方法获取。

复制代码
 DataGridTemplateColumn column = new DataGridTemplateColumn();
 DgvCellDataTemplateSelector cellTemplate = Application.Current.FindResource("DgvCellTemplateSelector") as DgvCellDataTemplateSelector;
 DgvCellDataTemplateSelector cellEditingTemplate = Application.Current.FindResource("DgvCellEditingTemplateSelector") as DgvCellDataTemplateSelector;
 
 column.Header = columnName;

 column.CellTemplate = new DataTemplate();
 FrameworkElementFactory factory = new FrameworkElementFactory(typeof(ContentPresenter));
 factory.SetBinding(ContentPresenter.ContentProperty, new Binding(columnName));
 factory.SetValue(ContentPresenter.ContentTemplateSelectorProperty, cellTemplate);
 column.CellTemplate.VisualTree = factory;

 column.CellEditingTemplate = new DataTemplate();
 FrameworkElementFactory editingfactory = new FrameworkElementFactory(typeof(ContentPresenter));
 editingfactory.SetBinding(ContentPresenter.ContentProperty, new Binding(columnName));
 editingfactory.SetValue(ContentPresenter.ContentTemplateSelectorProperty, cellEditingTemplate);
 column.CellEditingTemplate.VisualTree = editingfactory;

二、

编写模板选择器,DgvCellDataTemplateSelector是个实现了DataTemplateSelector接口的类型:

复制代码
public class TemplateMapping : List<TemplateMappingItem>
{

}

public class TemplateMappingItem
{
    public object Value { get; set; }
    public DataTemplate Template { get; set; }
}

public class DgvCellDataTemplateSelector : DataTemplateSelector
{
    public DataTemplate DefaultTemplate { get; set; }
    public TemplateMapping TemplateMap { get; set; }

    public override DataTemplate SelectTemplate(object item, DependencyObject container)
    {
        if (item == null) return DefaultTemplate;
        if (item is DataBase data)
        {
            if (data == null) return DefaultTemplate;
            return TemplateMap?.Find(m => Equals(m.Value, data.dataType))?.Template ?? DefaultTemplate;
        }
        return DefaultTemplate;

    }
}

三、

定义模板和创建全局模板选择器实例,app.xaml:

复制代码
<Application x:Class="TestSystem.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:utilities="clr-namespace:TestSystem.Utilities"
             xmlns:ut="clr-namespace:TestSystem.UserType"
             StartupUri="View/MainWindow.xaml">
    <Application.Resources>
        <ResourceDictionary>

            <DataTemplate x:Key="TemplateDefault">
                <TextBlock Text="{Binding Data.Value}" />
            </DataTemplate>

            
            <utilities:TemplateMapping x:Key="DgvCellEditingDataTypeTemplateMap">
                <utilities:TemplateMappingItem 
            Value="{x:Static ut:ControlUserType+DataType.Readonly}" 
            Template="{StaticResource TemplateDefault}" />
            </utilities:TemplateMapping>
          

            <utilities:DgvCellDataTemplateSelector 
        x:Key="DgvCellEditingTemplateSelector"
        DefaultTemplate="{StaticResource TemplateDefault}"
        TemplateMap="{StaticResource DgvCellEditingDataTypeTemplateMap}" />

            

        </ResourceDictionary>
    </Application.Resources>
</Application>

四、

创建存放数据的UserType。

复制代码
  public enum DataType
  {
      Readonly
  }
  public abstract class DataBase : NotifyPropertyChanged,ICloneable
  {
      private object value;
      public DataType dataType;
      public object Value { get { return value; } set { this.value = value;OnPropertyChanged(nameof(Value)); } }

      public DataBase() { }

      public abstract object Clone();

  }
    public class ReadOnlyData : DataBase
   {
       public ReadOnlyData()
       {
           dataType = DataType.Readonly;
       }
       public override object Clone()
       {
           var clone = new ReadOnlyData
           {
               Value = this.Value
           };

           return clone;
       }
   }
相关推荐
MediaTea15 分钟前
Python 第三方库:matplotlib(科学绘图与数据可视化)
开发语言·python·信息可视化·matplotlib
JS.Huang30 分钟前
【JavaScript】原生函数
开发语言·javascript·ecmascript
CoderCodingNo1 小时前
【GESP】C++五级考试大纲知识点梳理, (5) 算法复杂度估算(多项式、对数)
开发语言·c++·算法
星河队长1 小时前
VS创建C++动态库和C#访问过程
java·c++·c#
ftpeak2 小时前
JavaScript性能优化实战
开发语言·javascript·性能优化
William_cl2 小时前
【C# MVC 前置】异步编程 async/await:从 “卡界面” 到 “秒响应” 的 Action 优化指南(附微软官方避坑清单)
microsoft·c#·mvc
一个很帅的帅哥2 小时前
JavaScript事件循环
开发语言·前端·javascript
驰羽2 小时前
[GO]gin框架:ShouldBindJSON与其他常见绑定方法
开发语言·golang·gin
程序员大雄学编程2 小时前
「用Python来学微积分」5. 曲线的极坐标方程
开发语言·python·微积分
yong99903 小时前
C#驱动斑马打印机实现包装自动打印
java·数据库·c#