如何使 WPF 数据模板填充列表框的整个宽度?
Posted
技术标签:
【中文标题】如何使 WPF 数据模板填充列表框的整个宽度?【英文标题】:How do I make a WPF data template fill the entire width of the listbox? 【发布时间】:2010-09-13 05:13:40 【问题描述】:我在 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>
【问题讨论】:
您能否发布您的 XAML,以便清楚您目前拥有什么? 【参考方案1】:我还必须设置:
HorizontalContentAlignment="Stretch"
关于包含ListBox
。
【讨论】:
塔帕尔。谷歌搜索帮助,这是第一个链接。不错的一个:) @Eric Haskins 我对 Windows Phone 的 Pivot 控件有同样的问题 (<controls:Pivot.ItemTemplate><DataTemplate /></controls:Pivot.ItemTemplate>
) 但是我应该把代码放在哪里?我尝试了一些,但我无法弄清楚。
给 Windows Phone 用户的注意事项 - 这不起作用;该属性被 ListBox 的 ItemContainerStyle 覆盖。要使其正常工作,请在此处查看 Gabriel Mongeon 的回答:***.com/questions/838828/…
这一定是最烦人的 UI hack 之一。为什么默认不设置这个?嘘。
另外值得一提的是,您可能需要将其设置为 ListBoxItem 的样式,如果有的话:<ListView.ItemContainerStyle> <Style TargetType="ListViewItem"> <Setter Property="HorizontalContentAlignment" Value="Stretch" /> </Style> </ListView.ItemContainerStyle>
【参考方案2】:
<Grid.Width>
<Binding Path="ActualWidth"
RelativeSource="RelativeSource Mode=FindAncestor, AncestorType=x:Type ScrollContentPresenter" />
</Grid.Width>
【讨论】:
我喜欢这种方法的简单性。它不仅确保小项目填满宽度,还确保内容希望非常宽的项目被限制在列表框宽度内。 正是我要搜索的内容:太小时填充宽度,太大时限制宽度。 我刚刚注意到这个解决方案会导致 ListBox 的宽度始终比项目的宽度略小,这会稍微切断项目并激活列表框底部的水平滚动条。我通过显式禁用水平滚动来解决此问题。【参考方案3】:好的,这就是你所拥有的:
第 0 列:WrapPanel
第 1 列:无
第2栏:ListBox
听起来您希望WrapPanel
在左边缘,ListBox
在右边缘,并留出空间来占据中间的剩余部分。
最简单的方法实际上是使用DockPanel
,而不是Grid
。
<DockPanel>
<WrapPanel DockPanel.Dock="Left"></WrapPanel>
<ListBox DockPanel.Dock="Right"></ListBox>
</DockPanel>
这应该在WrapPanel
和ListBox
之间留出空白空间。
【讨论】:
【参考方案4】:扩展 Taeke 的答案,将 ScrollViewer.HorizontalScrollBarVisibility="Hidden"
设置为 ListBox
允许子控件采用父控件的宽度而不显示滚动条。
<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 >
【讨论】:
【参考方案5】:默认情况下Grid
应该占据ListBox
的整个宽度,因为它的默认ItemsPanel
是VirtualizingStackPanel
。我假设您没有更改了ListBox.ItemsPanel
。
也许如果你去掉中间的ColumnDefinition
(其他是默认的"*"
),把HorizontalAlignment="Left"
放在你的WrapPanel
和HorizontalAlignment="Right"
放在ListBox
的电话号码上。您可能需要稍微更改 ListBox
以使电话号码更加右对齐,例如为它们创建一个 DataTemplate
。
【讨论】:
【参考方案6】:如果您想使用Grid
,那么您需要将您的ColumnDefinition
s 更改为:
<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"
的控件都将填充剩余空间。
【讨论】:
这不会使数据模板填充列表框的宽度。 您需要在列表框上使用 HorizontalContentAlignment="Stretch",如下所述【参考方案7】:Taeke 的回答效果很好,根据 vancutterromney 的回答,您可以禁用水平滚动条以摆脱恼人的尺寸不匹配。但是,如果您确实想要两全其美——在不需要时移除滚动条,但在 ListBox 变得太小时自动启用它,您可以使用以下转换器:
/// <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>
然后在Width绑定中使用转换器:
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="RelativeSource Mode=FindAncestor, AncestorType=x:Type ScrollContentPresenter" Converter="StaticResource conDoubleLimiter" />
</Grid.Width>
【讨论】:
【参考方案8】:Taeke 的答案中的方法强制水平滚动条。这可以通过添加一个转换器来解决,该转换器将网格的宽度减小垂直滚动条控件的宽度。
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>
【讨论】:
这应该用 HorizontalContentAlignment 来完成。 @EdPlunkett 你的意思是 ListBox 上的 HorizontalContentAlignment,就像 Eric Haskins 接受的答案一样?如果是这样,我无法让它发挥作用,这就是为什么我转向这种更糟糕的方法。 天啊,正确的一般答案甚至不在此页面上。答案在这里:***.com/a/2924249/424129 -- 在列表框中的列表框 item 控件上设置HorizontalContentAlignment="Stretch"
,您可以通过ListBox.ItemContainerStyle
执行此操作。
@EdPlunkett 我确实遇到了那个答案,但除非我一直忽略一些简单的东西,否则它也不适合我。可能是因为我使用的是数据模板。以上是关于如何使 WPF 数据模板填充列表框的整个宽度?的主要内容,如果未能解决你的问题,请参考以下文章
选择时如何让wpf listboxitem拉伸列表框的整个高度
C#WPF如何在由数据模板中的对象列表组成的列表框中设置项目[重复]