Ответ 1
Мне также пришлось установить:
HorizontalContentAlignment="Stretch"
на содержащем ListBox
.
У меня есть 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>
Мне также пришлось установить:
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
.
Расширение ответа Taeke, установка 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"
будет заполнять оставшееся пространство.
Ответ 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 в соответствии с желаемыми значениями max/min, а также смещением, чтобы справиться с этим раздражающим несоответствием размера 2 пикселя, как указано в других ответах:
<ListBox.Resources>
<con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/>
</ListBox.Resources>
Затем используйте конвертер в привязке Width:
<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());
}
}
}
Добавьте пространство имен в корень node вашего XAML.
xmlns:converters="clr-namespace:Converters"
И обновите ширину сетки, чтобы использовать конвертер.
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
</Grid.Width>