0

I'm trying to put a StackPanel inside a ListBox and this inside a Grid that is a part of a UserControl.

So far I have come up with the following XAML but I cannot fix the width. When you take a look at the screenshot you'll see that the StackPanel is few pixels too wide. I tried HorizontalAlignment=Stretch on every element but on the Width={Binding...} manages to limt the width, although not perfectly. What do I miss?

<UserControl x:Class="Reusable.Apps.ExceptionControl"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:Reusable.Apps"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800" Width="{Binding (Window.Width), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}">
    <UserControl.Resources>
        <local:ExceptionVisualizerData x:Key="DesignViewModel" />
        <Style TargetType="TextBlock" x:Key="NameStyle">
            <Setter Property="FontSize" Value="20"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="FontFamily" Value="Consolas"/>
            <Setter Property="Foreground" Value="DarkMagenta"/>
        </Style>
        <Style TargetType="TextBlock" x:Key="MessageStyle">
            <Setter Property="FontSize" Value="16"></Setter>
            <Setter Property="FontFamily" Value="Segoe UI"/>
            <Setter Property="TextWrapping" Value="Wrap"/>
        </Style>
    </UserControl.Resources>
    <Grid Width="{Binding (UserControl.Width), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}}">
        <ListBox ItemsSource="{Binding Exceptions}" d:DataContext="{Binding Source={StaticResource DesignViewModel}}" Width="{Binding (Grid.Width), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel  Width="{Binding (ListBox.Width), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBox}}}">
                        <TextBlock Text="{Binding Name}" Style="{StaticResource NameStyle}"  />
                        <TextBlock Text="{Binding Message}" Style="{StaticResource MessageStyle}" />
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</UserControl>

enter image description here

t3chb0t
  • 16,340
  • 13
  • 78
  • 118

4 Answers4

1

Instead of referring to ListBox, refer width of ListBoxItem

<StackPanel  Width="{Binding (ListBoxItem.Width), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}">
Sats
  • 1,913
  • 1
  • 15
  • 21
  • Unfortunatelly this has not effect :-( – t3chb0t Dec 02 '18 at 12:24
  • This has worked in my local. Is it required to bind width ? I mean remove the Width from `StackPanel` and check. – Sats Dec 02 '18 at 12:28
  • Actually I find the `Width` binding ugly but it's the only way I could do it halfway work. I'd rather throw all this away if there was something better. – t3chb0t Dec 02 '18 at 12:31
  • This was close. Using the `ListBoxItem` was a good track but in the wrong place ;-) – t3chb0t Dec 03 '18 at 15:41
  • Wonder, why this was not working, even we are binding with the ListBoxItem.Wdth – Sats Dec 03 '18 at 15:47
  • I guess because the `ListBoxItem` itself was too wide so binding to its `Width` didn't solve it (this time?). It was apparently of unlimited width. – t3chb0t Dec 03 '18 at 15:48
  • 1
    Anyway, you succeeded in finding the solution. Mark your solution as answer, so that anyone suffering as you did will get the answer quick. -:) – Sats Dec 03 '18 at 15:52
  • I will, I just have to wait 19 hours until it's allowed, thanks for you input, it was a good hint as I didn't know about the `ListBoxItem` before ;-) – t3chb0t Dec 03 '18 at 15:54
1

It sounds like you should get rid of all the width bindings and just put a margin around your StackPanel, e.g:

<StackPanel Margin="10" >

--- UPDATED --

Frustrating is the right word. Okay, here's the solution.

(1) Replace StackPanel with Grid.

(2) In the ListBox, set ScrollViewer.HorizontalScrollBarVisibility to "Disabled"

<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
        <Grid Margin="10" >
            <Grid.RowDefinitions>
                <RowDefinition />
                <RowDefinition />
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Text="Title" Style="{StaticResource NameStyle}"  />
            <TextBlock Grid.Row="1" TextWrapping="Wrap" Text="lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text lots of text " Style="{StaticResource MessageStyle}" />
        </Grid>
    </ListBox>

This should do the trick.

DPH
  • 290
  • 1
  • 12
  • mhmm... I removed all `Width` bindings and it's definitely the damn `StackPanel` and when not bound to the `ListBox` then it's too wide and text wrap does not work and when it's bound it's always few pixels wider. This is so insane and frustrating :-( – t3chb0t Dec 02 '18 at 13:01
1

I finally got it! I found a similar question and adopted its answer to my needs:

<Grid >
    <ListBox ItemsSource="{Binding Exceptions}" d:DataContext="{Binding Source={StaticResource DesignViewModel}}" Margin="30" >
        <ListBox.ItemContainerStyle>
            <Style TargetType="ListBoxItem">
                <Setter Property="Width" Value="{Binding (Grid.ActualWidth), RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Grid}}}" />
            </Style>
        </ListBox.ItemContainerStyle>
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Name}" Style="{StaticResource NameStyle}"  />
                    <TextBlock Text="{Binding Message}" Style="{StaticResource MessageStyle}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

The trick was to bind the Width of the ListBoxItem to the parent. Holy cow! This was tricky. Now it also nicely scales when resizing the window.

t3chb0t
  • 16,340
  • 13
  • 78
  • 118
1

The reason for the overlap is due to the default template for a ListBoxItem, which has Padding set to "4,1" and a BorderThickness of "1" on both itself and the inner Border object. You can use a tool such as WPF Snoop to see this.

The solution is to bind to the ActualWidth of the next level of container, in this case the ContentPresenter.

<ListBox ItemsSource="{Binding DataItems}"
         ScrollViewer.HorizontalScrollBarVisibility="Disabled"
         HorizontalContentAlignment="Stretch">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Background="Yellow"
                  Width="{Binding RelativeSource={RelativeSource FindAncestor, 
                                                  AncestorType={x:Type ContentPresenter}}, 
                          Path=ActualWidth}">
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <TextBlock Grid.Row="0" Text="{Binding Id}" />
                <TextBlock Grid.Row="1" Text="{Binding Description}" TextWrapping="Wrap" />
        </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

Note the properties set on the ListBox, which prevent the content growing beyond the width of the ListBox, and forcing the content to resize as the ListBox width is increased.

Peregrine
  • 4,287
  • 3
  • 17
  • 34