Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically setting the Header text of a Silverlight DataGrid Column

Tags:

silverlight

  <my:DataGridTemplateColumn 
            CanUserResize="False" 
            Width="150" 
            Header="{Binding MeetingName, Source={StaticResource LocStrings}}" 
            SortMemberPath="MeetingName"> 
  </my:DataGridTemplateColumn>

I have the above column in a Silverlight grid control. But it is giving me a XamlParser error because of how I am trying to set the Header property. Has anyone done this before? I want to do this for multiple languages.

Also my syntax for the binding to a resouce is correct because I tried it in a lable outside of the grid.

like image 330
Kyle Avatar asked Sep 30 '08 03:09

Kyle


5 Answers

You can't Bind to Header because it's not a FrameworkElement. You can make the text dynamic by modifying the Header Template like this:

xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
xmlns:dataprimitives="clr-namespace:System.Windows.Controls.Primitives;assembly=System.Windows.Controls.Data"

<data:DataGridTemplateColumn>   
   <data:DataGridTemplateColumn.HeaderStyle>
       <Style TargetType="dataprimitives:DataGridColumnHeader">
          <Setter Property="Template">
             <Setter.Value>
                <ControlTemplate>                                        
                  <TextBlock Text="{Binding MeetingName, Source={StaticResource LocStrings}}" />                
               </ControlTemplate>
            </Setter.Value>
         </Setter>
      </Style>
   </data:DataGridTemplateColumn.HeaderStyle>
</data:DataGridTemplateColumn>
like image 172
Adam Kinney Avatar answered Nov 07 '22 02:11

Adam Kinney


My workaround was to use an attached property to set the binding automatically:

public static class DataGridColumnHelper
{
    public static readonly DependencyProperty HeaderBindingProperty = DependencyProperty.RegisterAttached(
        "HeaderBinding",
        typeof(object),
        typeof(DataGridColumnHelper),
        new PropertyMetadata(null, DataGridColumnHelper.HeaderBinding_PropertyChanged));

    public static object GetHeaderBinding(DependencyObject source)
    {
        return (object)source.GetValue(DataGridColumnHelper.HeaderBindingProperty);
    }

    public static void SetHeaderBinding(DependencyObject target, object value)
    {
        target.SetValue(DataGridColumnHelper.HeaderBindingProperty, value);
    }

    private static void HeaderBinding_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        DataGridColumn column = d as DataGridColumn;

        if (column == null) { return; }

        column.Header = e.NewValue;
    }
}

Then, in the XAML:

<data:DataGridTextColumn util:DataGridColumnHelper.HeaderBinding="{Binding MeetingName, Source={StaticResource LocStrings}}" />
like image 27
RobSiklos Avatar answered Nov 07 '22 01:11

RobSiklos


To keep the visual styling from the original header, use ContentTemplate instead of Template:

<Setter Property="ContentTemplate">
<Setter.Value>
    <DataTemplate>
        <Image Source="<image url goes here>"/>
    </DataTemplate>
</Setter.Value>

like image 11
Lars Holm Jensen Avatar answered Nov 07 '22 02:11

Lars Holm Jensen


Found an interesting workaround that also works with the wpflocalizeaddin.codeplex.com:

Created by Slyi

It uses an IValueConverter:

public class BindingConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value.GetType().Name == "Binding")
        {
            ContentControl cc = new ContentControl();
            cc.SetBinding(ContentControl.ContentProperty, value as Binding);
            return cc;
        }
        else return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {

        return null;
    }
}

And a style for the DataGridColumnHeader

<UserControl.Resources>
    <local:BindingConverter x:Key="BindCon"/>
    <Style x:Key="ColBinding" TargetType="dataprimitives:DataGridColumnHeader" >
        <Setter Property="ContentTemplate" >
            <Setter.Value>
                <DataTemplate>
                    <ContentPresenter Content="{Binding Converter={StaticResource BindCon}}"  />
                </DataTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</UserControl.Resources>

so that you can keep your favorite binding syntax on the Header attribute

<Grid x:Name="LayoutRoot" Background="White">
    <StackPanel>
        <TextBox Text="binding header" x:Name="tbox" />

        <data:DataGrid ItemsSource="{Binding AllPeople,Source={StaticResource folks}}" AutoGenerateColumns="False" ColumnHeaderStyle="{StaticResource ColBinding}"  >
            <data:DataGrid.Columns>
                <data:DataGridTextColumn Binding="{Binding ID}" 

                                         Header="{Binding Text, ElementName=tbox}" />
                <data:DataGridTextColumn Binding="{Binding Name}" 

                                         Header="hello" />
            </data:DataGrid.Columns>
        </data:DataGrid>
    </StackPanel>

</Grid>

http://cid-289eaf995528b9fd.skydrive.live.com/self.aspx/Public/HeaderBinding.zip

like image 2
Rudi Avatar answered Nov 07 '22 02:11

Rudi


It does seem much simpler to set the value in code, as mentioned above:

dg1.Columns[3].Header = SomeDynamicValue;

Avoids using the Setter Property syntax, which in my case seemed to mess up the styling, even though I did try using ContentTemplate as well as Template.

One point I slipped up on was that it is better to use the dg1.Columns[3].Header notation rather than trying to reference a named column.

I had named one of my columns and tried to reference that in code but got null exceptions. Using the Columns[index] method worked well, and I could assign the Header a text string based on localization resources.

like image 2
Steve Avatar answered Nov 07 '22 03:11

Steve