Comment définir la largeur de colonne maximum de la grille en fonction de la taille de la fenêtre ou de l'écran en XAML

StackOverflow https://stackoverflow.com/questions/82323

  •  01-07-2019
  •  | 
  •  

Question

J'ai une grille de 3 colonnes dans une fenêtre avec un GridSplitter sur la première colonne. Je souhaite définir la largeur maximale de la première colonne sur un tiers de la fenêtre ou de la page largeur parent (ou ActualWidth ) et je préférerais le faire en XAML si possible.

Voici un exemple de code XAML avec lequel jouer dans XamlPad (ou similaire) et qui montre ce que je fais.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="Column1" Width="200"/>
            <ColumnDefinition x:Name="Column2" MinWidth="50" />
            <ColumnDefinition x:Name="Column3" Width="{ Binding ElementName=Column1, Path=Width }"/>
            </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Background="Green" />
        <GridSplitter Grid.Column="0" Width="5" />
        <Label Grid.Column="1" Background="Yellow" />
        <Label Grid.Column="2" Background="Red" />
    </Grid>
</Page>

Comme vous pouvez le constater, la largeur de la colonne de droite est liée à la largeur de la première colonne. Ainsi, lorsque vous faites glisser la colonne de gauche à l'aide du séparateur, la colonne de droite fait la même chose :) Si vous faites glisser la colonne de gauche vers la droite, elle finira par glisser sur la moitié de la page / fenêtre et sur le côté droit de la fenêtre, repoussant ainsi les colonnes 2 et 3.

Je veux éviter cela en définissant la largeur maximale de la colonne 1 sur un tiers de la largeur de la fenêtre (ou quelque chose du genre). Je peux le faire dans le code derrière assez facilement, mais comment le faire dans "XAML Only"?

EDIT: David Schmitt a suggéré d'utiliser SharedSizeGroup au lieu de binding, ce qui est une excellente suggestion. Mon exemple de code ressemblerait à ceci:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="Column1" SharedSizeGroup="ColWidth" Width="40"/>
                <ColumnDefinition x:Name="Column2" MinWidth="50" Width="*" />
                <ColumnDefinition x:Name="Column3" SharedSizeGroup="ColWidth"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Background="Green" />
            <GridSplitter Grid.Column="0" Width="5" />
            <Label Grid.Column="1" Background="Yellow" />
            <Label Grid.Column="2" Background="Red" />
        </Grid>
</Page>
Était-ce utile?

La solution

Je pense que l'approche XAML uniquement est quelque peu détournée, mais voici une façon de le faire.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

    <!-- This contains our real grid, and a reference grid for binding the layout-->
    <Grid x:Name="Container">

      <!-- hidden because it's behind the grid below -->
      <Grid x:Name="LayoutReference">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <!-- We need the border, because the column doesn't have an ActualWidth -->
        <Border x:Name="ReferenceBorder" 
                Background="Black" />
        <Border Background="White" Grid.Column="1" />
        <Border Background="Black" Grid.Column="2" />
      </Grid>

      <!-- I made this transparent, so we can see the reference -->
      <Grid Opacity="0.9">
          <Grid.ColumnDefinitions>
              <ColumnDefinition x:Name="Column1" 
                                MaxWidth="{Binding ElementName=ReferenceBorder,Path=ActualWidth}"/>
              <ColumnDefinition x:Name="Column2" 
                                MinWidth="50"  />
              <ColumnDefinition x:Name="Column3" 
                                Width="{ Binding ElementName=Column1, Path=Width }"/>
              </Grid.ColumnDefinitions>

          <Label Grid.Column="0" Background="Green"/>
          <GridSplitter Grid.Column="0" Width="5" />
          <Label Grid.Column="1" Background="Yellow" />
          <Label Grid.Column="2" Background="Red" />
      </Grid>
    </Grid>

</Page>

Autres conseils

Trop paresseux pour l'écrire moi-même, mais vous devriez pouvoir utiliser un convertisseur mathématique et établir une liaison avec la largeur de votre fenêtre parente (soit par son nom, soit avec une recherche d'ancêtre RelativeSource).

//I know I borrowed this from someone, sorry I forgot to add a comment from whom
public class ScaledValueConverter : IValueConverter
{
  public Object Convert(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     Double scalingFactor = 0;
     if (parameter != null)
     {
        Double.TryParse((String)(parameter), out scalingFactor);
     }

     if (scalingFactor == 0.0d)
     {
        return Double.NaN;
     }

     return (Double)value * scalingFactor;
  }

  public Object ConvertBack(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     throw new Exception("The method or operation is not implemented.");
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top