WPF:将宽度(和高度)设置为百分比值

Posted

技术标签:

【中文标题】WPF:将宽度(和高度)设置为百分比值【英文标题】:WPF: Setting the Width (and Height) as a Percentage Value 【发布时间】:2010-10-17 13:37:13 【问题描述】:

假设我想要一个TextBlock 使其Width 等于它的父容器的Width(即,从一侧延伸到另一侧)或它的父容器Width 的百分比,我怎样才能做到这一点XAML 没有指定绝对值?

我想这样做,以便如果父容器容器稍后扩展(其'Width 增加),其'子元素也将自动扩展。 (基本上,就像在 html 和 CSS 中一样)

【问题讨论】:

看看this answer。 使用 cwap 的答案并将 tb 包含在网格中,使其对齐以拉伸。 【参考方案1】:

您可以将文本框放在网格内,以在网格的行或列上执行百分比值,并让文本框自动填充到其父单元格(默认情况下)。示例:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" />
        <ColumnDefinition Width="3*" />
    </Grid.ColumnDefinitions>

    <TextBox Grid.Column="0" />
    <TextBox Grid.Column="1" />
</Grid>

这将使 #1 的宽度为 2/5,而 #2 为 3/5。

【讨论】:

我已经尝试过了,但是我收到了这个错误:'2*' 字符串不能转换为长度。' 其实*(星号)是小星星;)etymonline.com/index.php?term=asterisk 我妈说我是明星 这不起作用,即使 TextBox 在网格中。宽度可以设置为 Double、Qualified Double(双精度值后跟 px、in、cm 或 pt)或 Auto。见msdn.microsoft.com/en-GB/library/… 是的.. 这实际上是一个非常糟糕的回复,但基于所有的赞成票,我想它帮助了某人(很久以前),这就是我没有删除它的原因。 【参考方案2】:

拉伸到和父容器一样大小的方法是使用属性:

 <Textbox HorizontalAlignment="Stretch" ...

这将使 Textbox 元素水平拉伸并水平填充所有父空间(实际上它取决于您使用的父面板,但应该适用于大多数情况)。

百分比只能与网格单元格值一起使用,因此另一种选择是创建一个网格并将您的文本框放在具有适当百分比的单元格中。

【讨论】:

【参考方案3】:

通常,您会使用适合您的场景的内置布局控件(例如,如果您想要相对于父级缩放,则使用网格作为父级)。如果您想使用任意父元素执行此操作,您可以创建一个 ValueConverter 执行此操作,但它可能不会像您希望的那样干净。但是,如果你绝对需要它,你可以这样做:

public class PercentageConverter : IValueConverter

    public object Convert(object value, 
        Type targetType, 
        object parameter, 
        System.Globalization.CultureInfo culture)
    
        return System.Convert.ToDouble(value) * 
               System.Convert.ToDouble(parameter);
    

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

可以像这样使用,以获取其父画布宽度的 10% 的子文本框:

<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:WpfApplication1"
    Title="Window1" Height="300" Width="300">
    <Window.Resources>
        <local:PercentageConverter x:Key="PercentageConverter"/>
    </Window.Resources>
    <Canvas x:Name="canvas">
        <TextBlock Text="Hello"
                   Background="Red" 
                   Width="Binding 
                       Converter=StaticResource PercentageConverter, 
                       ElementName=canvas, 
                       Path=ActualWidth, 
                       ConverterParameter=0.1"/>
    </Canvas>
</Window>

【讨论】:

这真的很酷,我如何在代码中做到这一点(设置文本框的宽度)? 您应该考虑将CultureInfo.InvariantCulture 添加到双重转换中,因为parameter 被视为string,并且在具有不同decimal separator 的文化中它不会按预期工作。【参考方案4】:

对于遇到以下错误的任何人:'2*' string cannot be convert to Length.

<Grid >
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2*" /><!--This will make any control in this column of grid take 2/5 of total width-->
        <ColumnDefinition Width="3*" /><!--This will make any control in this column of grid take 3/5 of total width-->
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition MinHeight="30" />
    </Grid.RowDefinitions>

    <TextBlock Grid.Column="0" Grid.Row="0">Your text block a:</TextBlock>
    <TextBlock Grid.Column="1" Grid.Row="0">Your text block b:</TextBlock>
</Grid>

【讨论】:

为什么不&lt;RowDefinition Height="auto" /&gt; "auto" 只占用控件所需的空间 非常感谢,这应该是最佳答案。 这绝对是最好的答案。【参考方案5】:

可以使用 IValueConverter 实现。从 IValueConverter 继承的转换器类接受一些参数,如value(百分比)和parameter(父宽度)并返回所需的宽度值。在 XAML 文件中,组件的宽度设置为所需的值:

public class SizePercentageConverter : IValueConverter

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        if (parameter == null)
            return 0.7 * value.ToDouble();

        string[] split = parameter.ToString().Split('.');
        double parameterDouble = split[0].ToDouble() + split[1].ToDouble() / (Math.Pow(10, split[1].Length));
        return value.ToDouble() * parameterDouble;
    

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    
        // Don't need to implement this
        return null;
    

XAML:

<UserControl.Resources>
    <m:SizePercentageConverter x:Key="PercentageConverter" />
</UserControl.Resources>

<ScrollViewer VerticalScrollBarVisibility="Auto"
          HorizontalScrollBarVisibility="Disabled"
          Width="Binding Converter=StaticResource PercentageConverter, RelativeSource=RelativeSource Mode=FindAncestor,AncestorType=x:Type Border,Path=ActualWidth"
          Height="Binding Converter=StaticResource PercentageConverter, ConverterParameter=0.6, RelativeSource=RelativeSource Mode=FindAncestor,AncestorType=x:Type Border,Path=ActualHeight">
....
</ScrollViewer>

【讨论】:

【参考方案6】:

我使用两种方法来确定相对大小。我有一个名为 Relative 的类,带有三个附加属性 ToWidthPercentHeightPercent转换器方法 - 虽然使用适合您的方法,但您会满意。

另一种方法更狡猾。在你想要相对大小的地方添加一个ViewBox,然后在其中添加一个宽度为100的Grid。然后如果你在其中添加一个宽度为10的TextBlock,它显然是100的10%。

ViewBox 将根据给定的空间缩放Grid,所以如果它是页面上唯一的东西,那么Grid 将有效地全宽缩放,您的TextBlock缩放到页面的 10%。

如果您没有在Grid 上设置高度,那么它将缩小以适应其内容,因此它的大小都会相对大小。您必须确保内容不会太高,即开始更改分配给ViewBox 的空间的纵横比,否则它也会开始缩放高度。您可以使用StretchUniformToFill 来解决此问题。

【讨论】:

【参考方案7】:

我知道这不是 XAML,但我对文本框的 SizeChanged 事件做了同样的事情:

private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)

   TextBlock textBlock = sender as TextBlock;
   FrameworkElement element = textBlock.Parent as FrameworkElement;
   textBlock.Margin = new Thickness(0, 0, (element.ActualWidth / 100) * 20, 0);

文本框的大小似乎是其父级的 80%(右侧边距为 20%),并在需要时拉伸。

【讨论】:

以上是关于WPF:将宽度(和高度)设置为百分比值的主要内容,如果未能解决你的问题,请参考以下文章

将元素高度/宽度设置为百分比和像素值的组合[重复]

WPF 中基于百分比的动态宽度

如果一个div在宽度为百分比的情况下,如何将这个div的高度的值设置成和宽度一样

Xamarin Forms StackLayout:如何将子项的宽度/高度设置为百分比

使用百分比值填充 flexbox 项

CSS 根据 jQuery 的宽度百分比设置高度