开发者

silverlight xaml layout issue: grid should be able to grow, but not off the screen

See the following XAML:

<UserControl xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" x:Class="SilverlightApplication1.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400" MinHeight="150">
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <sdk:DataGrid x:Name="grid" VerticalScrollBarVisibility="Visible" />
        <Button x:Name="button" Grid.Row="1" Content="hello" VerticalAlignment="Top" HorizontalAlignment="Center" Click="button_Click" />
    </Grid>
</UserControl>

Corresponding code:

public partial class MainPage : UserControl
{
    public class dataclass
    {
        public string data { get; set; }
    }

    ObservableCollection<dataclass> list;

    public MainPage()
    {
        InitializeComponent();
        grid.ItemsSource = list = new ObservableCollection<dataclass>();
    }

    private void button_Click(object sender, RoutedEventArgs e)
    {
        for (var i = 0; i < 5; i++)
            list.Add(new dataclass
            {
                data = "hello" + i
            });
    }
}

How it works now: The grid takes up the entire screen height minus the height of the button. When too many new items are added, you scan start scrolling. The position of the button never changes, it's always at the bottom of the screen.

What I would like: The grid should take up as little space as possible, so when it's empty, only the header should be visible, and the button immediately below it. When too many items are added, and the button is already at the bott开发者_如何转开发om of the screen, it shouldn't grow any more, but start scrolling instead.

If I swap the two RowDefinition's, then the grid is small at first, but grows indefinitely, pushes the button off the screen and never starts scrolling. How can I do this nicely?


In order to achieve this, nest another Grid in LayoutRoot and then use that nested grid as your main one. Then set both rows to Auto.

 <Grid x:Name="LayoutRoot" Background="White">
     <Grid x:Name="innerGrid">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <Grid x:Name="itemInTheFirstRow" Grid.Row="0" />
        <Button x:Name="itemInTheSecondRow" Grid.Row="1" />
     </Grid>
 </Grid>

Finally, you need to track the size of the grid and change the sizing rules accordingly. This "pinning" code looks something like.

RowDefinition row = this.innerGrid.RowDefinitions[0];
if (row.Height.GridUnitType == GridUnitType.Auto)
{
    if (this.innerGrid.ActualHeight > this.ActualHeight)
    {
        row.Height = new GridLength(1, GridUnitType.Star);
    }
}
else
{
    if (this.itemInTheFirstRow.DesiredSize.Height < row.ActualHeight)
    {
        row.Height = GridLength.Auto;
    }
}

In my implementation, I wrap this code in an UpdateRowPinning method that actually uses the dispatcher to call this code. I then call UpdateRowPinning on resize events for the main grid and the inner grid as well as on adding and removing items from the grid and expand/collapse operations of grid groups. This ensures that the second row behaves properly by sitting at the base of the first row until the screen is full and then floating over it after that.

My answer here also covers this issue. I searched for a XAML only solution but it just doesn't seem possible (unless you write some XAML extensions, then you might be able to pull it off with XAML but that's kind of cheating).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