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

时间:2022-01-19 22:37:24

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

我在WPF中有一个ListBox DataTemplate。我想要一件物品紧靠在列表框的左边,另一件物品紧靠右边,但是我不知道怎么做。

So far I have a Grid with 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?

到目前为止,我有一个包含三列的网格,左边和右边都有内容,中间是一个占位符,宽度设置为“*”。我哪里做错了?

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>

8 个解决方案

#1


132  

I also had to set:

我还必须设置:

HorizontalContentAlignment="Stretch"

on the containing ListBox.

包含列表框。

#2


20  

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

#3


4  

Ok, here's what you have:

好的,这是你的答案:

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

列0:WrapPanel列1:没有列2:列表框。

It sounds like you want WrapPanel on the left edge, ListBox on 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.

最简单的方法是使用DockPanel,而不是网格。

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

This should leave empty space between the WrapPanel and the ListBox.

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

#4


2  

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

扩展Taeke的答案,设置ScrollViewer。HorizontalScrollBarVisibility="Hidden" for a 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


1  

The Grid should by default take up the whole width of the ListBox because the default ItemsPanel for it is a VirtualizingStackPanel. I'm assuming that you have not changed ListBox.ItemsPanel.

默认情况下,网格应该占据列表框的整个宽度,因为默认的ItemsPanel是一个VirtualizingStackPanel。我假设您没有更改list . itemspanel。

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

如果您删除了中间的ColumnDefinition(其他的是默认的“*”),并将horizontalalign ="Left"放在WrapPanel上,horizontalalign ="Right"放在电话号码的列表框上。您可能需要稍微修改一下列表框,以使电话号码更加正确,例如为它们创建一个DataTemplate。

#6


1  

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

如果要使用网格,则需要将列定义更改为:

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

如果您不需要使用网格,那么您可以使用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 TextBlock at the end. Any control with no "DockPanel.Dock" defined will fill the remaining space.

注意末尾的TextBlock。任何没有“DockPanel”的控件。“已定义的Dock”将填充其余的空间。

#7


0  

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:

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

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

#8


0  

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>

#1


132  

I also had to set:

我还必须设置:

HorizontalContentAlignment="Stretch"

on the containing ListBox.

包含列表框。

#2


20  

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

#3


4  

Ok, here's what you have:

好的,这是你的答案:

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

列0:WrapPanel列1:没有列2:列表框。

It sounds like you want WrapPanel on the left edge, ListBox on 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.

最简单的方法是使用DockPanel,而不是网格。

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

This should leave empty space between the WrapPanel and the ListBox.

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

#4


2  

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

扩展Taeke的答案,设置ScrollViewer。HorizontalScrollBarVisibility="Hidden" for a 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


1  

The Grid should by default take up the whole width of the ListBox because the default ItemsPanel for it is a VirtualizingStackPanel. I'm assuming that you have not changed ListBox.ItemsPanel.

默认情况下,网格应该占据列表框的整个宽度,因为默认的ItemsPanel是一个VirtualizingStackPanel。我假设您没有更改list . itemspanel。

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

如果您删除了中间的ColumnDefinition(其他的是默认的“*”),并将horizontalalign ="Left"放在WrapPanel上,horizontalalign ="Right"放在电话号码的列表框上。您可能需要稍微修改一下列表框,以使电话号码更加正确,例如为它们创建一个DataTemplate。

#6


1  

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

如果要使用网格,则需要将列定义更改为:

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

如果您不需要使用网格,那么您可以使用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 TextBlock at the end. Any control with no "DockPanel.Dock" defined will fill the remaining space.

注意末尾的TextBlock。任何没有“DockPanel”的控件。“已定义的Dock”将填充其余的空间。

#7


0  

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:

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

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

#8


0  

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>