web-dev-qa-db-fra.com

Comment puis-je faire en sorte qu'un modèle de données WPF remplisse toute la largeur de la zone de liste?

J'ai un ListBoxDataTemplate dans WPF. Je veux qu'un élément soit serré contre le côté gauche du ListBox et un autre élément soit serré contre le côté droit, mais je ne sais pas comment faire cela.

Jusqu'à présent, j'ai un Grid avec trois colonnes, les gauche et droite ont du contenu et le centre est un espace réservé avec sa largeur définie sur "*". Où vais-je mal?

Voici le code:

<DataTemplate x:Key="SmallCustomerListItem">
    <Grid HorizontalAlignment="Stretch">
        <Grid.RowDefinitions>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <WrapPanel HorizontalAlignment="Stretch" Margin="0">
            <!--Some content here-->
            <TextBlock Text="{Binding Path=LastName}" TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text=", " TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text="{Binding Path=FirstName}" TextWrapping="Wrap" FontSize="24"/>

        </WrapPanel>
        <ListBox ItemsSource="{Binding Path=PhoneNumbers}" Grid.Column="2" d:DesignWidth="100" d:DesignHeight="50"
     Margin="8,0" Background="Transparent" BorderBrush="Transparent" IsHitTestVisible="False" HorizontalAlignment="Stretch"/>
    </Grid>
</DataTemplate>
59
Eric Haskins

J'ai également dû définir:

HorizontalContentAlignment="Stretch"

sur le contenant ListBox.

137
Eric Haskins
<Grid.Width>
    <Binding Path="ActualWidth" 
             RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
</Grid.Width>
23
Taeke

Ok, voici ce que vous avez:

Colonne 0: WrapPanel
Colonne 1: Rien
Colonne 2: ListBox

Il semble que vous souhaitiez WrapPanel sur le bord gauche, ListBox sur le bord droit, et de l'espace pour occuper ce qui reste au milieu.

La manière la plus simple de le faire est en fait d'utiliser un DockPanel, pas un Grid.

<DockPanel>
    <WrapPanel DockPanel.Dock="Left"></WrapPanel>
    <ListBox DockPanel.Dock="Right"></ListBox>
</DockPanel>

Cela devrait laisser un espace vide entre le WrapPanel et le ListBox.

4
17 of 26

Extension de la réponse de Taeke, définition du ScrollViewer.HorizontalScrollBarVisibility="Hidden" pour un ListBox permet au contrôle enfant de prendre la largeur du parent et de ne pas afficher la barre de défilement.

<ListBox Width="100" ScrollViewer.HorizontalScrollBarVisibility="Hidden">                
    <Label Content="{Binding Path=., Mode=OneWay}" HorizontalContentAlignment="Stretch" Height="30" Margin="-4,0,0,0" BorderThickness="0.5" BorderBrush="Black" FontFamily="Calibri" >
        <Label.Width>
            <Binding Path="Width" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ListBox}}" />
        </Label.Width>
    </Label>
</ListBox >
2
vancutterromney

Le Grid doit par défaut occuper toute la largeur du ListBox car le ItemsPanel par défaut est pour lui un VirtualizingStackPanel. Je suppose que vous avez pas changé ListBox.ItemsPanel.

Peut-être que si vous vous êtes débarrassé du milieu ColumnDefinition (les autres sont par défaut "*"), et met HorizontalAlignment="Left" sur votre WrapPanel et HorizontalAlignment="Right" sur le ListBox pour les numéros de téléphone. Vous devrez peut-être modifier légèrement ce ListBox pour obtenir des numéros de téléphone encore plus alignés à droite, par exemple en créant un DataTemplate pour eux.

1
Joel B Fant

Si vous souhaitez utiliser un Grid, vous devez changer votre ColumnDefinitions pour qu'il soit:

    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="Auto"/>
        <ColumnDefinition Width="*"/>
        <ColumnDefinition Width="Auto"/>
    </Grid.ColumnDefinitions>

Si vous n'avez pas besoin d'utiliser un Grid, vous pouvez utiliser un DockPanel:

    <DockPanel>
        <WrapPanel DockPanel.Dock="Left">
            <!--Some content here-->
            <TextBlock Text="{Binding Path=LastName}" TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text=", " TextWrapping="Wrap" FontSize="24"/>
            <TextBlock Text="{Binding Path=FirstName}" TextWrapping="Wrap" FontSize="24"/>
        </WrapPanel>
        <ListBox DockPanel.Dock="Right" ItemsSource="{Binding Path=PhoneNumbers}" 
 Margin="8,0" Background="Transparent" BorderBrush="Transparent" IsHitTestVisible="False"/>
        <TextBlock />
    </DockPanel>

Remarquez le TextBlock à la fin. Tout contrôle sans "DockPanel.Dock" defined remplira l'espace restant.

1
Phobis

La méthode dans la réponse de Taeke force une barre de défilement horizontale. Cela peut être résolu en ajoutant un convertisseur pour réduire la largeur de la grille par la largeur du contrôle de barre de défilement verticale.

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;

namespace Converters
{
    public class ListBoxItemWidthConverter : MarkupExtension, IValueConverter
    {
        private static ListBoxItemWidthConverter _instance;

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return System.Convert.ToInt32(value) - SystemParameters.VerticalScrollBarWidth;
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion

        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            return _instance ?? (_instance = new ListBoxItemWidthConverter());
        }
    }
}

Ajoutez un espace de noms au nœud racine de votre XAML.

xmlns:converters="clr-namespace:Converters"

Et mettez à jour la largeur de la grille pour utiliser le convertisseur.

<Grid.Width>
    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
</Grid.Width>
0
Kevin Hilt

La réponse de Taeke fonctionne bien, et selon la réponse de vancutterromney, vous pouvez désactiver la barre de défilement horizontale pour vous débarrasser de l'inadéquation de taille gênante. Cependant, si vous voulez le meilleur des deux mondes - pour supprimer la barre de défilement lorsqu'elle n'est pas nécessaire, mais l'activer automatiquement lorsque la ListBox devient trop petite, vous pouvez utiliser le convertisseur suivant:

/// <summary>
/// Value converter that adjusts the value of a double according to min and max limiting values, as well as an offset. These values are set by object configuration, handled in XAML resource definition.
/// </summary>
[ValueConversion(typeof(double), typeof(double))]
public sealed class DoubleLimiterConverter : IValueConverter
{
    /// <summary>
    /// Minimum value, if set. If not set, there is no minimum limit.
    /// </summary>
    public double? Min { get; set; }

    /// <summary>
    /// Maximum value, if set. If not set, there is no minimum limit.
    /// </summary>
    public double? Max { get; set; }

    /// <summary>
    /// Offset value to be applied after the limiting is done.
    /// </summary>
    public double Offset { get; set; }

    public static double _defaultFailureValue = 0;

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null || !(value is double))
            return _defaultFailureValue;

        double dValue = (double)value;
        double minimum = Min.HasValue ? Min.Value : double.NegativeInfinity;
        double maximum = Max.HasValue ? Max.Value : double.PositiveInfinity;
        double retVal = dValue.LimitToRange(minimum, maximum) + Offset;
        return retVal;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Ensuite, définissez-le en XAML en fonction des valeurs max/min souhaitées, ainsi qu'un décalage pour faire face à cette incompatibilité de taille de 2 pixels gênante, comme mentionné dans les autres réponses:

<ListBox.Resources>
    <con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/>
</ListBox.Resources>

Utilisez ensuite le convertisseur dans la liaison Largeur:

<Grid.Width>
    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{StaticResource conDoubleLimiter}"  />
</Grid.Width>
0
BCA