2008-09-25 8 views
55

Mam ListBoxDataTemplate w WPF. Chcę, aby jeden element był ciasny po lewej stronie ListBox i inny element, który powinien być ciasny po prawej stronie, ale nie mogę wymyślić, jak to zrobić.Jak utworzyć szablon danych WPF wypełnić całą szerokość listbox?

Do tej pory mam z trzema kolumnami, lewy i prawy mają treść, a środek jest symbolem zastępczym, którego szerokość jest ustawiona na "*". Gdzie się mylę?

Oto kod:

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

Czy możesz zamieścić swój XAML, aby było jasne, co masz do tej pory? –

Odpowiedz

129

miałem również ustawić:

HorizontalContentAlignment="Stretch" 

na zawierające ListBox.

+5

Ta pal. Googled o pomoc i to było na pierwszym linku. Nice one :) –

+0

@Eric Haskins Mam ten sam rodzaj problemu dla kontroli Pivot dla Windows Phone ('') Ale gdzie powinienem umieścić ten kod? Próbowałem, ale nie mogłem tego rozgryźć. – SynerCoder

+7

Uwaga dla użytkowników Windows Phone - to nie zadziała; właściwość zostaje nadpisana przez ItemBoxSearle ListBox. Aby to zadziałało, zobacz odpowiedź Gabriel Mongeon tutaj: http://stackoverflow.com/questions/838828/how-to-get-a-listbox-itemtemplate-to-stretch-horizontally-the-full-width-of- –

1

Grid domyślnie powinien trwać całą szerokość ListBox ponieważ domyślna ItemsPanel dla niego jest VirtualizingStackPanel. Zakładam, że masz nie zmieniony .

Może gdybyś pozbył środkowych ColumnDefinition (pozostałe są domyślne "*") i umieścić HorizontalAlignment="Left" na WrapPanel i HorizontalAlignment="Right" na ListBox dla numerów telefonów. Być może będziesz musiał nieco zmienić ten kod, aby uzyskać jeszcze lepsze wyrównanie numerów telefonu, na przykład utworzyć dla nich DataTemplate.

4

Ok, oto co trzeba:

Kolumna 0: WrapPanel
Kolumna 1: Nic
Kolumna 2: ListBox

Brzmi jak chcesz WrapPanel na lewym brzegu, ListBox po prawej krawędź i przestrzeń, by zająć to, co zostało w środku.

Najprostszym sposobem na to jest użycie DockPanel, a nie Grid.

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

Należy pozostawić pustą przestrzeń pomiędzy WrapPanel i ListBox.

1

Jeśli chcesz użyć Grid, to trzeba zmienić ColumnDefinition do bycia:

<Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto"/> 
     <ColumnDefinition Width="*"/> 
     <ColumnDefinition Width="Auto"/> 
    </Grid.ColumnDefinitions> 

Jeśli nie trzeba używać Grid, wówczas można użyć 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> 

Zauważ TextBlock na końcu. Każda kontrolka bez zdefiniowanej wartości "DockPanel.Dock" wypełni pozostałą przestrzeń.

+4

To NIE powoduje, że datatemplate wypełnia szerokość listbox. –

+2

Musisz użyć HorizontalContentAlignment = "Stretch" w polu listy, jak wspomniano poniżej – cbeuker

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

Uwielbiam prostotę tego podejścia. Nie tylko zapewnia, że ​​małe elementy wypełniają szerokość, ale także zapewnia, że ​​elementy, których zawartość wolałaby być bardzo szeroka, są ograniczone do szerokości listy. –

+0

Dokładnie to, czego szukałem: Wypełnianie szerokości, gdy jest zbyt mała i ograniczenie szerokości, gdy jest zbyt duży. – Lensflare

+1

Po prostu zauważyłem, że to rozwiązanie powoduje, że szerokość ListBox jest stale nieco mniejsza niż szerokość elementu, co powoduje odcięcie elementów i uaktywnia poziomy pasek przewijania u dołu listy. Naprawiłem to, wyraźnie wyłączając przewijanie w poziomie. – Lensflare

2

Rozszerzanie Taeke za odpowiedź, ustawienie ScrollViewer.HorizontalScrollBarVisibility="Hidden" dla ListBox umożliwia kontrolę dziecka do szerokości rodzica i nie ma paska przewijania pokazać.

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

odpowiedź Taeke za dobrze, a co za odpowiedź vancutterromney może wyłączyć pasek przewijania poziomego, aby pozbyć się uciążliwego wielkości niedopasowania. Jednakże, jeśli nie chcemy, co najlepsze z obu światów - usunięcie paska przewijania, gdy nie jest potrzebny, ale to automatycznie włączane, gdy ListBox staje się zbyt mała, można użyć następującego Przelicznik:

/// <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(); 
    } 
} 

Następnie zdefiniować go w XAML według żądanych wartości max/min, a także przesunięcie do czynienia z tym przykry wielkości niedopasowania 2 pikseli, jak wspomniano w innych odpowiedzi:

<ListBox.Resources> 
    <con:DoubleLimiterConverter x:Key="conDoubleLimiter" Min="450" Offset="-2"/> 
</ListBox.Resources> 

następnie użyć konwertera w wiązaniu Szerokość:

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

Metoda w odpowiedzi Taeke wymusza poziomy pasek przewijania. Można to naprawić, dodając konwerter, aby zmniejszyć szerokość siatki o szerokość pionowego paska przewijania.

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()); 
     } 
    } 
} 

Dodaj przestrzeń nazw do głównego węzła swojego XAML.

xmlns:converters="clr-namespace:Converters" 

Zaktualizuj szerokość siatki, aby użyć konwertera.

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

Należy tego dokonać za pomocą HorizontalContentAlignment. –

+0

@EdPlunkett Czy chodzi o HorizontalContentAlignment na ListBox, jak w przyjętej odpowiedzi Eric Haskins? Jeśli tak, nie mogłem tego zrobić, dlatego przeniosłem tę gorszą metodę. –

+0

OMG, poprawna ogólna odpowiedź nie jest nawet na tej stronie. To jest w tej odpowiedzi tutaj: https://stackoverflow.com/a/2924249/424129 - ustaw "HorizontalContentAlignment =" Stretch "' na listbox * element * formanty w polu listy, które robisz za pomocą 'ListBox.ItemContainerStyle'. –

Powiązane problemy