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

У меня ListBoxDataTemplate в 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>

Можете ли вы опубликовать свой XAML, чтобы было понятно, что у вас есть на данный момент?

17 of 26 26.09.2008 00:00
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
63
1
55 607
8
Перейти к ответу Данный вопрос помечен как решенный

Ответы 8

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

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

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

Столбец 0: WrapPanel
. Столбец 1: Nothing
. Столбец 2: ListBox.

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

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

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

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

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

Это НЕ заставляет табличку данных заполнять всю ширину списка.

Kevin Berridge 11.05.2009 16:00

Вам необходимо использовать HorizontalContentAlignment = "Stretch" в списке, как указано ниже.

cbeuker 18.02.2011 02:42
Ответ принят как подходящий

Еще мне пришлось установить:

HorizontalContentAlignment = "Stretch"

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

Ta pal. Погуглил за помощью, и это было по первой ссылке. Хороший :)

Binary Worrier 21.03.2009 02:20

@Eric Haskins. У меня такая же проблема с элементом управления Pivot для Windows Phone (<controls:Pivot.ItemTemplate><DataTemplate /></controls:Pivot.ItemTemplate>). Но где мне поместить этот код? Я пробовал, но не мог понять.

SynerCoder 04.10.2012 19:30

Примечание для пользователей Windows Phone - это не сработает; свойство переопределяется ItemContainerStyle ListBox. Чтобы заставить его работать, см. Ответ Габриэля Монжеона здесь: stackoverflow.com/questions/838828/…

Carlos P 11.11.2012 14:11

Это должен быть один из самых раздражающих взломов пользовательского интерфейса. Почему это не установлено по умолчанию? Smh.

Matthew S 14.05.2018 20:17

Также стоит упомянуть, что вам может потребоваться установить это в стиле ListBoxItem, если он есть: <ListView.ItemContainerStyle> <Style TargetType = "ListViewItem"> <Setter Property = "HorizontalContentAlignment" Value = "Stretch" /> </Style> </ListView.ItemContainerStyle>

sergeantKK 10.04.2019 11:51

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

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

Mal Ross 19.08.2011 12:38

Именно то, что я искал: заполнение ширины, когда она слишком мала, и ограничение ширины, когда она слишком велика.

Lensflare 07.01.2016 15:43

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

Lensflare 07.01.2016 16:10

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

Ответ 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>

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

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

Это должно быть сделано с помощью HorizontalContentAlignment.

15ee8f99-57ff-4f92-890c-b56153 23.06.2017 01:39

@EdPlunkett Вы имеете в виду HorizontalContentAlignment в ListBox, как в принятом ответе Эрика Хаскинса? Если так, я не мог заставить это работать, поэтому я перешел на этот худший метод.

Kevin Hilt 23.06.2017 22:26

OMG, правильного общего ответа даже нет на этой странице. Вот этот ответ: stackoverflow.com/a/2924249/424129 - установите HorizontalContentAlignment = "Stretch" в список. предмет контролирует в списке, что вы делаете через ListBox.ItemContainerStyle.

15ee8f99-57ff-4f92-890c-b56153 23.06.2017 22:29

@EdPlunkett Я наткнулся на этот ответ, но если я не упущу из виду что-то простое, он также не работает для меня. Это может быть потому, что я использую шаблон данных.

Kevin Hilt 23.06.2017 22:54

Другие вопросы по теме