keelerjr12
keelerjr12

Reputation: 1903

Bind Datagrid column header to DatePicker selection

I'm trying to bind the datagrid column header to the date selected in the datepicker. For example:

+--------------------------------------+
|               1/29/2018              |
+--------------------------------------+
|1/29/2018|1/30/2018|1/31/2018|2/1/2018|
+--------------------------------------+
|Available|Leave    |Available|Leave   |
|Leave    |Leave    |Available|Leave   |
+--------------------------------------+

using:

<StackPanel>
  <DatePicker HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top" Text="{Binding SelectedDate}"/>
  <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding UserScheduleViewModels}">
    <DataGrid.Columns>
      <DataGridTextColumn Header="Name" />
      <DataGridTextColumn Header="{Binding SelectedDate}" />
    </DataGrid.Columns>
  </DataGrid>
</StackPanel>

However, my first column is showing Name like it should, but the date for the 2nd column is just blank. Any ideas?

Upvotes: 0

Views: 109

Answers (2)

Mike Strobel
Mike Strobel

Reputation: 25623

The data context does not pass through the DataGrid.Columns collection, so placing a Binding on a column definition won't work without some added indirection.

<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding UserScheduleViewModels}">
  <DataGrid.Resources>
    <local:BindingProxy x:Key="proxy" Value="{Binding SelectedDate}" />
  </DataGrid.Resources>
  <DataGrid.Columns>
    <DataGridTextColumn Header="Name" />
    <DataGridTextColumn Header="{Binding Source={StaticResource proxy}, Path=Value}" />
  </DataGrid.Columns>
</DataGrid>

BindingProxy is a utility class that you can use to work around situations like this. The idea is that you place one in a resource dictionary and use it as an intermediary. You bind its Value to the otherwise inaccessible data you need, then reference it as the binding Source from outside of the inheritance context. As with all static resources, the BindingProxy resource declaration must appear before the Binding that points to it (in Xaml parse order).

public class BindingProxy : Freezable
{
    public static readonly DependencyProperty ValueProperty =
        DependencyProperty.Register(
            "Value",
            typeof(object),
            typeof(BindingProxy),
            new PropertyMetadata(default(object)));

    public object Value
    {
        get { return (object)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }

    protected override Freezable CreateInstanceCore()
    {
        return new BindingProxy();
    }
}

Although using a proxy object may seem less than ideal, it has the benefit of working in most situations where you need to use bindings from outside the normal inheritance context. Learning this approach (and why it works) may help you in similar situations in the future. For example, this will come in handy if you ever need bindings inside of a ToolTip.

Upvotes: 1

cuongtd
cuongtd

Reputation: 3182

<StackPanel>
  <DatePicker HorizontalAlignment="Center" Margin="0,0,0,0" VerticalAlignment="Top" Text="{Binding SelectedDate}"/>
   <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding UserScheduleViewModels}">
    <DataGrid.Columns>
      <DataGridTextColumn Header="Name" />
       <DataGridTextColumn>
         <DataGridTextColumn.HeaderTemplate>
           <DataTemplate>
             <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=DataGrid},Path=DataContext.SelectedDate}"/>
           </DataTemplate>
         </DataGridTextColumn.HeaderTemplate>
      </DataGridTextColumn>
    </DataGrid.Columns>
  </DataGrid>
</StackPanel>

Upvotes: 1

Related Questions