WPF DataGrid with dynamic cols

From no name for this wiki
Jump to: navigation, search

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; }
        }
    }
}