Como posso fazer uma WPF modelo de dados preencher toda a largura da caixa de listagem?
-
02-07-2019 - |
Pergunta
Eu tenho um ListBox
DataTemplate
em WPF. Eu quero um item para ser apertado contra o lado esquerdo do ListBox
e outro item a ser apertado contra o lado direito, mas eu não consigo descobrir como fazer isso.
Até agora eu tenho um Grid
com três colunas, os esquerdo e direito tem conteúdo e o centro é um espaço reservado com o seu conjunto de largura para "*". Onde estou indo errado?
Aqui está o código:
<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>
Solução
Eu também tive que set:
HorizontalContentAlignment="Stretch"
no ListBox
contendo.
Outras dicas
<Grid.Width>
<Binding Path="ActualWidth"
RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" />
</Grid.Width>
Ok, aqui está o que você tem:
Coluna 0: WrapPanel
Coluna 1: Nada
Coluna 2: ListBox
Parece que você quer WrapPanel
na borda esquerda, ListBox
na margem direita, e espaço para pegar o que sobrou no meio.
A maneira mais fácil de fazer isso é realmente usar um DockPanel
, não um Grid
.
<DockPanel>
<WrapPanel DockPanel.Dock="Left"></WrapPanel>
<ListBox DockPanel.Dock="Right"></ListBox>
</DockPanel>
Isso deve deixar espaço vazio entre a WrapPanel
eo ListBox
.
Estendendo resposta de Taeke, definindo o ScrollViewer.HorizontalScrollBarVisibility="Hidden"
para uma ListBox
permite o controle filho para tomar a largura do pai e não tem a barra de rolagem aparecer.
<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 >
O Grid
deve por padrão, tomai toda a largura da ListBox
porque o ItemsPanel
padrão para ele é um VirtualizingStackPanel
. Estou assumindo que você tem não mudou ListBox.ItemsPanel
.
Talvez se você se livrou do ColumnDefinition
meio (os outros são "*"
padrão), e colocar HorizontalAlignment="Left"
em seu WrapPanel
e HorizontalAlignment="Right"
na ListBox
para números de telefone. Você pode ter que alterar essa ListBox
um pouco para obter os números de telefone ainda mais alinhado à direita, como a criação de um DataTemplate
para eles.
Se você quiser usar um Grid
, então você precisa mudar seus ColumnDefinition
s a ser:
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
Se você não precisa usar um Grid
, em seguida, você poderia usar um 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>
Observe o TextBlock
no final. Qualquer controle sem "DockPanel.Dock"
definido irá preencher o espaço restante.
A resposta de Taeke funciona bem, e de acordo com a resposta de vancutterromney você pode desativar a barra de rolagem horizontal para se livrar da incompatibilidade de tamanho de irritante. No entanto, se você quer o melhor de dois mundos - para remover a barra de rolagem, quando não é necessário, mas tê-lo automaticamente ativado quando o ListBox torna-se muito pequeno, você pode usar o seguinte conversor:
/// <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();
}
}
Em seguida, definem-lo em XAML de acordo com os valores / min max desejadas, bem como um deslocamento de lidar com esse tamanho irritante incompatibilidade 2-pixel como indicado nas outras respostas:
<ListBox.Resources>
<con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/>
</ListBox.Resources>
Em seguida, use o conversor na Largura de ligação:
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{StaticResource conDoubleLimiter}" />
</Grid.Width>
O método nas forças resposta do Taeke uma barra de rolagem horizontal. Isso pode ser corrigido através da adição de um conversor para reduzir a largura da grade pela largura do controle de barra de rolagem vertical.
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());
}
}
}
Adicionar um espaço de nomes para o nó de raiz do seu XAML.
xmlns:converters="clr-namespace:Converters"
E atualizar a largura da grade de usar o conversor.
<Grid.Width>
<Binding Path="ActualWidth" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType={x:Type ScrollContentPresenter}}" Converter="{converters:ListBoxItemWidthConverter}"/>
</Grid.Width>