WPF DataGrid with dynamic cols
Contents
X
MainWindow.xaml
<Window x:Class="ControlsTestProject.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:ControlsTestProject"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:TableVm x:Key="ViewModel"/>
</Window.Resources>
<StackPanel DataContext="{Binding Source={StaticResource ViewModel}}">
<local:MyTable />
</StackPanel>
</Window>
MyTable.xaml
<UserControl x:Class="ControlsTestProject.MyTable"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ControlsTestProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<DataGrid x:Name="MyDataGrid"
ItemsSource="{Binding Path=Rows}"
AutoGenerateColumns="False"
CanUserAddRows="False">
</DataGrid>
</Grid>
</UserControl>
MyTable.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
namespace ControlsTestProject
{
/// <summary>
/// Interaction logic for MyTable.xaml
/// </summary>
public partial class MyTable : UserControl
{
public MyTable()
{
InitializeComponent();
Loaded += new RoutedEventHandler(MyControl_Loaded);
}
private void GenerateColumns()
{
}
void MyControl_Loaded(object sender, RoutedEventArgs e)
{
TableVm tableVm = (TableVm) MyDataGrid.DataContext;
int numCols = tableVm.NumCols();
for(int i=0; i<numCols; i++)
{
DataGridTemplateColumn template = CreateTemplatedColumn(i);
MyDataGrid.Columns.Add(template);
}
}
private DataGridTemplateColumn CreateTemplatedColumn(int col)
{
DataGridTemplateColumn result = new DataGridTemplateColumn();
FrameworkElementFactory factory = new FrameworkElementFactory(typeof(MyCellPresenter));
Binding binding = new Binding();
string bindingPath = string.Format(@"Cells[{0}]", col);
binding.Path = new PropertyPath(bindingPath);
factory.SetBinding(DataContextProperty, binding);
result.CellTemplate = new DataTemplate { VisualTree = factory };
return result;
}
}
}
MyCellPresenter.xaml
<UserControl x:Class="ControlsTestProject.MyCellPresenter"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ControlsTestProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<UserControl.Resources>
<DataTemplate x:Key="Template1">
<local:MyControl1/>
</DataTemplate>
<DataTemplate x:Key="Template2">
<local:MyControl2/>
</DataTemplate>
<local:MyTemplateSelector x:Key="TemplateSelector"/>
</UserControl.Resources>
<StackPanel Background="Yellow">
<Label Foreground="Black"
Content="{Binding}"
ContentTemplateSelector="{StaticResource TemplateSelector}">
</Label>
</StackPanel>
</UserControl>
MyControl1.xaml
<UserControl x:Class="ControlsTestProject.MyControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ControlsTestProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TextBlock Text="{Binding Path=Text}"
PreviewMouseLeftButtonDown="TextBlock_PreviewMouseLeftButtonDown">
<TextBlock.Background>
<SolidColorBrush>
<SolidColorBrush.Color>
Aquamarine
</SolidColorBrush.Color>
</SolidColorBrush>
</TextBlock.Background>
</TextBlock>
</Grid>
</UserControl>
MyControl2.xaml
<UserControl x:Class="ControlsTestProject.MyControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:ControlsTestProject"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
d:DataContext="{d:DesignInstance Type=local:MyItemVm}">
<StackPanel Background="Green">
<TextBox Text="{Binding Path=Text}"/>
</StackPanel>
</UserControl>
MyTemplateSelector.cs
using System.Windows;
using System.Windows.Controls;
namespace ControlsTestProject
{
public class MyTemplateSelector : DataTemplateSelector
{
public MyTemplateSelector()
{
}
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
TableCellVm cell = item as TableCellVm;
if (cell != null && cell != null)
{
string resourceKey = cell.TemplateKey;
DataTemplate result = element.FindResource(resourceKey) as DataTemplate;
return result;
}
return null;
}
}
}
TableVm.cs
using System.Collections.ObjectModel;
using System.Linq;
namespace ControlsTestProject
{
public class TableVm
{
public TableVm()
{
Rows = new ObservableCollection<TableRowVm>();
for(int i=0; i<5; i++)
{
TableRowVm row = new TableRowVm();
Rows.Add(row);
}
}
public int NumCols()
{
return Rows.Max(x => x.Cells.Count());
}
public ObservableCollection<TableRowVm> Rows { get; private set; }
}
}
TableRowVm.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ControlsTestProject
{
public class TableRowVm
{
public TableRowVm()
{
Cells = new ObservableCollection<TableCellVm>();
for(int i=0; i<10; i++)
{
TableCellVm cell = new TableCellVm(i % 2 == 0 ? "Template1" : "Template2");
Cells.Add(cell);
}
}
public ObservableCollection<TableCellVm> Cells { get; private set; }
}
}
TableCellVm.cs
namespace ControlsTestProject
{
public class TableCellVm
{
public TableCellVm(string templateKey)
{
this.TemplateKey = templateKey;
this.Text = templateKey;
}
private string _text;
public string Text
{
get
{
return _text;
}
set
{
_text = value;
}
}
private string _templateKey;
public string TemplateKey {
get { return _templateKey; }
set { _templateKey = value; }
}
}
}