Conteneurs WPF

De Banane Atomic
Aller à la navigationAller à la recherche

Liens

DockPanel

Xaml.svg
<DockPanel>
    <Button DockPanel.Dock="Top">0000</Button>
    <Button DockPanel.Dock="Right">1111</Button>
    <Button DockPanel.Dock="Bottom">2222</Button>
    <Button DockPanel.Dock="Left">3333</Button>
    <Button>4444</Button>  <!-- prend la place nécessaire pour l'affichage de son contenu -->
    <Button>5555</Button>  <!-- prend toute la place restante -->
</DockPanel>
Toujours déclarer en premier les éléments dockés.

Le dernier élément prend toute la place restante.

LastChildFill="False" pour changer ce comportement

StackPanel

Pile verticale (par défaut) ou horizontale.

Xaml.svg
<StackPanel Orientation="Horizontal">            

</StackPanel>

Si les éléments n'ont pas de taille, ils sont étirés suivant:

  • Width pour une orientation verticale
  • Height pour une orientation horizontale

WrapPanel

Pile horizontale (par défaut) ou verticale. À la différence du StackPanel, la pile continue sur une nouvelle rangée quand elle atteint la limite du conteneur.

Grid

Xaml.svg
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="2*" />  <!-- deuxième colonne 2x plus large que la première -->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
    </Grid.RowDefinitions>

    <Button Grid.Column="0">0000</Button>
    <Button Grid.Column="1">1111</Button>
    <Button Grid.Row="1" Grid.ColumnSpan="2">22 - 22 - 22</Button>  <!-- sur 2 colonnes -->
</Grid>
ColumnDefinition Width and RowDefinition Height
100 100px
px par défaut. Autres unités: cm, in, pt
Auto dimension déterminé par l'élément contenu
* répartition des dimensions en fonction de l'espace disponible
Un chiffre peut préfixer l'étoile pour donner une dimension proportionnelle.

Aligner les colonnes de différentes Grid: SharedSizeGroup

Xaml.svg
<StackPanel Grid.IsSharedSizeScope="True">  <!-- le conteneur doit avoir la propriété IsSharedSizeScope à True -->
    
    <Grid Width="200" ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" SharedSizeGroup="col1"/>
            <ColumnDefinition Width="Auto"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>

        <TextBlock Grid.Column="0">0000</TextBlock>
        <TextBlock Grid.Column="1">1111</TextBlock>
    </Grid>

    <Grid Width="200" ShowGridLines="True">
        <Grid.ColumnDefinitions>
            <ColumnDefinition SharedSizeGroup="col1" />  <!-- Même largeur de colonne que celles du groupe col1 -->
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition />
        </Grid.RowDefinitions>

        <TextBlock Grid.Column="0">aaaa</TextBlock>
        <TextBlock Grid.Column="1">bbbb</TextBlock>
    </Grid>

GridSplitter

Xaml.svg
<Grid>
    <Grid.ColumnDefinitions>
        <!-- limite la réduction de la taille de la colonne à 100 -->
        <ColumnDefinition Width="*" MinWidth="100" />  
        <ColumnDefinition Width="Auto" />
        <ColumnDefinition Width="*" />
    </Grid.ColumnDefinitions>

    <Button Grid.Column="0">Left side</Button>

    <GridSplitter Grid.Column="1" Width="2"
                  HorizontalAlignment="Center" VerticalAlignment="Stretch"
                  Background="Chocolate"
                  ShowsPreview="True" />
    <!-- ShowsPreview: redimmensionner les colonnes une fois le bouton de la sourie relaché -->

    <Button Grid.Column="2">Right side</Button>
</Grid>
Pour éviter que le GridSplitter ne fasse sortir les colonnes de la fenêtre, utiliser Width avec une * plutôt qu'une valeur dans les 2 colonnes adjacentes, MinWidth peut être utiliser avec une valeur pour compenser.

Uniform Grid

Grid simplifiée. Toutes les cellules ont la même taille.
Les éléments sont répartis automatiquement.

Xaml.svg
<!-- Il est possible de forcer le nombre de lignes (Rows="1") ou de colonnes (Columns="2") -->
<UniformGrid Columns="2">
    <Button>0000</Button>
    <Button>1111</Button>
    <Button>2222</Button>
    <Button>3333</Button>
</UniformGrid>

Canvas

Organisation en coordonnées X,Y

Xaml.svg
<Canvas Height="50" Width="100" Background="LightCyan">
    <TextBlock Canvas.Left="20">Bye bye</TextBlock>
    <TextBlock Canvas.Right="20" Canvas.Bottom="20">Yesterday!</TextBlock>
</Canvas>

L'origine du repère se trouve en haut à gauche.
Les éléments qui sortent du canvas sont quand même affiché sauf si la propriété ClipToBounds est mise à True.

Autres

Border

Xaml.svg
<Border BorderBrush="Black" BorderThickness="2" CornerRadius="5" Padding="5">

</Border>

GroupBox

Xaml.svg
<GroupBox Header="Mon Texte">

ScrollViewer

