6 votes

Liaison à la largeur d'une ColumnDefinition

J'ai besoin d'une sorte de tableau pour les entrées de l'utilisateur. J'ai donc créé une grille avec des colonnes et des lignes définies. Le tableau n'est pas destiné à afficher des données, son but est simplement de structurer les entrées.

Pour structurer tous les éléments, comme les zones de texte, etc. J'ai défini toutes les colonnes avec une largeur. Il y aura plusieurs grilles alignées dans un stackpanel.

La définition des colonnes en XAML ressemble à ceci :

<Grid.ColumnDefinitions>
  <ColumnDefinition x:Name="widthLoopID" Width="55" />
</Grid.ColumnDefinition>

Je l'ai référencé à partir d'autres grilles comme :

<Grid.ColumnDefinitions>
  <ColumnDefinition Width="{Binding ElementName=widthLoopID, Path=Width}" />
</GridColumnDefinition>

Ça marche plutôt bien.

Maintenant, la partie difficile. Comment je fais ça dans le code-behind ?

J'ai essayé ce qui suit :

// define columns
ColumnDefinition loopIdColumn = new ColumnDefinition();
// setup databinding for columns
Binding loopIdBinding = new Binding();
// set binding for width
loopIdBinding.ElementName = "widthLoopID";
loopIdBinding.Path = new PropertyPath("Width");
loopIdColumn.SetBinding(Grid.WidthProperty, loopIdBinding);
// add definition of column
loopGrid.ColumnDefinitions.Add(loopIdColumn);

Mais lorsqu'il est exécuté, j'obtiens l'erreur suivante

System.Windows.Data Error: 1 : Cannot create default converter to perform 'one-way' conversions between types 'System.Windows.GridLength' and 'System.Double'. Consider using Converter property of Binding. BindingExpression:Path=Width; DataItem='ColumnDefinition' (HashCode=37457626); target element is 'ColumnDefinition' (HashCode=7871588); target property is 'Width' (type 'Double')

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='55' BindingExpression:Path=Width; DataItem='ColumnDefinition' (HashCode=37457626); target element is 'ColumnDefinition' (HashCode=7871588); target property is 'Width' (type 'Double')

Je dois donc convertir "Width", mais comment le faire et pourquoi cela ne peut pas être effectué par le convertisseur par défaut comme dans XAML ?

Je suis assez novice en matière de WPF et il se peut que je n'aie pas compris tous les concepts, alors donnez-moi un indice.

Merci d'avance Benny

EDITAR:

J'ai essayé l'astuce de la première réponse. Cela ne fonctionne pas, car GridLengthConverter n'est pas du type IValueConverter.

J'ai donc écrit un DoubleToGridLengthConverter, qui convertit un GridLength en un Double et vice versa.

Maintenant la valeur est convertie mais le résultat n'est pas le même que celui que le code fait dans XAML. J'ai l'impression que cela ne fonctionne pas du tout à partir du code. Vraiment étrange.

Voici le code du convertisseur :

using System;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
using System.Globalization;
using System.Diagnostics;

namespace editor
{
   [ValueConversion(typeof(Double), typeof(GridLength))]
   class DoubleToGridLengthConverter : IValueConverter
   {
       public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
       {
           // check whether a value is given
           if (value != null)
           {
              Debug.WriteLine("value is: " + value + " type: " + value.GetType());
              return (Double)((GridLength)(value)).Value;
           }
           else
           {
               throw new ValueUnavailableException();
           }
       }

       public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
       {
           // check whether a value is given
           if (value != null)
           {
               return new GridLength((Double)value);
           }
           else
           {
               throw new ValueUnavailableException();
           }
        }
    }
}

D'autres conseils ? Je peux imaginer que quelqu'un d'autre a déjà eu ce problème.

Merci encore Benny

2voto

Matt Hamilton Points 98268

Vous êtes très proche, et l'erreur est un gros indice. Vous devez utiliser un Convertisseur de longueur de grille pour convertir le type original ( System.Double ) à un GridLength (ce qui correspond à la définition de la largeur des colonnes).

