Making a Scrollviewer fill the available space in a DockPanel

I somewhat of a WPF noob and am using a DockPanel to display the text content of an email in a TextBox in a ScrollViewer. The panel has a button bar and area for the email headers at the top, a button bar at the bottom, a panel at the right and the email itself should fill the remaining space dynamically:

[Banner at top, below which is a button bar and box with email headers. At the bottom is another full width button bar. The space between them is divided into a fixed-width panel at the right and a large text box for the email contents.] http://rowlandsoftware.com/Screenshots/LongEmail.png

(The DockPanel sits inside a grid that provides the bit at the very top and is used when the email is not visible.)

The problem is that if the email is too short or too narrow, the textbox fails to fill the remaining width. In this screenshot, you can see some of the underlying stuff between the box and the panel:

[Between the text box and the panel is a column that is not filled. Part of what lies under it can be seen.] http://rowlandsoftware.com/Screenshots/TooNarrow.png

The XAML is:

<DockPanel x:Name="EmailCanvas" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Visibility="Collapsed" Height="Auto">
    <DockPanel x:Name="topButtonBar" DockPanel.Dock="Top" Height="50" Background="White">
        <Button x:Name="btnReturn" DockPanel.Dock="Left" Content="Return to List" Click="btnReturn_Click" />
        <Image Width="15" Source="Images/transparent.png" />
        <Button x:Name="btnTextToggle" Content="Plain text" Click="btnTextToggle_Click" />
        <Button x:Name="btnZoomOut" Content="Zoom Out" />
        <Button x:Name="btnZoomIn" Content="Zoom In" />
        <Image Width="150" DockPanel.Dock="Right" Source="Images/transparent.png" />
        <Button x:Name="btnPrint" DockPanel.Dock="Right" Content="Print" Width="100"/>
        <Image DockPanel.Dock="Right" Source="Images/transparent.png" />
    </DockPanel>
    <StackPanel x:Name="EmailHeaders" Orientation="Horizontal" DockPanel.Dock="Top" Width="Auto" Background="Linen">
        <StackPanel Orientation="Vertical">
            <TextBlock Text="Subject:" FontSize="16" />
            <TextBlock Text="Time Sent:" FontSize="16"/>
            <TextBlock Text="Other Recipients: " FontSize="16"/>
        </StackPanel>
        <StackPanel Orientation="Vertical">
            <TextBlock x:Name="labSubject" Text="Subject:" FontSize="16" />
            <TextBlock x:Name="labDateTime" Text="Sent:" FontSize="16"/>
            <TextBlock x:Name="labSpare" Text="Other Recipients:" FontSize="14"/>
        </StackPanel>
    </StackPanel>
    <DockPanel x:Name="bottomButtonBar" DockPanel.Dock="Bottom" Height="80" >
        <Image Width="150" DockPanel.Dock="Left" Source="Images/transparent.png" />
        <Button x:Name="btnDelete" DockPanel.Dock="Left" Content="Delete" />
        <Image Width="150" Source="Images/transparent.png" />
        <Button x:Name="btnSave" Content="Save" />
        <Image Width="150" Source="Images/transparent.png" />
        <Button x:Name="btnReply" Content="Reply" />
        <Image Width="150" DockPanel.Dock="Right" Source="Images/transparent.png" />
    </DockPanel>
    <StackPanel DockPanel.Dock="Right" Orientation="Vertical" Background="White" Width="150">
        <Button x:Name="btnAttachments" Content="Attachment"/>
    </StackPanel>
    <ScrollViewer x:Name="eTextViewer" VerticalScrollBarVisibility="Auto" HorizontalAlignment="Stretch" HorizontalContentAlignment="Stretch">
        <TextBox x:Name="eText" Background="White" HorizontalAlignment="Stretch" TextWrapping="Wrap" FontFamily="Verdana" FontSize="18" IsReadOnly="True" />
    </ScrollViewer>
    <!--Image Width="Auto" Height="Auto" DockPanel.Dock="Bottom" Source="Images/white.png" /-->
    <WebBrowser x:Name="eHTML" Height="Auto" DockPanel.Dock="Top" Visibility="Collapsed" />
</DockPanel>

The box is extended only to fill the available height, not the width. The documentation for the DockPanel.LastChildFill Property says,

If you set the LastChildFill property to true, which is the default setting, the last child element of a DockPanel always fills the remaining space, regardless of any other dock value that you set on the last child element.

msdn.microsoft.com/en-us/library/system.windows.controls.dockpanel.lastchildfill%28v=vs.110%29.aspx

That does not appear to be the case: in my program it is only filling height, not width. LastFillChild=true is the default, but explicitly setting it to True or False doesn't make a blind bit of difference.

Interestingly, if you set DockPanel.Dock="Top" on the ScrollViewer, it fills the available width but not the height, leaving some of the underlying stuff showing between the text box and the bottom button bar. Again this is contrary to the documentation which says that the dock value set on the last child element is ignored.

Setting HorizontalAlignment="Stretch" to both the ScrollViewer and the TextBox and HorizontalContentAlignment="Stretch" to the ScrollViewer makes not a jot of difference.

So my question is, how can I ensure that the textbox fills the available space in the DockPanel even when the contents of the email are too short?

UPDATE: I have just noticed that if I remove the WebBrowser that is set initially to Visibility="Collapsed", then it works fine. I guess that its presence fools the DockPanel into regarding it as the LastChild even though it is Collapsed.

However, I need to toggle between displaying the email in the web browser and the text box, so removing it isn't an option. Both need to be treated as last child when they are visible. Any ideas?

UPDATE 2: So I wrap the scrollviewer and the web browser in another container, eg grid, which is the Last Child. Then I can toggle between the the two but they both fill the space.

Thanks guys. I wouldn't have got there without humiliating myself in public ;)


DockPanel will work, but beware of Collapsed items. Although the documentation says that a collapsed item has no effect on layout, with DockPanel it does if it is the LastChild. The solution in my case was to add another container as the last child, and place the two items that I wanted to toggle between in that container. Then both will fill the remaining space in the panel.

链接地址: http://www.djcxy.com/p/50078.html

上一篇: C ++单例设计模式

下一篇: 使滚动查看器填充DockPanel中的可用空间