3
votes

I am trying to figure out how to use a WPF list box in conjunction with a window that has its SizeToContent property set to WidthAndHeight. The MainWindow has a grid with two rows and two columns. In the bottom right quadrant, I have a list box. I want the rest of the controls in the window to control the size of the window, and the list box to simply fill the available space. Currently, the list box is expanding to fit its contents, which causes the entire MainWindow to expand.

Note: I attempted to create a simple example, but want to point out that in my real scenario I'm using MVVM, and the controls that I want to determine the window width/height are bound to properties in a viewmodel that have their values set after the window is loaded.

Edit to add: The list box is bound to its content before the controls that I want to determine size are, and I don't have control over that.

Here is what the MainWindow currently looks like at startup:

enter image description here

Notice the red and blue bars which indicate what I'm not wanting to happen. Content in that area should only be visible by scroll bars.

Here is what I want the MainWindow to look like at startup:

enter image description here

Notice the size of the MainWindow is determined by the text blocks along the top and left sides, and the list box fills the available space and uses scrollbars if necessary.

Here is some sample code...

MainWindow.xaml:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" SizeToContent="WidthAndHeight">

<Grid>   
    <Grid.RowDefinitions>
        <RowDefinition Height="auto"/>
        <RowDefinition Height="auto"/>
        <RowDefinition />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="auto"/>
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <Grid Grid.Column="1">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto"/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <TextBlock Text="The window should fit to the width of this" FontSize="15"/>

        <Canvas Background="Red" Grid.Column="1"/>
    </Grid>

    <Grid Grid.Row="1" Grid.RowSpan="2">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>

        <TextBlock Text="The window should fit to the height of this" FontSize="15">
            <TextBlock.LayoutTransform>
                <RotateTransform Angle="-90"/>
            </TextBlock.LayoutTransform>
        </TextBlock>

        <Canvas Background="Blue" Grid.Row="1"/>
    </Grid>

    <Grid Grid.Row="2" Grid.Column="1">
        <ListBox Name="ListBox1">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Grid>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();

        var Messages = new ObservableCollection<string>() { "This is a long string to demonstrate that the list box content is determining window width" };

        for (int i = 0; i < 16; i++)
            Messages.Add("Test" + i);

        for (int i = 0; i < 4; i++)
            Messages.Add("this text should be visible by vertical scrollbars only");

        ListBox1.ItemsSource = Messages;
    }
}
1

1 Answers

0
votes

Set the list box ItemsSource, and set SizeToContent=Manual after the Window has loaded.

public MainWindow()
{
    InitializeComponent();

    Loaded += OnLoaded;
}

private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
    SizeToContent = SizeToContent.Manual;

    var messages = new ObservableCollection<string>
        {
            "This is a long string to demonstrate that the list" + 
            " box content is determining window width"
        };

    for (int i = 0; i < 16; i++)
    {
        messages.Add("Test" + i);
    }

    for (int i = 0; i < 4; i++)
    {
        messages.Add("this text should be visible by vertical scrollbars only");
    }

    ListBox1.ItemsSource = messages;
}

In this way the main window is initially sized to fit the content (with no data in the listbox), and then the listbox displays its items with scrollbars.