web-dev-qa-db-fra.com

Définition dynamique du texte d'en-tête d'une colonne Silverlight DataGrid

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

J'ai la colonne ci-dessus dans un contrôle de grille Silverlight. Mais il me donne une erreur XamlParser en raison de la façon dont je tente de définir la propriété Header. Est-ce que quelqu'un a déjà fait ça? Je veux le faire pour plusieurs langues.

De plus, ma syntaxe pour la liaison à une ressource est correcte car je l'ai essayée dans une étiquette en dehors de la grille.

29
Kyle

Vous ne pouvez pas vous lier à Header car ce n'est pas un FrameworkElement. Vous pouvez rendre le texte dynamique en modifiant le modèle d'en-tête comme suit:

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>
28
Adam Kinney

Ma solution de contournement consistait à utiliser une propriété attachée pour définir la liaison automatiquement:

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

Ensuite, dans le XAML:

<data:DataGridTextColumn util:DataGridColumnHelper.HeaderBinding="{Binding MeetingName, Source={StaticResource LocStrings}}" />
14
RobSiklos

Pour conserver le style visuel de l'en-tête d'origine, utilisez ContentTemplate au lieu de Template:

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

11
Lars Holm Jensen

Il semble beaucoup plus simple de définir la valeur dans le code, comme mentionné ci-dessus:

dg1.Columns[3].Header = SomeDynamicValue;

Évite d'utiliser la syntaxe Setter Property, qui dans mon cas semblait gâcher le style, même si j'ai essayé d'utiliser ContentTemplate ainsi que Template.

Un point sur lequel j’ai échappé, c’est qu’il est préférable d’utiliser la notation dg1.Columns[3].Header plutôt que de faire référence à une colonne nommée.

J'avais nommé une de mes colonnes et essayé de le référencer dans le code, mais j'avais des exceptions nulles. L'utilisation de la méthode Columns [index] a bien fonctionné et j'ai pu attribuer à l'en-tête une chaîne de texte basée sur les ressources de localisation.

2
Steve

Nous avons trouvé une solution de contournement intéressante qui fonctionne également avec le fichier wpflocalizeaddin.codeplex.com :

Créé par Slyi

Il utilise une 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;
    }
}

Et un style pour le 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>

afin que vous puissiez conserver votre syntaxe de liaison préférée sur l'attribut Header

<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

2
Rudi

Pourquoi ne pas simplement définir ceci dans le code:

dg1.Columns[3].Header = SomeDynamicValue;
1
Jersey Dude

S'il vous plaît noter dans la solution fournie par RobSiklos, Source {staticResource ...} est la clé, si vous envisagez de passer le RelativeSource comme 

Binding DataContext.SelectedHistoryTypeItem,RelativeSource={RelativeSource AncestorType=sdk:DataGrid},

ça peut ne pas marcher

1
Jit

J'ai une solution pour la reliure. Puisque vous utilisez DataGridTemlateColumn, sous-classez-le et ajoutez une propriété de type Binding nommée par exemple "HeaderBinding". Vous pouvez maintenant vous lier à cette propriété à partir du code XAML. Ensuite, vous devez propager la liaison au TextBlock dans le DataTemplate de votre en-tête. Par exemple, vous pouvez le faire avec l'événement OnLoaded de ce TextBlock.

 HeaderTextBlock.SetBinding(TextBlock.TextProperty, HeaderBinding);

C'est tout. Si vous avez plus de colonnes et que vous souhaitez utiliser un seul DataTemplate, alors c'est un peu plus compliqué, mais l'idée est la même.

0
Dimitar