2

У меня не получается создать пользовательский элемент который будет авто масштабировать в таблице (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>

  • 1
  • О каком масштабировании идет речь? Вот у вас квадрат, по центру буква, в нижнем углу цифра, да и сверху цифра, что в итоге вы хотите? Чтоб когда этот квадрат был растянут, то и контент в нем подстраивался под его размер, или вы хотите, чтоб, например буква по центру изменяла свой размер так, чтоб текст всегда помещался в этот квадрат (H - большая HH - чуть меньше HHH - еще меньше и так далее)? – EvgeniyZ Nov 13 '20 at 13:08
  • @EvgeniyZ вроде, того – Gnom Skull Nov 14 '20 at 14:31
  • Вроде того что? Я два вида масштабирования расписал и спросил что именно вы хотите... – EvgeniyZ Nov 14 '20 at 14:38
  • @EvgeniyZ первый вариант. Чтобы если квадрат был растянут, то и контент подстраивался под его размер, но при этом текст не съезжал сильно влево или вправо – Gnom Skull Nov 14 '20 at 14:42

2 Answers2

3

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

EvgeniyZ
  • 15,694
1

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

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

aepot
  • 49,560