Как заставить шаблон данных WPF заполнить всю ширину списка?

StackOverflow https://stackoverflow.com/questions/135375

Вопрос

у меня есть 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.

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

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

Возможно, если бы вы избавились от середины ColumnDefinition (остальные по умолчанию "*"), и положи HorizontalAlignment="Left" на ваше WrapPanel и HorizontalAlignment="Right" на ListBox для телефонных номеров.Возможно, вам придется это изменить ListBox немного, чтобы номера телефонов были еще более выровнены по правому краю, например, создав 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" определенный заполнит оставшееся пространство.

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

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

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>
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top