Essayez ceci (non testé) :

loopIdBinding.Converter = new System.Windows.GridLengthConverter();

En fait, cela devrait être tout ce que vous avez à faire. Cela devrait indiquer au binding d'exécuter la valeur à travers le convertisseur pour obtenir le type dont vous avez besoin.

Modifier

Alors oui, GridLengthConverter n'est pas un IValueConverter donc tu ne peux pas faire ça. A la place, vous devrez créer une nouvelle classe qui implémente IValueConverter así:

public class GridLengthValueConverter : IValueConverter
{
    GridLengthConverter _converter = new GridLengthConverter();

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return _converter.ConvertFrom(value);
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return _converter.ConvertTo(value, targetType);
    }
}

... puis assignez une nouvelle instance de ceci comme votre convertisseur :

loopIdBinding.Converter = new System.Windows.GridLengthConverter();

Encore une fois, cela n'a pas été testé. Faites-moi savoir comment ça se passe.

1voto

MikeKulls Points 1498

Je pense que j'ai mal compris la question, je n'avais pas réalisé que vous liiez entre 2 grilles. Cependant, j'ai laissé ma réponse précédente car elle pourrait être pertinente. Si vous devez ajouter des colonnes dans le code assez souvent, cela vaut la peine d'y réfléchir, car vous faites quelque chose de mal. Mais chaque situation est différente :-)

Quoi qu'il en soit, la réponse à votre question est que vous Ne le fais pas. besoin d'un convertisseur. Vous avez juste lié à la mauvaise propriété dans cette ligne

loopIdColumn.SetBinding(Grid.WidthProperty, loopIdBinding);

changez cela en

loopIdColumn.SetBinding(ColumnDefinition.WidthProperty, loopIdBinding);

et tout fonctionne très bien.

1voto

TheZenker Points 1053

Si tout ce dont vous avez besoin est de synchroniser (partager) la taille des colonnes sur des grilles séparées, avez-vous vérifié la propriété SharedSizeGroup de la ColumnDefinition ? Il semblerait qu'elle puisse faciliter un peu les choses.

Propriété SharedSizeGroup MSDN

Exemple de code à partir du lien MSDN :

<StackPanel>
<Grid ShowGridLines="True" Margin="0,0,10,0">
  <Grid.ColumnDefinitions>
    <ColumnDefinition SharedSizeGroup="FirstColumn"/>
    <ColumnDefinition SharedSizeGroup="SecondColumn"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
  </Grid.RowDefinitions>

    <Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0" Width="200" Height="100"/>
    <Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0" Width="150" Height="100"/>

    <TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>

<Grid ShowGridLines="True">
  <Grid.ColumnDefinitions>
    <ColumnDefinition SharedSizeGroup="FirstColumn"/>
    <ColumnDefinition SharedSizeGroup="SecondColumn"/>
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>        
    <RowDefinition Height="Auto" SharedSizeGroup="FirstRow"/>
  </Grid.RowDefinitions>

    <Rectangle Fill="Silver" Grid.Column="0" Grid.Row="0"/>
    <Rectangle Fill="Blue" Grid.Column="1" Grid.Row="0"/>

    <TextBlock Grid.Column="0" Grid.Row="0" FontWeight="Bold">First Column</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="0" FontWeight="Bold">Second Column</TextBlock>
</Grid>
</StackPanel>

0voto

MikeKulls Points 1498

Pourquoi devez-vous faire cela dans le code derrière ? Je pense que si vous avez besoin d'un nombre variable de colonnes, vous devriez utiliser un contrôle d'éléments de quelque sorte. Vous pouvez le faire avec quelque chose comme ceci :

    <ItemsControl>
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <StackPanel Orientation="Horizontal"></StackPanel>
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
    </ItemsControl>

Vous pouvez utiliser un canevas comme modèle d'élément et je suppose que vous pouvez utiliser une grille (je n'ai pas essayé la grille moi-même). Vous dimensionnez ensuite les articles en utilisant un modèle de données. Si cela vous est utile, faites-le moi savoir et je pourrai vous donner plus de détails.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X