如何使 WPF 数据模板填充列表框的整个宽度?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/135375/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 19:39:30  来源:igfitidea点击:

How do I make a WPF data template fill the entire width of the listbox?

wpflayoutlistboxdatatemplate

提问by Eric Haskins

I have a ListBoxDataTemplatein WPF. I want one item to be tight against the left side of the ListBoxand another item to be tight against the right side, but I can't figure out how to do this.

ListBoxDataTemplate在 WPF 中有一个。我希望一件物品紧贴左侧ListBox,另一件紧贴右侧,但我不知道如何做到这一点。

So far I have a Gridwith three columns, the left and right ones have content and the center is a placeholder with it's width set to "*". Where am I going wrong?

到目前为止,我有一个Grid三列,左右两列有内容,中心是一个占位符,其宽度设置为“*”。我哪里错了?

Here is the 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>

回答by Eric Haskins

I also had to set:

我还必须设置:

HorizontalContentAlignment="Stretch"

on the containing ListBox.

在包含ListBox.

回答by Taeke

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

回答by 17 of 26

Ok, here's what you have:

好的,这是你所拥有的:

Column 0: WrapPanel
Column 1: Nothing
Column 2: ListBox

第 0 列:WrapPanel
第 1 列:无
第 2 列:ListBox

It sounds like you want WrapPanelon the left edge, ListBoxon the right edge, and space to take up what's left in the middle.

听起来你想要WrapPanel在左边缘、ListBox右边缘和空间来占据中间剩下的东西。

Easiest way to do this is actually to use a DockPanel, not a Grid.

最简单的方法实际上是使用 a DockPanel,而不是 a Grid

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

This should leave empty space between the WrapPaneland the ListBox.

这应该在WrapPanel和之间留下空白空间ListBox

回答by vancutterromney

Extending Taeke's answer, setting the ScrollViewer.HorizontalScrollBarVisibility="Hidden"for a ListBoxallows the child control to take the parent's width and not have the scroll bar show up.

扩展 Taeke 的答案,设置ScrollViewer.HorizontalScrollBarVisibility="Hidden"for aListBox允许子控件采用父控件的宽度而不显示滚动条。

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

回答by Phobis

If you want to use a Grid, then you need to change your ColumnDefinitions to be:

如果要使用 a Grid,则需要将ColumnDefinitions更改为:

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

If you don't need to use a Grid, then you could use a DockPanel:

如果您不需要使用 a Grid,那么您可以使用 a 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>

Notice the TextBlockat the end. Any control with no "DockPanel.Dock"defined will fill the remaining space.

注意TextBlock最后。任何"DockPanel.Dock"未定义的控件将填充剩余空间。

回答by Joel B Fant

The Gridshould by default take up the whole width of the ListBoxbecause the default ItemsPanelfor it is a VirtualizingStackPanel. I'm assuming that you have notchanged ListBox.ItemsPanel.

Grid默认情况下应承担的整个宽度ListBox,因为默认ItemsPanel它是一个VirtualizingStackPanel。我假设你没有改变ListBox.ItemsPanel

Perhaps if you got rid of the middle ColumnDefinition(the others are default "*"), and put HorizontalAlignment="Left"on your WrapPaneland HorizontalAlignment="Right"on the ListBoxfor phone numbers. You may have to alter that ListBoxa bit to get the phone numbers even more right-aligned, such as creating a DataTemplatefor them.

也许如果你去掉中间的ColumnDefinition(其他是默认的"*"),并把HorizontalAlignment="Left"你的WrapPanelHorizontalAlignment="Right"放在ListBox电话号码上。您可能需要ListBox稍微更改一下以使电话号码更加右对齐,例如DataTemplate为它们创建一个。

回答by BCA

Taeke's answer works well, and as per vancutterromney's answer you can disable the horizontal scrollbar to get rid of the annoying size mismatch. However, if you do want the best of both worlds--to remove the scrollbar when it is not needed, but have it automatically enabled when the ListBox becomes too small, you can use the following converter:

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

Then define it in XAML according to the desired max/min values, as well an offset to deal with that annoying 2-pixel size mismatch as mentioned in the other answers:

然后根据所需的最大/最小值在 XAML 中定义它,以及处理其他答案中提到的令人讨厌的 2 像素大小不匹配的偏移量:

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

Then use the converter in the Width binding:

然后在 Width 绑定中使用转换器:

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

回答by Kevin Hilt

The method in Taeke's answer forces a horizontal scroll bar. This can be fixed by adding a converter to reduce the grid's width by the width of the vertical scrollbar control.

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

Add a namespace to the root node of your XAML.

将命名空间添加到 XAML 的根节点。

xmlns:converters="clr-namespace:Converters"

And update the Grid width to use the converter.

并更新网格宽度以使用转换器。

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