开发者

Wrapping panels in WPF

I have the following layout in my window:

  1. Grid with two columns
  2. GridSplitter which resizes grid columns
  3. Second grid column is filled with StackPanel
  4. StackPanel is oriented vertically and has 2 children: TextBlock and a WrapPanel
  5. WrapPanel has two Grids as children
  6. First Grid child contains one Image
  7. Second Grid contains a StackPanel with 3 TextBlocks oriented vertically.

The XAML code looks like this:

<Window>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Left" />
    <StackPanel Grid.Column="1" Margin="5,0,0,0" Orientation="Vertical" 
        HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
      <TextBlock Text="Now here's a silly poem for you." />
      <WrapPanel>
        <Grid Name="GridForImage">
          <Image Width="200" Height="200" Source="Image.jpg" />
        </Grid>
        <Grid Name="GridForText">
          <StackPanel Orientation="Vertical">
            <TextBlock TextWrapping="WrapWithOverflow" Text="Roses are red." />
            <TextBlock TextWrapping="WrapWithOverflow" Text="Violets are blue." />
            <TextBlock TextWrapping="WrapWithOverflow" Text="You belong in a zoo." />
          </StackPanel>
        </Grid>
      </WrapPanel>
    </StackPanel>
  </Grid>
</Window>

Once the window opens, the second column is wide enough to allow grids GridForImage and GirdForText to be placed next to each other horizontally. If I shrink the width of the second column using the grid splitter, the GridForText grid gets placed underneath the GridForImage at one point, which is quite expected.

Here's what I would like to achieve:

  1. I want GridForText to shrink its width to a certain size and to remain positioned to the right of the GridForImage, as I move the grid splitter to the right side of the window. Then, when the width shrinks to a certain value, say 200px, it should get placed underneath the GridForImage, i.e. WrapPanel should do its magic. Right now, the GridForText doesn't resize at all, it just gets placed underneath when it's current width becomes too large for the width of the WrapPanel.
  2. When the GridForText does get placed underneath the GridForImage, I want GridForImage to fill the entire width of the WrapPanel's width.

Is all this possible and what should I do? Th开发者_运维百科ank you all.


You're essentially trying to use two distinct layout modes so you just need to set up the two distinct states in your layout and then add bindings or triggers to switch between them at the point when you want to switch modes (i.e. width = 200). Using a Grid is the most flexible and gives you a lot more control over the relative sizes but requires more settings and would work best in a ControlTemplate or DataTemplate where you can use Triggers to set a bunch of things at once based on a condition.

Here's a more compact example using UniformGrid with some Bindings and a converter. I removed the fixed sizing on the Image - try Stretch="Fill" if you care more about filling width than aspect ratio. I also changed one StackPanel to a DockPanel to maintain vertical stretching for its children and added a Background to one of the TextBlocks just to show how much Width it's really getting:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Left" />
    <DockPanel Grid.Column="1" Margin="5,0,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
        <TextBlock Text="Now here's a silly poem for you." DockPanel.Dock="Top"/>
        <UniformGrid Rows="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={x:Static local:LayoutModeConverter.Row}, ConverterParameter=200}"
                     Columns="{Binding RelativeSource={RelativeSource Self}, Path=ActualWidth, Converter={x:Static local:LayoutModeConverter.Column}, ConverterParameter=200}">
            <Image Source="Image.jpg" />

            <StackPanel Orientation="Vertical">
                <TextBlock TextWrapping="WrapWithOverflow" Text="Roses are red." Background="Red" />
                <TextBlock TextWrapping="WrapWithOverflow" Text="Violets are blue." />
                <TextBlock TextWrapping="WrapWithOverflow" Text="You belong in a zoo." />
            </StackPanel>
        </UniformGrid>
    </DockPanel>
</Grid>

And the converter:

public class LayoutModeConverter : IValueConverter
{
    public static readonly LayoutModeConverter Row = new LayoutModeConverter { RowMode = true };
    public static readonly LayoutModeConverter Column = new LayoutModeConverter { RowMode = false };

    public bool RowMode { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double width = System.Convert.ToDouble(value);
        double targetWidth = System.Convert.ToDouble(parameter);
        if (RowMode)
            return width > targetWidth ? 1 : 2;
        else
            return width > targetWidth ? 2 : 1;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