Wie fülle ich eine WPF-Datenvorlage aus, die die gesamte Breite der Listbox ausfüllt?


Answers

Ich musste auch einstellen:

HorizontalContentAlignment="Stretch"

auf der enthaltenden ListBox .

Question

Ich habe eine ListBox DataTemplate in WPF. Ich möchte, dass ein Element dicht an der linken Seite der ListBox und ein anderes Objekt an der rechten Seite anliegt, aber ich kann nicht herausfinden, wie das geht.

Bisher habe ich ein Grid mit drei Spalten, die linke und die rechte haben einen Inhalt und die Mitte ist ein Platzhalter, dessen Breite auf "*" gesetzt ist. Wo gehe ich falsch?

Hier ist der 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>



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



Wenn Sie ein Grid möchten, müssen Sie Ihre ColumnDefinition ändern:

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

Wenn Sie kein Grid , können Sie ein 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>

Beachten Sie den TextBlock am Ende. Jedes Steuerelement, für das kein "DockPanel.Dock" definiert ist, füllt den verbleibenden Speicherplatz aus.




Das Grid sollte standardmäßig die gesamte Breite der ListBox da das Standard- ItemsPanel dafür ein VirtualizingStackPanel . Ich gehe davon aus, dass Sie ListBox.ItemsPanel nicht geändert ListBox.ItemsPanel .

Vielleicht, wenn Sie die mittlere ColumnDefinition (die anderen sind Standard "*" ), setzen Sie HorizontalAlignment="Left" auf Ihr WrapPanel und HorizontalAlignment="Right" auf die ListBox für Telefonnummern. Möglicherweise müssen Sie die ListBox etwas ändern, damit die Telefonnummern noch besser ausgerichtet werden, z. B. DataTemplate Sie eine DataTemplate für sie DataTemplate .




Okay, hier ist was du hast:

Spalte 0: WrapPanel
Spalte 1: Nichts
Spalte 2: ListBox

Es klingt so, als ob Sie WrapPanel am linken Rand, ListBox am rechten Rand und Platz für das, was in der Mitte übrig ist, ListBox .

Am einfachsten ist es, ein DockPanel und kein Grid .

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

Das sollte leeren Raum zwischen dem WrapPanel und der ListBox .




Taeke's Antwort funktioniert gut, und nach der Antwort von vancutterromney können Sie die horizontale Bildlaufleiste deaktivieren, um die lästige Größenabweichung loszuwerden. Wenn Sie jedoch das Beste aus beiden Welten wollen - um die Bildlaufleiste zu entfernen, wenn sie nicht benötigt wird, aber automatisch aktiviert wird, wenn die ListBox zu klein wird, können Sie den folgenden Konverter verwenden:

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

Definieren Sie es dann in XAML entsprechend den gewünschten Max / Min-Werten, sowie einem Offset, um die lästige 2-Pixel-Größenübereinstimmung zu behandeln, wie in den anderen Antworten erwähnt:

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

Verwenden Sie dann den Konverter in der Bindungsbreite:

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



Wenn Taeke die Antwort erweitert und ScrollViewer.HorizontalScrollBarVisibility="Hidden" für eine ListBox kann das ListBox Steuerelement die Breite des übergeordneten ListBox übernehmen und die Bildlaufleiste nicht ListBox werden.

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



Die Methode in Taekes Antwort erzwingt eine horizontale Bildlaufleiste. Dies kann behoben werden, indem ein Konverter hinzugefügt wird, um die Breite des Rasters um die Breite der vertikalen Bildlaufleiste zu reduzieren.

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

Fügen Sie dem Stammknoten Ihres XAML einen Namespace hinzu.

xmlns:converters="clr-namespace:Converters"

Und aktualisieren Sie die Grid-Breite, um den Konverter zu verwenden.

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