如何使WPF数据模板填充列表框的整个宽度?
我在WPF中有一个ListBox
DataTemplate
。 我想要一个项目在左侧的ListBox
和另一个项目紧靠在右侧,但我不知道如何做到这一点。
到目前为止,我有一个三列的Grid
,左侧和右侧的内容和中心是宽度设置为“*”的占位符。 我哪里错了?
这里是代码:
<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>
我还必须设置:
HorizontalContentAlignment="Stretch"
在包含的ListBox
。
<Grid.Width> <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" /> </Grid.Width>
好的,这是你有什么:
列0: WrapPanel
专栏1:没有
第2列: ListBox
这听起来像你想要左边的WrapPanel
,右边的ListBox
,还有空间去占据左边的东西。
最简单的方法是使用DockPanel
,而不是Grid
。
<DockPanel> <WrapPanel DockPanel.Dock="Left"></WrapPanel> <ListBox DockPanel.Dock="Right"></ListBox> </DockPanel>
这应该留下WrapPanel
和ListBox
之间的空白空间。
扩展Taeke的答案,为ListBox
设置ScrollViewer.HorizontalScrollBarVisibility="Hidden"
允许子控件获取父宽度,而不显示滚动条。
<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 >
Grid
默认占用ListBox
的整个宽度,因为它的默认ItemsPanel
是一个VirtualizingStackPanel
。 我假设你没有改变ListBox.ItemsPanel
。
也许如果你摆脱了中间ColumnDefinition
(其他人是默认的"*"
),并将HorizontalAlignment="Left"
ColumnDefinition
HorizontalAlignment="Left"
您的WrapPanel
和HorizontalAlignment="Right"
ListBox
的电话号码。 您可能需要稍微改变一下ListBox
以使电话号码更加右alignment,比如为它们创build一个DataTemplate
。
如果你想使用一个Grid
,那么你需要改变你的ColumnDefinition
为:
<Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions>
如果你不需要使用Grid
,那么你可以使用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>
最后注意TextBlock
。 没有定义"DockPanel.Dock"
任何控件将填充剩余的空间。
泰克的答案效果很好,根据vancutterromney的回答,您可以禁用水平滚动条来摆脱烦人的尺寸不匹配。 但是,如果您确实需要两全其美的解决scheme – 在不需要滚动条的情况下移除滚动条,但在列表框变得太小时自动启用该滚动条,则可以使用以下转换器:
/// <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(); } }
然后根据所需的最大/最小值在XAML中定义它,以及处理如其他答案中提到的令人讨厌的2像素大小不匹配的偏移量:
<ListBox.Resources> <con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/> </ListBox.Resources>
然后在宽度绑定中使用转换器:
<Grid.Width> <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{StaticResource conDoubleLimiter}" /> </Grid.Width>
Taeke答案中的方法强制水平滚动条。 这可以通过添加一个转换器来减less垂直滚动条控件的宽度来减小网格的宽度。
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()); } } }
将命名空间添加到XAML的根节点。
xmlns:converters="clr-namespace:Converters"
并更新网格宽度以使用转换器。
<Grid.Width> <Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/> </Grid.Width>