如何在 XAML 中根据窗口或屏幕大小设置网格列最大宽度

发布于 2024-07-05 14:29:11 字数 2259 浏览 10 评论 0原文

我的窗口中有一个 3 列网格,第一列上有一个 GridSplitter。 我想将第一列的 MaxWidth 设置为父窗口或页面 Width(或 ActualWidth)的三分之一,并且如果可能的话,我更愿意在 XAML 中执行此操作。

这是一些在 XamlPad(或类似的)中使用的示例 XAML,它显示了我正在做的事情。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="Column1" Width="200"/>
            <ColumnDefinition x:Name="Column2" MinWidth="50" />
            <ColumnDefinition x:Name="Column3" Width="{ Binding ElementName=Column1, Path=Width }"/>
            </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Background="Green" />
        <GridSplitter Grid.Column="0" Width="5" />
        <Label Grid.Column="1" Background="Yellow" />
        <Label Grid.Column="2" Background="Red" />
    </Grid>
</Page>

如您所见,右列宽度绑定到第一列的宽度,因此当您使用拆分器滑动左列时,右列也会执行相同的操作:) 如果将左列向右滑动,最终它将滑过页面/窗口的一半并滑到窗口的右侧,从而推开第 2 列和第 3 列。

我想通过将第 1 列的 MaxWidth 设置为来防止这种情况窗口宽度的三分之一(或类似的东西)。 我可以很容易地在代码后面执行此操作,但如何在“仅 XAML”中执行此操作?

编辑:David Schmitt 建议使用 SharedSizeGroup 而不是绑定,这是一个很好的建议。 我的示例代码将如下所示:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="Column1" SharedSizeGroup="ColWidth" Width="40"/>
                <ColumnDefinition x:Name="Column2" MinWidth="50" Width="*" />
                <ColumnDefinition x:Name="Column3" SharedSizeGroup="ColWidth"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Background="Green" />
            <GridSplitter Grid.Column="0" Width="5" />
            <Label Grid.Column="1" Background="Yellow" />
            <Label Grid.Column="2" Background="Red" />
        </Grid>
</Page>

I have a 3 column grid in a window with a GridSplitter on the first column. I want to set the MaxWidth of the first column to a third of the parent Window or Page Width (or ActualWidth) and I would prefer to do this in XAML if possible.

This is some sample XAML to play with in XamlPad (or similar) which shows what I'm doing.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition x:Name="Column1" Width="200"/>
            <ColumnDefinition x:Name="Column2" MinWidth="50" />
            <ColumnDefinition x:Name="Column3" Width="{ Binding ElementName=Column1, Path=Width }"/>
            </Grid.ColumnDefinitions>

        <Label Grid.Column="0" Background="Green" />
        <GridSplitter Grid.Column="0" Width="5" />
        <Label Grid.Column="1" Background="Yellow" />
        <Label Grid.Column="2" Background="Red" />
    </Grid>
</Page>

As you can see, the right column width is bound to the width of the first column, so when you slide the left column using the splitter, the right column does the same :)
If you slide the left column to the right, eventually it will slide over half the page/window and over to the right side of the window, pushing away column 2 and 3.

I want to prevent this by setting the MaxWidth of column 1 to a third of the window width (or something like that). I can do this in code behind quite easily, but how to do it in "XAML Only"?

EDIT: David Schmitt suggested to use SharedSizeGroup instead of binding, which is an excellent suggestion. My sample code would look like this then:

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:sys="clr-namespace:System;assembly=mscorlib" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
        <Grid IsSharedSizeScope="True">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="Column1" SharedSizeGroup="ColWidth" Width="40"/>
                <ColumnDefinition x:Name="Column2" MinWidth="50" Width="*" />
                <ColumnDefinition x:Name="Column3" SharedSizeGroup="ColWidth"/>
            </Grid.ColumnDefinitions>
            <Label Grid.Column="0" Background="Green" />
            <GridSplitter Grid.Column="0" Width="5" />
            <Label Grid.Column="1" Background="Yellow" />
            <Label Grid.Column="2" Background="Red" />
        </Grid>
</Page>

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

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

发布评论

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

