在 WPF 中包裹面板

发布于 2024-10-20 15:39:42 字数 2233 浏览 2 评论 0原文

我的窗口中有以下布局:

  1. Grid 有两列
  2. GridSplitter ,它调整网格列的大小
  3. 第二个网格列填充有 StackPanel
  4. StackPanel 是垂直方向的,有 2 个子元素:TextBlock 和一个 WrapPanel
  5. WrapPanel 有两个 Grid 作为Children
  6. 第一个 Grid 子项包含一个 Image
  7. 第二个 Grid 包含一个 StackPanel,其中包含 3 个垂直方向的 TextBlock

XAML 代码如下所示:

<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>

窗口打开后,第二列的宽度足以允许网格 GridForImageGirdForText 水平并排放置。如果我使用网格分割器缩小第二列的宽度,GridForText 网格会在某一时刻放置在 GridForImage 下方,这是完全符合预期的。

这是我想要实现的目标:

  1. 当我移动网格分割器时,我希望 GridForText 将其宽度缩小到一定大小,并保持位于 GridForImage 的右侧到窗口的右侧。然后,当宽度缩小到某个值(例如 200px)时,它应该放置在 GridForImage 下方,即 WrapPanel 应该发挥其魔力。现在,GridForText 根本不调整大小,只是当其当前宽度对于 WrapPanel 的宽度来说太大时,它才会被放置在下面。
  2. GridForText 确实放置在 GridForImage 下方时,我希望 GridForImage 填充 WrapPanel 的整个宽度' s 宽度。

这一切可能吗?我该怎么办?谢谢大家。

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? Thank you all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

成熟稳重的好男人 2024-10-27 15:39:42

您本质上是在尝试使用两种不同的布局模式,因此您只需要在布局中设置两种不同的状态,然后添加绑定或触发器以在您想要切换模式时在它们之间切换(即宽度= 200) 。使用网格是最灵活的,可以让您更好地控制相对大小,但需要更多设置,并且在 ControlTemplate 或 DataTemplate 中效果最好,您可以在其中使用触发器根据条件一次设置一堆内容。

这是一个更紧凑的示例,使用 UniformGrid 以及一些绑定和转换器。我删除了图像上的固定大小 - 如果您更关心填充宽度而不是纵横比,请尝试 Stretch="Fill"。我还将一个 StackPanel 更改为 DockPanel,以保持其子级的垂直拉伸,并向其中一个 TextBlock 添加背景,只是为了显示它实际获得的宽度:

<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>

以及转换器:

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();
    }
}

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();
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文