TransWikia.com

Создание элемента с масштабируемостью WPF

Stack Overflow на русском Asked by Gnom Skull on December 29, 2020

У меня не получается создать пользовательский элемент который будет авто масштабировать в таблице (grid). Результат которого я хочу добиться это вот: Желаемый результат

Т.е чтобы в центре надпись и под ней сама масштабировалась.

Только здесь можно убрать самую верхнюю надпись, и степени окисления которые находятся в правом верхнем углу. Вот мой набросок ( с градиентом и цветом решу в конце, это не сложно).

Текущий результат

Но здесь не получается по центру выравнять буквы ( в данном варианте Br). Также здесь может быть минимально одна буква, а максимально 3 буквы. Но так получается что съезжает влево если одна буква или две, если 3 буквы то по размеру часть их скрывалась, я сделал DockPanel и объединил ячейки в центре как на скрине: 3 буквы

Но не получается желаемый результат. Я много разных вариантов перепробовал с border, grid и другими контейнерами. Кто может подсказать как это решить? Я бы просто налепил картинок с уже задаными значениями, но я хочу парсить из базы данных значения и заполнять этими элементами таблицу. Код ниже:

    <UserControl x:Class="ChemicalBase.Elements.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:ChemicalBase.Elements"
             mc:Ignorable="d" 
             d:DesignHeight="50" d:DesignWidth="50" MinHeight="50" MinWidth="50" MaxWidth="50" MaxHeight="50">
    <Border BorderBrush="White" Background="White">
        <Grid Background="#FF58B26D" Margin="2">
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="9*"/>
                <ColumnDefinition Width="9*"/>
                <ColumnDefinition Width="5*"/>
            </Grid.ColumnDefinitions>
            <DockPanel Grid.Row="1" Grid.ColumnSpan="3" LastChildFill="False">
                <TextBlock HorizontalAlignment="Center" DockPanel.Dock="left" TextWrapping="Wrap" Text="Uuh" Width="25" Foreground="White" FontWeight="Bold" Grid.Column="1" RenderTransformOrigin="0.608,0.471" Grid.Row="1" Margin="16,0,6,0"/>
            </DockPanel>
            <TextBlock TextWrapping="Wrap" Text="111" Grid.Row="2" Grid.Column="0" Foreground="White" FontSize="10"/>
        </Grid>
    </Border>

</UserControl>

2 Answers

Начнем с того, что в WPF есть такой компонент, как Viewbox, он автоматически меняет контент, который находится в нем. Viewbox позволяет настраивать пропорции при помощи свойства Stretch, допустим нам надо сделать квадрат, который внутри будет иметь некий текст, настраиваем все, делаем как надо, получаем, например такое:

<Border Background="Green" Width="100" Height="100">
    <TextBlock Text="Текст"
                VerticalAlignment="Center" TextAlignment="Center"
                Foreground="White" FontSize="16"
                Typography.Capitals="AllSmallCaps"/>
</Border>

Что даст нам предсказуемый результат, где размер будет статичный:

Static Result

Помещаем это в Viewbox и задаем Stretch="Uniform", разметка превращается в такое:

<Viewbox Stretch="Uniform">
    <Border Background="Green" Width="100" Height="100">
        <TextBlock Text="Текст"
            VerticalAlignment="Center" TextAlignment="Center"
            Foreground="White" FontSize="16"
            Typography.Capitals="AllSmallCaps"/>
    </Border>
</Viewbox>

Результатом уже будет квадрат, который меняет размер и сохраняет все пропорнции:

Dynamic result

Имея все это, мы можем сделать уже допустим такое:

<UserControl.Style>
    <Style TargetType="UserControl">
        <Setter Property="Background">
            <Setter.Value>
                <LinearGradientBrush>
                    <GradientStop Color="#4e9e6d"/>
                    <GradientStop Color="#0e2806" Offset="1"/>
                </LinearGradientBrush>
            </Setter.Value>
        </Setter>
        <Setter Property="Foreground" Value="#f9fcfd"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="UserControl">
                    <Viewbox Stretch="Uniform">
                        <Border Background="{TemplateBinding Background}"
                                MinWidth="100" MinHeight="100"
                                Width="100" Height="100"
                                Padding="3">
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Viewbox Grid.Row="1">
                                    <TextBlock  Text="{Binding Text, ElementName=uc, FallbackValue=Text}"
                                            VerticalAlignment="Center" TextAlignment="Center"
                                            Foreground="{TemplateBinding Foreground}"
                                            Typography.Capitals="AllSmallCaps" />
                                </Viewbox>
                                <TextBlock Grid.Row="2" Text="{Binding Numb, ElementName=uc, FallbackValue=00}"
                                            Foreground="{TemplateBinding Foreground}"
                                            FontSize="10"/>
                            </Grid>
                        </Border>
                    </Viewbox>
                </ControlTemplate>
            </Setter.Value>
        </Setter>            
    </Style>
</UserControl.Style>

И получим:

Final Result

Вы спросите: "а зачем тут внутренний текст также обернут в Viewbox?", а чтобы он органично вписывался в этот квадрат, если там будет больше одной буквы. Небольшая демонстрация:

Resize Text

Как видите, если использовать грамотно позиционирование объектов, а именно использовать разные *Alignment свойства (допустим центральный текст у меня имеет VerticalAlignment="Center" TextAlignment="Center", что устанавливает вертикальный размер элемента строго по контенту, а горизонтальный растягивает на максимально допустимый размер предка, ну и TextAlignment делает сам текст по середине блока) и Viewbox, то любой контент без труда можно сделать динамически подстраиваемым.

Correct answer by EvgeniyZ on December 29, 2020

если я правильно понял Вашу проблему, то Вам должна помочь такая разметка:

<WrapPanel Orientation="Horizontal" VerticalAlignment="Top" HorizontalAlignment="Stretch" ItemWidth="90">
                    <Grid Height="auto" Width="auto" Background="#FF58B26D" Margin="5, 5, 0, 5">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="1*"/>
                            <RowDefinition Height="10*"/>
                            <RowDefinition Height="1*"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="1*"/>
                            <ColumnDefinition Width="20*"/>
                            <ColumnDefinition Width="1*"/>
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="1"
                                       Grid.Row="1"
                                       VerticalAlignment="Center"
                                       HorizontalAlignment="Center"
                                       Foreground="White"
                                       FontSize="35"
                                       TextAlignment="Center">A</TextBlock>
                        <TextBlock Grid.Column="0"
                                       Grid.Row="2"
                                       Grid.ColumnSpan="3"
                                       VerticalAlignment="Center"
                                       HorizontalAlignment="Left"
                                       Foreground="White"
                                       FontSize="11"
                                       TextAlignment="Center">11111</TextBlock>
                    </Grid>
</WrapPanel>

Вот так он выглядит: введите сюда описание изображения

Но здесь мы вынуждены контролировать ширину элемента, что бы при изменении текста, сам элемент не расползался и не сужался.

Как Вы можете заметить, я задаю значение для свойства ItemWidth = 90, что бы контролировать ширину родительского объекта, так же вы можете задать MinWidth для элемента что бы он не мог стать уже, но мог расшириться, что бы влез весь текст.

Answered by Aleksandr Kurilov on December 29, 2020

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP