如何使用WPF Grid面板调整大小?

3
我有一个包含两列(TextBlock和TextBox)的网格窗口,我需要将第0列设置为根据其内容自动调整大小,并使第1列(内容)的大小是第0列的4倍。如果这是解决方案,我将创建Grid后代类。 列0的内容在运行时不会更改,因此列0或列1的大小不得在运行时更改。这个网格将是以SizeToContent =“WidthAndHeight”配置的窗口的子级,因此不必存在额外的空间。
答复Dmitry:我尝试了你所说的以下代码,但完全不起作用:
<Window x:Class="UnderstandSizing.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" 
SizeToContent="WidthAndHeight" >
<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width=".25*" />
        <ColumnDefinition Width=".75*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Grid.Column="0" Text="THIS IS THE LABEL:" />
    <TextBox Grid.Column="1" Text="content" />
</Grid>
</Window>

最后编辑:我(或任何人)为什么需要这个?

WPF的一个好处是它可以在没有固定大小的情况下工作,对吧?如果您视力受损并且字体大小更大,一切都会很好。如果您将UI翻译成需要x2大小的另一种语言,一切都会很好。如果您有不同的PPI设置,一切都会很好。

但是我不想看到屏幕在运行时改变其大小,因为用户不习惯这样做。这就是为什么我想将输入字段的大小设置为已知字段的倍数。如果我让标签单元格重新调整其所需大小,然后将内容单元格设置为标签的倍数,我将获得自适应大小的好处,并具有用户期望的固定大小屏幕的行为(除非他们通过调整大小来更改它)。


你想让网格的外部尺寸在列1内容大小增加时扩展吗?还是你有一个给定的空间,网格必须保持在其中?或者列1的宽度在编译时是恒定且已知的? - Martin Hennings
一个问题:如果你想让第一列的大小是第零列的四倍,那么剩余的空间会发生什么?或者说,如果第零列的宽度加上第一列的四倍超过了可用空间,你想要什么? - dowhilefor
你尝试使用百分比了吗?- http://www.tanguay.info/web/index.php?pg=codeExamples&id=36 - user572559
@Dmitry 0.2* еТМ 0.8* зЫЄељУдЇО * еТМ 4*пЉМиАМеРОиАЕжЫіжО•ињС SoMoS еѓїжЙЊзЪДеЖЕеЃєгАВ - Martin Hennings
@所有人:添加了更多的解释来帮助你们理解这个问题。感谢大家。 - Ignacio Soler Garcia
@SoMoS请查看我的更新答案。它是有效的,你必须考虑子控件的行为。 - user572559
4个回答

8
您可以在表格列上使用绑定:
<Grid.ColumnDefinitions>
   <ColmunDefinition Width="Auto" x:Name="firstCol"/>
   <ColumnDefinition Width="{Binding ActualWidth, ElementName=firstCol, Converter={StaticResource MultiplyConverter}, ConverterParameter=4}" />
</Grid.ColumnDefinitions>

然后是转换器:
public class MultiplyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double originalValue;
        double multiplier;
        if (value != null && parameter != null && 
            double.TryParse(value.ToString(), out originalValue) &&
            double.TryParse(parameter.ToString(), out multiplier)) //Can be lots of things: sentinel object, NaN (not a number)...
        {
            return originalValue * multiplier;
        }
        else return Binding.DoNothing;
    }

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

你也可以为网格列编写附加属性。


看起来很可行。你能解释一下附加属性是什么吗?我不明白你的意思。 - Ignacio Soler Garcia
你可以简单地检查 if(value is double),这样它就不可能为空并且不需要解析。此外,请查看 Binding.DoNothing。使用ConverterParameter增加了灵活性,给你一个赞... - Martin Hennings
@Martin 对 Binding.DoNothing 的看法很好。但是我对 value is double 的事情并不确定,因为它们实际上是字符串。 - Louis Kottmann
@Baboon:也许是针对ColumnDefinitions。对象的宽度是一个双精度浮点数。我进行了调试并查看了value.GetType().ToString()。结果是:System.Double - Martin Hennings
不行,ActualWidth在运行时返回0(即使在Visualstudio编辑器中工作...奇怪)。有什么提示吗? - Ignacio Soler Garcia
显示剩余2条评论

0

摘自:http://www.tanguay.info/web/index.php?pg=codeExamples&id=36

这个想法是使用:

更新2-完整的XAML发布(注意您的网格子元素的行为):

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width=".25*" />
                <ColumnDefinition Width=".75*" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
            </Grid.RowDefinitions>
            <Grid Background="Yellow" Grid.Column="0">
                <TextBlock  Text="THIS IS THE LABEL:" />
            </Grid>
            <Grid Background="Blue" Grid.Column="1">
                <TextBox Background="Transparent" Text="content" />
            </Grid>

        </Grid>

    </Grid>