评论(2

柳若烟 2024-07-12 14:29:11

我认为仅 XAML 方法有些迂回,但这里有一种方法可以实现。

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

    <!-- This contains our real grid, and a reference grid for binding the layout-->
    <Grid x:Name="Container">

      <!-- hidden because it's behind the grid below -->
      <Grid x:Name="LayoutReference">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <!-- We need the border, because the column doesn't have an ActualWidth -->
        <Border x:Name="ReferenceBorder" 
                Background="Black" />
        <Border Background="White" Grid.Column="1" />
        <Border Background="Black" Grid.Column="2" />
      </Grid>

      <!-- I made this transparent, so we can see the reference -->
      <Grid Opacity="0.9">
          <Grid.ColumnDefinitions>
              <ColumnDefinition x:Name="Column1" 
                                MaxWidth="{Binding ElementName=ReferenceBorder,Path=ActualWidth}"/>
              <ColumnDefinition x:Name="Column2" 
                                MinWidth="50"  />
              <ColumnDefinition x:Name="Column3" 
                                Width="{ Binding ElementName=Column1, Path=Width }"/>
              </Grid.ColumnDefinitions>

          <Label Grid.Column="0" Background="Green"/>
          <GridSplitter Grid.Column="0" Width="5" />
          <Label Grid.Column="1" Background="Yellow" />
          <Label Grid.Column="2" Background="Red" />
      </Grid>
    </Grid>

</Page>

I think the XAML-only approach is somewhat circuitous, but here is a way to do it.

<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:sys="clr-namespace:System;assembly=mscorlib"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >

    <!-- This contains our real grid, and a reference grid for binding the layout-->
    <Grid x:Name="Container">

      <!-- hidden because it's behind the grid below -->
      <Grid x:Name="LayoutReference">
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
          <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <!-- We need the border, because the column doesn't have an ActualWidth -->
        <Border x:Name="ReferenceBorder" 
                Background="Black" />
        <Border Background="White" Grid.Column="1" />
        <Border Background="Black" Grid.Column="2" />
      </Grid>

      <!-- I made this transparent, so we can see the reference -->
      <Grid Opacity="0.9">
          <Grid.ColumnDefinitions>
              <ColumnDefinition x:Name="Column1" 
                                MaxWidth="{Binding ElementName=ReferenceBorder,Path=ActualWidth}"/>
              <ColumnDefinition x:Name="Column2" 
                                MinWidth="50"  />
              <ColumnDefinition x:Name="Column3" 
                                Width="{ Binding ElementName=Column1, Path=Width }"/>
              </Grid.ColumnDefinitions>

          <Label Grid.Column="0" Background="Green"/>
          <GridSplitter Grid.Column="0" Width="5" />
          <Label Grid.Column="1" Background="Yellow" />
          <Label Grid.Column="2" Background="Red" />
      </Grid>
    </Grid>

</Page>
寄离 2024-07-12 14:29:11

太懒了,我自己实际上无法编写它,但是您应该能够使用数学转换器并绑定到父窗口宽度(通过名称或使用RelativeSource祖先搜索)。

//I know I borrowed this from someone, sorry I forgot to add a comment from whom
public class ScaledValueConverter : IValueConverter
{
  public Object Convert(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     Double scalingFactor = 0;
     if (parameter != null)
     {
        Double.TryParse((String)(parameter), out scalingFactor);
     }

     if (scalingFactor == 0.0d)
     {
        return Double.NaN;
     }

     return (Double)value * scalingFactor;
  }

  public Object ConvertBack(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     throw new Exception("The method or operation is not implemented.");
  }
}

Too lazy to actually write it up myself, but you should be able to use a mathematical converter and bind to your parent windows width (either by name, or with a RelativeSource ancestor search).

//I know I borrowed this from someone, sorry I forgot to add a comment from whom
public class ScaledValueConverter : IValueConverter
{
  public Object Convert(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     Double scalingFactor = 0;
     if (parameter != null)
     {
        Double.TryParse((String)(parameter), out scalingFactor);
     }

     if (scalingFactor == 0.0d)
     {
        return Double.NaN;
     }

     return (Double)value * scalingFactor;
  }

  public Object ConvertBack(Object value, Type targetType, Object parameter, System.Globalization.CultureInfo culture)
  {
     throw new Exception("The method or operation is not implemented.");
  }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文