title: WPF: how to convert a DataGridTextColumn to a DataGridCheckBoxColumn and vice versa
body: <p>Using WPF and Xaml, i have defined a data grid with a few columns.
  One of these columns i want displayed as a CheckBoxColumn (check boxes in celss) or a TextColumn (text only in cells) depending on a specific state of my application which is toggleable at will by the user.</p>
  
  <p>Assuming my initial column type is TextColumn,
  I believe I can do this by creating a new instance of the CheckBoxColumn type, giving it some style and setters, and then saving a reference to the original text column. I would then reassign the dataGrid.Column[x] column back to the saved reference on the un-toggle event.</p>
  
  <p>I was wondering if there was a way I could simply start with a CheckBoxColumn and then change the Column's style somehow on the "text" toggle event for it to render the data as text ("True" or "False") even though it's a CheckBoxColumn. This way I do not have create a new Column instance and save/restore the original. </p>
  
  <p>Any thoughts?</p>
  
  <p>Edit: 
  Here is code that demonstrates what I'd like to do regarding the conversion of the DataGrid Column type. What I don't want to do is save the old column and then swap with the new on the toggle. See method UpdateForTextMode. The ultimate goal here is to be able to grab whole rows in raw text and paste them back into the grid as new whole rows, or into a spreadsheet. I'd be surprised if there was not some way I could switch the visual rendering out on the fly without having to swap whole column instances in the code behind.
  I've look at column templates, but I have no idea how to change the display template depending on my app state. I thought they were used mainly for edit/non edit views. Iy my case, both text and non text mode should allow editing, whether you click a checkbox or type in the word "True".</p>
  
  <p>App.xaml</p>
  
  <pre><code>&lt;Application x:Class="WpfApplication1.App"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           StartupUri="MainWindow.xaml"&gt;
  &lt;Application.Resources&gt;
      &lt;Style TargetType="{x:Type DataGridCell}" x:Key="DataGridCenterCellStyle"&gt;
          &lt;Setter Property="Template"&gt;
              &lt;Setter.Value&gt;
                  &lt;ControlTemplate TargetType="{x:Type DataGridCell}"&gt;
                      &lt;Grid Background="{TemplateBinding Background}"&gt;
                          &lt;ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/&gt;
                      &lt;/Grid&gt;
                  &lt;/ControlTemplate&gt;
              &lt;/Setter.Value&gt;
          &lt;/Setter&gt;
      &lt;/Style&gt;
      &lt;Style TargetType="{x:Type DataGridColumnHeader}" x:Key="CustomDataGridCenterHeader"&gt;
          &lt;Setter Property="VerticalContentAlignment" Value="Center" /&gt;
          &lt;Setter Property="HorizontalContentAlignment" Value="Center" /&gt;
          &lt;Setter Property="FontWeight" Value="Bold"/&gt;
      &lt;/Style&gt;        
      &lt;Style x:Key="ColumnHeaderGripperStyle" TargetType="{x:Type Thumb}"&gt;
          &lt;Setter Property="Width" Value="8" /&gt;
          &lt;Setter Property="Background" Value="Transparent" /&gt;
          &lt;Setter Property="Cursor"
        Value="SizeWE" /&gt;
          &lt;Setter Property="Template"&gt;
              &lt;Setter.Value&gt;
                  &lt;ControlTemplate TargetType="{x:Type Thumb}"&gt;
                      &lt;Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" /&gt;
                  &lt;/ControlTemplate&gt;
              &lt;/Setter.Value&gt;
          &lt;/Setter&gt;
      &lt;/Style&gt;
      &lt;!--Style and template for the DataGridColumnHeader.--&gt;
      &lt;Style TargetType="{x:Type DataGridColumnHeader}" x:Key="DataGridColumnHeader"&gt;
          &lt;Setter Property="VerticalContentAlignment" Value="Center" /&gt;
          &lt;Setter Property="Template"&gt;
              &lt;Setter.Value&gt;
                  &lt;ControlTemplate TargetType="{x:Type DataGridColumnHeader}"&gt;
                      &lt;Grid&gt;
                          &lt;Border x:Name="columnHeaderBorder" BorderThickness="1" Padding="3,0,3,0"&gt;
                              &lt;Border.BorderBrush&gt;
                                  &lt;LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"&gt;
                                      &lt;GradientStop Color="{DynamicResource BorderLightColor}" Offset="0" /&gt;
                                      &lt;GradientStop Color="{DynamicResource BorderDarkColor}" Offset="1" /&gt;
                                  &lt;/LinearGradientBrush&gt;
                              &lt;/Border.BorderBrush&gt;
                              &lt;Border.Background&gt;
                                  &lt;LinearGradientBrush EndPoint="0.5,1"
                                 StartPoint="0.5,0"&gt;
                                      &lt;GradientStop Color="{DynamicResource ControlLightColor}" Offset="0" /&gt;
                                      &lt;GradientStop Color="{DynamicResource ControlMediumColor}" Offset="1" /&gt;
                                  &lt;/LinearGradientBrush&gt;
                              &lt;/Border.Background&gt;
                              &lt;ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                            SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                            VerticalAlignment="{TemplateBinding VerticalContentAlignment}" /&gt;
                          &lt;/Border&gt;
  
                          &lt;Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}" /&gt;
                          &lt;Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}" /&gt;
                      &lt;/Grid&gt;
                  &lt;/ControlTemplate&gt;
              &lt;/Setter.Value&gt;
          &lt;/Setter&gt;
          &lt;Setter Property="Background"&gt;
              &lt;Setter.Value&gt;
                  &lt;LinearGradientBrush EndPoint="0.5,1"
                         StartPoint="0.5,0"&gt;
                      &lt;GradientStop Color="{DynamicResource ControlLightColor}"
                    Offset="0" /&gt;
                      &lt;GradientStop Color="{DynamicResource ControlMediumColor}"
                    Offset="1" /&gt;
                  &lt;/LinearGradientBrush&gt;
              &lt;/Setter.Value&gt;
          &lt;/Setter&gt;
      &lt;/Style&gt;
  
  &lt;/Application.Resources&gt;
  </code></pre>
  
  <p></p>
  
  <p>App.xaml.cs</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Configuration;
  using System.Data;
  using System.Linq;
  using System.Threading.Tasks;
  using System.Windows;
  
  namespace WpfApplication1
  {
      /// &lt;summary&gt;
      /// Interaction logic for App.xaml
      /// &lt;/summary&gt;
      public partial class App : Application
      {
          private static App instance = null;
  
          public static App GetInstance()
          {
              return instance;
          }
  
          public App()
          {
              instance = this;
          }
  
      }
  }
  </code></pre>
  
  <p>DataViewModel.cs</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Collections.ObjectModel;
  namespace WpfApplication1
  {
      public class Data
      {
          string name = null;
  
          public string Name
          {
              get { return name; }
              set { name = value; }
          }
                  bool reserved = false;
  
          public bool Reserved
          {
              get { return reserved; }
              set { reserved = value; }
          }
  
          public Data(string name, bool isReserved)
          {
              this.name = name;
              reserved = isReserved;
          }
      }
  
      public class DataViewModel
      {
          private List&lt;Data&gt; datas = null;
          private ObservableCollection&lt;DataViewModel&gt; rows = null;
  
          public Data Data { get; set; }
  
          public DataViewModel(List&lt;Data&gt; datas, ObservableCollection&lt;DataViewModel&gt; rows, Data data)
          {
              this.datas = datas;
              this.rows = rows;
              Data = data;
          }
  
          public DataViewModel(List&lt;Data&gt; datas, ObservableCollection&lt;DataViewModel&gt; rows)
          {
              this.datas = datas;
              this.rows = rows;
              Data = null;
          }
  
          public void ConvertLastRow()
          {
              if (Data == null)
              {
                  Data = new Data("", false);
                  datas.Add(Data);
                  rows.Add(new DataViewModel(datas, rows));
              }
          }
  
          public int ID
          {
              get { return rows.IndexOf(this); }
          }
  
          public string Name
          {
              get
              {
                  if (Data == null)
                      return string.Empty;
                  return Data.Name;
              }
              set
              {
                  ConvertLastRow();
                  Data.Name = value;
  
              }
          }
  
          public bool Reserved
          {
              get
              {
                  if (Data == null)
                      return false;
  
                  return Data.Reserved;
              }
              set
              {
                  ConvertLastRow();
                  Data.Reserved = value;
              }
          }
  
      }
  }
  </code></pre>
  
  <p>MainWindow.xaml</p>
  
  <pre><code>&lt;Window x:Class="WpfApplication1.MainWindow"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          Title="MainWindow" Height="350" Width="525"&gt;
      &lt;Grid&gt;
          &lt;Grid.RowDefinitions&gt;
              &lt;RowDefinition Height="25"/&gt;
              &lt;RowDefinition Height="25"/&gt;
              &lt;RowDefinition Height="*"/&gt;
          &lt;/Grid.RowDefinitions&gt;
          &lt;Grid.ColumnDefinitions&gt;
              &lt;ColumnDefinition Width="130"/&gt;
              &lt;ColumnDefinition Width="*"/&gt;
              &lt;ColumnDefinition Width="90"/&gt;
          &lt;/Grid.ColumnDefinitions&gt;
          &lt;Label Grid.Column="0" Grid.Row="1" Content="Enable Text Mode"  /&gt;
          &lt;CheckBox Grid.Column="1" Grid.Row="1" x:Name="textModeCheckBox" Checked="ToggleTextMode" Unchecked="ToggleTextMode"/&gt;
          &lt;DataGrid Grid.Column="1" Grid.Row="2" x:Name="fooGrid" ItemsSource="{Binding Rows}" AutoGenerateColumns="False" CanUserResizeRows="False" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible"&gt;
              &lt;DataGrid.Columns &gt;
                  &lt;DataGridTextColumn x:Name ="indexColumn" Binding="{Binding Path=ID}" Width="*" Header="Index" IsReadOnly="True"/&gt;
                  &lt;DataGridTextColumn x:Name ="nameColumn" Binding="{Binding Path=Name}" Width="*" Header="Name"/&gt;
                  &lt;DataGridTextColumn x:Name="reservedColumn" Binding="{Binding Path=Reserved}" Width="*" Header="Reserved"/&gt;
              &lt;/DataGrid.Columns&gt;
          &lt;/DataGrid&gt;
      &lt;/Grid&gt;
  &lt;/Window&gt;
  </code></pre>
  
  <p>MainWindow.xaml.cs</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;
  using System.Windows.Shapes;
  using System.Collections.ObjectModel;
  using System.Windows.Controls.Primitives;
  namespace WpfApplication1
  {
      /// &lt;summary&gt;
      /// Interaction logic for MainWindow.xaml
      /// &lt;/summary&gt;
      public partial class MainWindow : Window
      {
          private List&lt;Data&gt; datas = null;
          private ObservableCollection&lt;DataViewModel&gt; rows = new ObservableCollection&lt;DataViewModel&gt;();
          private bool textMode = false;
          private DataGridColumn savedReservedColumn = null;
          public bool TextMode
          {
              get { return textMode; }
              set { textMode = value; }
          }
  
          public ObservableCollection&lt;DataViewModel&gt; Rows
          {
              get { return rows; }
              set { rows = value; }
          }
  
          public MainWindow()
          {
              InitializeComponent();
              this.datas = new List&lt;Data&gt;();
              datas.Add(new Data("foo1", false));
              datas.Add(new Data("foo2", true));
              this.DataContext = this;
              savedReservedColumn = reservedColumn;
              UpdateRows();
              UpdateForTextMode();
          }
  
          public static void UpdateRows(ContentControl userControl)
          {
              (userControl as MainWindow).UpdateRows();
          }
          private void UpdateRows(List&lt;Data&gt; datas)
          {
              rows.Clear();
  
              this.datas = datas;
  
              if (this.datas == null)
                  return;
  
              foreach (Data data in datas)
              {
                  rows.Add(new DataViewModel(datas, rows, data));
              }
  
              rows.Add(new DataViewModel(datas, rows));
          }
          private void UpdateRows()
          {
              UpdateRows(datas);
          }
          public void UpdateForTextMode()
          {
              // If not text mode
              if (!textMode)
              {
                  //Convert textColumn to a CheckBoxColumn
                  DataGridColumn t  = InitCheckBoxCell(savedReservedColumn as DataGridTextColumn);
                  fooGrid.Columns[2] = t;
              }
              // If text mode
              else if (fooGrid.Columns[2] != savedReservedColumn)
              {
                  // Put Hashed from XAML
                  fooGrid.Columns[2] = savedReservedColumn as DataGridTextColumn;
              }
          }
  
          public static DataGridColumn InitCheckBoxCell(DataGridTextColumn originalColumn)
          {
              // Create the Column
              DataGridCheckBoxColumn templateColumn = new DataGridCheckBoxColumn();
  
              // Create a header style and set it in the column
              templateColumn.CellStyle = new Style(typeof(DataGridCell));
  
              MouseButtonEventHandler handler = PreviewMouseLeftButtonDownDataGridCell;
              SetStyleSetterEvent(templateColumn.CellStyle, ContentControl.PreviewMouseLeftButtonDownEvent, handler);
  
              SetterBaseCollection defaultSetters = (App.GetInstance().Resources["DataGridCenterCellStyle"] as Style).Setters;
              foreach (Setter setter in defaultSetters)
                  SetStyleSetterProperty(templateColumn.CellStyle, setter.Property, setter.Value);
  
              // Create the header
              templateColumn.Binding = originalColumn.Binding;
              templateColumn.Header = originalColumn.Header;
              templateColumn.Width = originalColumn.Width;
  
              templateColumn.HeaderStyle = MergeStyles(App.GetInstance().Resources["DataGridColumnHeader"] as Style, templateColumn.HeaderStyle, typeof(DataGridColumnHeader));
              templateColumn.HeaderStyle = MergeStyles(App.GetInstance().Resources["CustomDataGridCenterHeader"] as Style, templateColumn.HeaderStyle, typeof(DataGridColumnHeader));
  
              return templateColumn;
          }
  
          public static void PreviewMouseLeftButtonDownDataGridCell(object sender, MouseButtonEventArgs e)
          {
              DataGridCell cell = sender as DataGridCell;
              if (cell != null &amp;&amp; !cell.IsEditing &amp;&amp; !cell.IsReadOnly)
              {
                  if (!cell.IsFocused)
                  {
                      cell.Focus();
                  }
                  DataGrid dataGrid = FindParent&lt;DataGrid&gt;(cell);
                  if (dataGrid != null)
                  {
                      if (dataGrid.SelectionUnit != DataGridSelectionUnit.FullRow)
                      {
                          if (!cell.IsSelected)
                              cell.IsSelected = true;
                      }
                      else
                      {
                          DataGridRow row = FindParent&lt;DataGridRow&gt;(cell);
                          if (row != null &amp;&amp; !row.IsSelected)
                          {
                              row.IsSelected = true;
                          }
                      }
                  }
              }
          }
  
          public static T FindParent&lt;T&gt;(UIElement element) where T : UIElement
          {
              UIElement parent = element;
              while (parent != null)
              {
                  T correctlyTyped = parent as T;
                  if (correctlyTyped != null)
                  {
                      return correctlyTyped;
                  }
  
                  parent = VisualTreeHelper.GetParent(parent) as UIElement;
              }
              return null;
          }
  
          public static Style MergeStyles(Style srcStyle, Style dstStyle, Type type)
          {
              // If no header style was created in the XAML
              if (dstStyle == null)
                  // Create a header style and set it in the column
                  dstStyle = new Style(type);
  
              SetterBaseCollection defaultSetters = srcStyle.Setters;
              foreach (Setter setter in defaultSetters)
              {
                  SetStyleSetterProperty(dstStyle, setter.Property, setter.Value);
              }
  
              return dstStyle;
          }
  
          public static void SetStyleSetterProperty(Style style, DependencyProperty property, object value)
          {
              // Iterate through all the configured header styles
              bool found = false;
              foreach (SetterBase setterBase in style.Setters)
              {
                  if (setterBase is Setter)
                  {
                      Setter setter = (setterBase as Setter);
  
                      if (setter.Property.Name.Equals(property.Name))
                      {
                          setter.Value = value;
                          found = true;
                      }
                  }
              }
              if (!found)
                  style.Setters.Add(new Setter(property, value));
          }
  
          public static void SetStyleSetterEvent(Style style, RoutedEvent routedEvent, MouseButtonEventHandler handler)
          {
              // Iterate through all the configured header styles
              bool found = false;
              foreach (SetterBase setterBase in style.Setters)
              {
                  if (setterBase is EventSetter)
                  {
                      EventSetter eventSetter = (setterBase as EventSetter);
  
                      if (eventSetter.Event.Equals(routedEvent))
                      {
                          eventSetter.Handler = handler;
                      }
                  }
              }
              if (!found)
                  style.Setters.Add(new EventSetter(routedEvent, (Delegate)handler));
          }
  
          private void ToggleTextMode(object sender, RoutedEventArgs e)
          {
              textMode = !textMode;
              UpdateRows();
              UpdateForTextMode();
          }
      }
  }
  </code></pre>