Wie kann ich eine WPF Datenvorlage über die gesamte Breite des Listbox füllen?
-
02-07-2019 - |
Frage
Ich habe eine ListBox
DataTemplate
in WPF. Ich mag ein Element dicht an der linken Seite des ListBox
und ein anderes Elements sein und fest an der rechten Seite zu sein, aber ich kann nicht herausfinden, wie dies zu tun.
Bisher habe ich eine Grid
mit drei Spalten haben, haben die linken und richtigen Inhalt und das Zentrum ist ein Platzhalter mit ihm Breite Set zu „*“. Wo soll ich denn 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>
Lösung
Ich hatte auch setzen:
HorizontalContentAlignment="Stretch"
auf der enthaltenden ListBox
.
Andere Tipps
<Grid.Width>
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
</Grid.Width>
Ok, hier ist das, was Sie haben:
Spalte 0: WrapPanel
Spalte 1: Nichts
Spalte 2: ListBox
Es klingt wie Sie WrapPanel
am linken Rand wollen, ListBox
am rechten Rand und Raum zu übernehmen, was in der Mitte übrig geblieben ist.
Die einfachste Weg, dies zu tun, ist eigentlich eine DockPanel
zu verwenden, keinen Grid
.
<DockPanel>
<WrapPanel DockPanel.Dock="Left"></WrapPanel>
<ListBox DockPanel.Dock="Right"></ListBox>
</DockPanel>
Dies sollte leeren Raum zwischen dem WrapPanel
verlassen und dem ListBox
.
Die Ausweitung Taeke Antwort, die ScrollViewer.HorizontalScrollBarVisibility="Hidden"
für eine ListBox
Einstellung des Kindes Kontrolle ermöglicht es den Eltern Breite nehmen und nicht die Bildlaufleiste zeigen müssen.
<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 Grid
standardmäßig sollte die gesamte Breite des ListBox
, weil der Standard ItemsPanel
denn es ist ein VirtualizingStackPanel
aufzunehmen. Ich gehe davon aus, dass Sie nicht geändert ListBox.ItemsPanel
.
Vielleicht, wenn Sie von der Mitte ColumnDefinition
losgeworden (die anderen sind Standard "*"
) und setzen HorizontalAlignment="Left"
auf WrapPanel
und HorizontalAlignment="Right"
auf dem ListBox
für Telefonnummern. Sie können von diesem ListBox
ein wenig zu verändern haben die Telefonnummern noch rechtsbündig, wie die Schaffung eines DataTemplate
für sie zu erhalten.
Wenn Sie eine Grid
verwenden möchten, dann müssen Sie Ihre ColumnDefinition
s ändern werden:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
Wenn Sie keinen Grid
verwenden müssen, dann könnten Sie eine DockPanel
verwenden:
<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 die TextBlock
am Ende. Jede Kontrolle ohne "DockPanel.Dock"
definiert wird den verbleibenden Raum füllen.
Taeke Antwort gut funktioniert, und wie pro vancutterromney Antwort können Sie die horizontale Bildlaufleiste deaktivieren, das lästigen size mismatch loszuwerden. Wenn Sie jedoch das Beste aus beiden Welten tun wollen - die Bildlaufleiste zu entfernen, wenn sie nicht benötigt wird, sondern es automatisch aktiviert, wenn die List-Box 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();
}
}
Dann ist es in XAML definieren, je nach den gewünschten max / min-Werten als auch ein Versatz mit diesem lästigen 2-Pixelgrße Mismatch zu behandeln, wie in den anderen Antworten genannt:
<ListBox.Resources>
<con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/>
</ListBox.Resources>
Verwenden Sie dann den Konverter in der Breite Bindung:
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{StaticResource conDoubleLimiter}" />
</Grid.Width>
Das Verfahren in Taeke Antwort erzwingt eine horizontale Bildlaufleiste. Dies kann durch Zugabe eines Wandlers befestigt werden das Netz der Breite durch die Breite der vertikalen Bildlaufsteuerung 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 einen Namespace auf den Wurzelknoten Ihrer XAML.
xmlns:converters="clr-namespace:Converters"
und aktualisieren Sie die Rasterweite des Wandlers verwendet werden.
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
</Grid.Width>