WPF: Setting the Width (and Height) as a Percentage Value

前端 未结 7 588
悲&欢浪女
悲&欢浪女 2020-11-27 10:59

Say I want a TextBlock to have its Width equal to it\'s Parent container\'s Width (ie, stretch from side to side) or a percentage of

相关标签:
7条回答
  • 2020-11-27 11:22

    You can put the textboxes inside a grid to do percentage values on the rows or columns of the grid and let the textboxes auto-fill to their parent cells (as they will by default). Example:

    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="2*" />
            <ColumnDefinition Width="3*" />
        </Grid.ColumnDefinitions>
    
        <TextBox Grid.Column="0" />
        <TextBox Grid.Column="1" />
    </Grid>
    

    This will make #1 2/5 of the width, and #2 3/5.

    0 讨论(0)
  • 2020-11-27 11:28

    I know it's not Xaml but I did the same thing with SizeChanged event of the textbox:

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

    The textbox appears to be 80% size of it's parent (well right side margin is 20%) and stretches when needed.

    0 讨论(0)
  • 2020-11-27 11:32

    I use two methods for relative sizing. I have a class called Relative with three attached properties To, WidthPercent and HeightPercent which is useful if I want an element to be a relative size of an element anywhere in the visual tree and feels less hacky than the converter approach - although use what works for you, that you're happy with.

    The other approach is rather more cunning. Add a ViewBox where you want relative sizes inside, then inside that, add a Grid at width 100. Then if you add a TextBlock with width 10 inside that, it is obviously 10% of 100.

    The ViewBox will scale the Grid according to whatever space it has been given, so if its the only thing on the page, then the Grid will be scaled out full width and effectively, your TextBlock is scaled to 10% of the page.

    If you don't set a height on the Grid then it will shrink to fit its content, so it'll all be relatively sized. You'll have to ensure that the content doesn't get too tall, i.e. starts changing the aspect ratio of the space given to the ViewBox else it will start scaling the height as well. You can probably work around this with a Stretch of UniformToFill.

    0 讨论(0)
  • 2020-11-27 11:37

    Typically, you'd use a built-in layout control appropriate for your scenario (e.g. use a grid as a parent if you want scaling relative to the parent). If you want to do it with an arbitrary parent element, you can create a ValueConverter do it, but it probably won't be quite as clean as you'd like. However, if you absolutely need it, you could do something like this:

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

    Which can be used like this, to get a child textbox 10% of the width of its parent canvas:

    <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>
    
    0 讨论(0)
  • 2020-11-27 11:37

    For anybody who is getting an error like : '2*' string cannot be converted 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>
    
    0 讨论(0)
  • 2020-11-27 11:42

    IValueConverter implementation can be used. Converter class which take inheritance from IValueConverter take some parameters like value (percentage) and parameter (parent's width) and returns desired width value. In XAML file, component's width is set with that desired with value:

    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>
    
    0 讨论(0)
提交回复
热议问题