</Window>

我刚刚检查了它并且它运行正常。

更新:简而言之 - 在WPF中没有现成的方法来做到这一点。根据您的情况,您必须想出某种技巧来使您的网格工作。

另一个问题是 - 一般情况下,WPF布局是设计为保护性的,即如果您的网格子项无法缩小 - 通常您的布局逻辑应该适应它,通常是通过暂停某些布局规则来实现。


很抱歉,这完全没有回答问题。当列0的内容大小改变时,您如何更改网格的宽度? - Martin Hennings
问题是:试过吗?您的网格将始终扩展到整个宽度,第0列通常不会具有其内容的精确宽度。 - Martin Hennings
不是这样的,马丁。在网格中放置两个按钮并尝试一下。 - user572559
这是因为按钮自动调整到网格的大小。将第一个按钮的宽度设置为“20”,看看第二列的宽度是否会自动变为“60”。 - Martin Hennings

0

编辑:

如果在编译时已知大小,手动设置宽度不是更容易吗?


你可以使用BindingConverter来实现,我建议在水平StackPanel中使用单独的项(确保StackPanel的宽度足够容纳内容):
这是清理后的代码。

MainWindow.xaml:

<!-- define xmlns:local="clr-namespace:YourAppNamespace" -->
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
    <StackPanel.Resources>
        <local:WidthConverter x:Key="wc" />
    </StackPanel.Resources>
    <Grid Background="Gray" x:Name="col1">
        <TextBlock Text="blub"/>
    </Grid>
    <Grid Background="Orange" Width="{Binding ElementName=col1, Path=ActualWidth, Converter={StaticResource ResourceKey=wc}}">
        <Label Content="bla"></Label>
    </Grid>
</StackPanel>

MainWindow.xaml.cs:

public class WidthConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (!(value is double))
        {
            return Binding.DoNothing;
        }
        return ((double)value) * 4.0;
    }

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

这对整个列不起作用,只适用于标签和文本块之间。 - Louis Kottmann
我不知道有比你发布的那种方式更好的创建卡顿、无响应的用户界面方法。你在项目中使用它吗? - user572559
@Baboon:好的,已经更改了,现在网格彼此依赖。 - Martin Hennings
@Dmitry:StackPanel 确保这两个网格向左对齐,并且仅占用它们所需的空间。 - Martin Hennings
大小在编译时不可知,只有在执行的最开始才能确定。请阅读我的最后一次编辑。谢谢。 - Ignacio Soler Garcia

0

我理解您正在尝试为标签(文本块)和相应的输入字段进行布局。作为指示,您应该首先查看{{link1:Beth Massi's Windows Client video}},其中演示了一个简单的数据输入表单,但布局也展示得非常好。

特别注意她如何使用设计师、属性窗口和XAML在WPF窗口上布置控件,然后我认为您不需要将第一列设置为Auto大小,第二列设置为4*第一列。

编辑:根据问题的更新,我在下面发布了可能的解决方案:

  1. XAML文件代码(注意Window中的SizeToContent用法以及Textbox控件的ActualWidth属性绑定):

    <Window x:Class="GridTest.MainWindow"
        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:local="clr-namespace:GridTest"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        d:DesignHeight="350"
        d:DesignWidth="525"
        SizeToContent="WidthAndHeight"
        mc:Ignorable="d">
    <Grid>
        <Grid.Resources>
            <local:FourWidthConverter x:Key="FourWidthConv" />
        </Grid.Resources>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <TextBlock Name="tb"
                   Grid.Column="0"
                   Text="自动文本,设计时更改以查看宽度变化" />
        <TextBox Name="tx"
                 Grid.Column="1"
                 Width="{Binding ElementName=tb,
                                 Path=ActualWidth,
                                 Converter={StaticResource FourWidthConv}}"
                 Text="4 * col 1 width displaying Text in SizetoContentWindow" />
    </Grid>
    </Window>
    
  2. .Xaml.cs文件代码(注意这里的转换器):

    using System.Windows;
    using System.Windows.Data;
    
    namespace GridTest
    {
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
        }
    
        public class FourWidthConverter : IValueConverter
        {
            public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                return 4 * (double)value;
            }
    
            public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new System.NotImplementedException();
            }
        }
    }
    

阅读我的编辑以了解为什么我或任何人都需要这个功能。 - Ignacio Soler Garcia
@SoMoS 我已经编辑了我的答案并发布了可能的解决方案,请查看编辑后的内容。 - S2S2
@SoMoS 可能需要将此代码实现在用户控件内,而不是窗口中,以便重用这种功能。 - S2S2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接