Xaml.svg
<ScrollViewer Height="30"
              BorderThickness="0">
    <StackPanel>
        <Button>Button</Button>
        <Button>Button</Button>
Propriétés HorizontalScrollBarVisibility et VerticalScrollBarVisibility
Auto visible si le contenu déborde du conteneur.
Disable pas d'affichage des scrollbars.
Hidden pas d'affichage des scrollbars.
Visible affichage des scrollbars.

AutoScroll

AutoScrollDependencyProperty.cs
public static class AutoScrollDependencyProperty
{
    public static readonly DependencyProperty AutoScrollProperty =
    DependencyProperty.RegisterAttached("AutoScroll", typeof(bool), typeof(AutoScrollDependencyProperty), new PropertyMetadata(false, AutoScrollPropertyChanged));

    public static void AutoScrollPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
    {
        var scrollViewer = obj as ScrollViewer;
        if (scrollViewer != null && (bool)args.NewValue)
        {
            scrollViewer.SizeChanged += ScrollViewer_SizeChanged;
            scrollViewer.ScrollToEnd();
        }
        else
        {
            scrollViewer.LayoutUpdated -= ScrollViewer_SizeChanged;
        }
    }

    private static void ScrollViewer_SizeChanged(object sender, EventArgs e)
    {
        var scrollViewer = sender as ScrollViewer;
        scrollViewer?.ScrollToEnd();
    }

    public static bool GetAutoScroll(DependencyObject obj)
    {
        return (bool)obj.GetValue(AutoScrollProperty);
    }

    public static void SetAutoScroll(DependencyObject obj, bool value)
    {
        obj.SetValue(AutoScrollProperty, value);
    }
}
View.xaml
<Window xmlns:local="clr-namespace:MonNamespace">
    <ScrollViewer local:AutoScrollDependencyProperty.AutoScroll="True">

ViewBox

TabControl

Disposition des éléments dans leur conteneur

Margin

4 valeurs Margin="left top right bottom"
2 valeurs Margin="left&right top&bottom"
1 valeur Margin="left&right&top&bottom"

Alignement

HorizonzalAlignement VerticalAlignement
  • Stretch par défaut sauf si Width est définie
  • Left
  • Center
  • Right
  • Stretch par défaut sauf si Height est définie
  • Top
  • Center
  • Bottom

Visibility

Visible valeur par défaut
Hidden l'élément n'est pas affiché mais occupe sa place
Collapse l'élément n'est pas affiché et ne prend pas de place

ZIndex

Par défaut à 0. Plus cette valeur est élevée, plus l'objet est mis en avant-plan.
L’élément ajouté en dernier recouvre les autres ayant le même ZIndex.

Appliquer un style à tous les éléments enfants du conteneur

Impossible d'utiliser un type parent commun comme TargetType

Xaml.svg
<StackPanel Margin="0 10 0 0">
    <StackPanel.Resources>
        <Style TargetType="FrameworkElement">
            <Setter Property="Margin" Value="5"></Setter>
        </Style>
    </StackPanel.Resources>

    <Button>0000</Button>
    <TextBox>1111</TextBox>
</StackPanel>

Un style pour chaque type

Xaml.svg
<StackPanel>
    <StackPanel.Resources>
        <Style x:Key="ChildrenStyle">
            <Setter Property="Margin" Value="5"></Setter>
        </Style>

        <Style TargetType="Button" BasedOn="{StaticResource ChildrenStyle}"></Style>
        <Style TargetType="TextBox" BasedOn="{StaticResource ChildrenStyle}"></Style>
    </StackPanel.Resources>

    <Button>0000</Button>
    <TextBox>1111</TextBox>
</StackPanel>

Attached Property

Xaml.svg
<Window xmlns:CommonFrameworkWindows="clr-namespace:CommonFramework.Windows;assembly=CommonFramework.Windows">
    <StackPanel CommonFrameworkWindows:MarginSetter.Margin="10">
Csharp.svg
public class MarginSetter
{
    public static Thickness GetMargin(DependencyObject obj)
    {
        return (Thickness)obj.GetValue(MarginProperty);
    }

    public static void SetMargin(DependencyObject obj, Thickness value)
    {
        obj.SetValue(MarginProperty, value);
    }

    // Using a DependencyProperty as the backing store for Margin.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MarginProperty =
        DependencyProperty.RegisterAttached("Margin", typeof(Thickness), 
                                            typeof(MarginSetter), new UIPropertyMetadata(new Thickness(), MarginChangedCallback));

    public static void MarginChangedCallback(object sender, DependencyPropertyChangedEventArgs e)
    {
        // Make sure this is put on a panel
        var panel = sender as Panel;

        if (panel == null) return;

        panel.Loaded += new RoutedEventHandler(panel_Loaded);
    }

    static void panel_Loaded(object sender, RoutedEventArgs e)
    {            
        var panel = sender as Panel;

        // Go over the children and set margin for them:
        foreach (var child in panel.Children)
        {
            var fe = child as FrameworkElement;

            if (fe == null) continue;

            fe.Margin = MarginSetter.GetMargin(panel);
        }
    }
}