Come faccio a fare in modo che un modello di dati WPF riempia l'intera larghezza della casella di riepilogo?

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

Domanda

Ho un ListBox DataTemplate in WPF. Voglio che un oggetto sia stretto contro il lato sinistro del ListBox e un altro oggetto sia stretto contro il lato destro, ma non riesco a capire come farlo.

Finora ho un Grid con tre colonne, quelle sinistra e destra hanno contenuto e il centro è un segnaposto con la larghezza impostata su " * " ;. Dove sto sbagliando?

Ecco il codice:

<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>
È stato utile?

Soluzione

Ho anche dovuto impostare:

HorizontalContentAlignment="Stretch"

sul ListBox .

Altri suggerimenti

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

Ok, ecco cosa hai:

Colonna 0: WrapPanel
Colonna 1: niente
Colonna 2: ListBox

Sembra che tu voglia WrapPanel sul bordo sinistro, ListBox sul bordo destro e spazio per occupare ciò che resta nel mezzo.

Il modo più semplice per farlo è in realtà utilizzare un DockPanel , non un Grid .

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

Questo dovrebbe lasciare uno spazio vuoto tra WrapPanel e ListBox .

Estendendo la risposta di Taeke, impostando ScrollViewer.HorizontalScrollBarVisibility = " Hidden " per un ListBox consente al controllo figlio di prendere la larghezza del genitore e non mostrare la barra di scorrimento up.

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

Il Grid dovrebbe per impostazione predefinita occupare l'intera larghezza del ListBox perché il ItemsPanel predefinito è un VirtualizingStackPanel . Suppongo che tu abbia non cambiato ListBox.ItemsPanel .

Forse se ti sei sbarazzato del ColumnDefinition centrale (gli altri sono predefiniti " * " ) e metti HorizontalAlignment = " Left " su WrapPanel e HorizontalAlignment = " Right " su ListBox per i numeri di telefono. Potrebbe essere necessario modificare un po 'quel ListBox per ottenere i numeri di telefono ancora più allineati a destra, come la creazione di un DataTemplate per loro.

Se vuoi usare una Grid , allora devi cambiare le tue ColumnDefinition in:

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

Se non è necessario utilizzare un Grid , è possibile utilizzare 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>

Nota il TextBlock alla fine. Qualsiasi controllo senza " DockPanel.Dock & riempirà lo spazio rimanente.

La risposta di Taeke funziona bene, e secondo la risposta di Vancutterromney puoi disabilitare la barra di scorrimento orizzontale per sbarazzarti del fastidioso disallineamento delle dimensioni. Tuttavia, se si desidera il meglio dei due mondi: rimuovere la barra di scorrimento quando non è necessaria, ma attivarla automaticamente quando ListBox diventa troppo piccola, è possibile utilizzare il seguente convertitore:

/// <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();
    }
}

Quindi definiscilo in XAML in base ai valori max / min desiderati, oltre a un offset per gestire quella fastidiosa discrepanza di dimensioni di 2 pixel come menzionato nelle altre risposte:

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

Quindi utilizzare il convertitore nell'associazione Larghezza:

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

Il metodo nella risposta di Taeke forza una barra di scorrimento orizzontale. Ciò può essere risolto aggiungendo un convertitore per ridurre la larghezza della griglia della larghezza del controllo barra di scorrimento 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());
        }
    }
}

Aggiungi uno spazio dei nomi al nodo principale del tuo XAML.

xmlns:converters="clr-namespace:Converters"

E aggiorna la larghezza della griglia per utilizzare il convertitore.

<Grid.Width>
    <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
</Grid.Width>
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top