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

168
10 мая 2022, 08:40

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

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

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

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

Но не получается желаемый результат. Я много разных вариантов перепробовал с 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>
Answer 1

Начнем с того, что в 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>

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

Помещаем это в 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>

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

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

<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>

И получим:

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

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

Answer 2

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

<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 для элемента что бы он не мог стать уже, но мог расшириться, что бы влез весь текст.

READ ALSO
Как дублировать положение объекта?

Как дублировать положение объекта?

У меня есть 2 объекта один статичный другой подвижныйНужно чтобы статичный объект повторял положение подвижного

317
Проблемы с HtmlContentBuilder

Проблемы с HtmlContentBuilder

Всем доброго времени суток

363
IEnumerable перенести записи

IEnumerable перенести записи

есть функция которая возвращает записи из базы IEnumerable<Persons>

226
Можно ли создать InlineKeyboardMarkup в групповом чате?

Можно ли создать InlineKeyboardMarkup в групповом чате?

Если бот общается с пользователем в лс, то при сообщении /commands , бот все норм создает такую клавиатуру, а если в групповом, то выдает ошибку...

195