Как сделать так, чтобы шаблон данных WPF заполнял всю ширину списка? - PullRequest
59 голосов
/ 25 сентября 2008

У меня есть ListBox DataTemplate в WPF. Я хочу, чтобы один предмет плотно прилегал к левой стороне 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>

Ответы [ 8 ]

135 голосов
/ 26 сентября 2008

Я также должен был установить:

HorizontalContentAlignment="Stretch"

на содержащие ListBox.

23 голосов
/ 15 января 2011
<Grid.Width>
    <Binding Path="ActualWidth" 
             RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
</Grid.Width>
4 голосов
/ 26 сентября 2008

Хорошо, вот что у вас есть:

Столбец 0: WrapPanel
Колонка 1: Ничего
Колонка 2: ListBox

Звучит так, как будто вы хотите WrapPanel на левом краю, ListBox на правом краю и место, чтобы занять то, что осталось в середине.

Самый простой способ сделать это - использовать DockPanel, а не Grid.

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

Это должно оставить пустое пространство между WrapPanel и ListBox.

2 голосов
/ 10 октября 2012

Расширяя ответ Тэке, установка 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 >
1 голос
/ 26 сентября 2008

Если вы хотите использовать 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" заполнит оставшееся пространство.

1 голос
/ 26 сентября 2008

Grid должен по умолчанию занимать всю ширину ListBox, потому что по умолчанию ItemsPanel для него - VirtualizingStackPanel. Я предполагаю, что вы не изменили ListBox.ItemsPanel.

Возможно, если вы избавились от середины ColumnDefinition (остальные по умолчанию "*"), и поставили HorizontalAlignment="Left" на свои WrapPanel и HorizontalAlignment="Right" на ListBox для телефонных номеров. Возможно, вам придется немного изменить это значение ListBox, чтобы телефонные номера стали еще лучше выровнены, например, создать для них DataTemplate.

0 голосов
/ 23 июня 2017

Метод в ответе Тэке вызывает горизонтальную полосу прокрутки. Это можно исправить, добавив конвертер, чтобы уменьшить ширину сетки на ширину элемента управления вертикальной полосы прокрутки.

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>
0 голосов
/ 19 ноября 2016

Ответ Тэке работает хорошо, и в соответствии с ответом Ванцутерромнея вы можете отключить горизонтальную полосу прокрутки, чтобы избавиться от досадного несоответствия размеров. Однако, если вы хотите получить лучшее из обоих миров - убрать полосу прокрутки, когда она не нужна, но включить ее автоматически, когда 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>

Затем используйте конвертер в привязке ширины:

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