0

I am trying to add a TextBox (and ComboBox when I get this working) to the default DataGridColumnHeader and have done so like below. This is in an application ResourceDirectory^:

<Style x:Key="DataGridColumnHeaderStyle_TextBox" TargetType="{x:Type DataGridColumnHeader}">
   <Setter Property="VerticalContentAlignment" Value="Center"/>
   <Setter Property="Template">
      <Setter.Value>
         <ControlTemplate TargetType="{x:Type DataGridColumnHeader}">
            <Themes:DataGridHeaderBorder Grid.Row="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" IsClickable="{TemplateBinding CanUserSort}" IsPressed="{TemplateBinding IsPressed}" IsHovered="{TemplateBinding IsMouseOver}" Padding="{TemplateBinding Padding}" SortDirection="{TemplateBinding SortDirection}" SeparatorBrush="{TemplateBinding SeparatorBrush}" SeparatorVisibility="{TemplateBinding SeparatorVisibility}">
               <Grid>
                  <Grid.RowDefinitions>
                     <RowDefinition Height="*"/>
                     <RowDefinition Height="*"/>
                  </Grid.RowDefinitions>
                  <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                  <TextBox Grid.Row="1" Text="" HorizontalAlignment="Stretch" BorderThickness="1" />
                  <Thumb x:Name="PART_LeftHeaderGripper" HorizontalAlignment="Left" Style="{StaticResource ColumnHeaderGripperStyle}"/>
                  <Thumb x:Name="PART_RightHeaderGripper" HorizontalAlignment="Right" Style="{StaticResource ColumnHeaderGripperStyle}"/>
               </Grid>
            </Themes:DataGridHeaderBorder>
         </ControlTemplate>
      </Setter.Value>
   </Setter>
</Style>

In my Window DataGrid I have the following:

<DataGridTextColumn Header="PO Number" Binding="{Binding PO_Number}" HeaderStyle="{DynamicResource DataGridColumnHeaderStyle_TextBox}"/>

This looks the way I want at the moment, and the Header text binds to the ContentPresenter.

Question

How do I set it up so I can bind to the newly add TextBox (or any object for that matter) like this: HeaderTemplate.TextBox.Text="{Binding SomeSubTotalClass}"

<DataGridTextColumn Header="PO Number" HeaderTemplate.TextBox.Text="{Binding SomeSubTotalClass}" Binding="{Binding PO_Number}" HeaderStyle="{DynamicResource DataGridColumnHeaderStyle_TextBox}"/>
thatguy
  • 21,059
  • 6
  • 30
  • 40
Jmyster
  • 965
  • 2
  • 9
  • 27

1 Answers1

1

You can create a set of attached properties for your custom column header.

public static class DataGridHeaderProperties
{
   public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
      "Text", typeof(string), typeof(DataGridHeaderProperties));

   public static string GetText(DependencyObject dependencyObject)
   {
      return (string)dependencyObject.GetValue(TextProperty);
   }

   public static void SetText(DependencyObject dependencyObject, string value)
   {
      dependencyObject.SetValue(TextProperty, value);
   }
}

Then adapt your column header template so that the Text property of the TextBox binds to this attached property that is specified on the corresponding data grid column definition.

<TextBox Grid.Row="1" Text="{Binding Column.(local:DataGridHeaderProperties.Text), RelativeSource={RelativeSource AncestorType={x:Type DataGridColumnHeader}}}" HorizontalAlignment="Stretch" BorderThickness="1" />

Now, set the property on your column definition. Below, there is only a static text for testing, but you can bind the property any way you like.

<DataGridTextColumn Header="PO Number"
                    Binding="{Binding PO_Number}"
                    HeaderStyle="{StaticResource DataGridColumnHeaderStyle_TextBox}"
                    local:DataGridHeaderProperties.Text="My custom text"/>

However, note that columns are not part of the visual tree and do not have a data context to bind to, so you have to use a binding proxy or another mechanism. This is a well known issue for the DataGrid and not the core of this question, but there are already solutions on StackOverflow.

You can extend this solution for any other controls in the column header, like a ComboBox. You just have to add additional attached properties, e.g. for the ItemsSource, SelectedItem and so on, but you should also invest some to refine the concept. It seems odd to put these kinds of controls in column headers. It could harm the usability of your application. Maybe there is a more suitable approach that fits your requirements.

thatguy
  • 21,059
  • 6
  • 30
  • 40
  • Thanks, I'll work on trying to implement this. I really just trying to get a bit more advanced in my learnings of xmal. Conceptually the ComboBox's would be like Excel's Data Filters and the TextBox's are subtotals for the column. I'll report back – Jmyster Dec 08 '20 at 18:18
  • This part work out great. Working on the Binding Proxy now. Different issue so I can accept this one – Jmyster Dec 09 '20 at 05:51