Ваш bru sh имеет четыре фрагмента, потому что вы установили область просмотра точно на 1/4 относительного размера выходной ограничительной рамки. Пока область просмотра имеет фиксированную связь с ограничительной рамкой, вы не можете получить ничего другого , кроме четырех.
Итак, способ исправить это - удалить эту связь и замените его чем-нибудь более подходящим. Простейший способ сделать это - установить режим просмотра в Absolute
вместо RelativeToBoundingBox
. Но тогда возникает вопрос, какое абсолютное значение использовать? В коде, который вы разместили, если вы установите абсолютный размер на любое заданное фиксированное значение c, вы получите тот же размер везде, где вы используете bru sh, и он не будет соответствовать желаемому TextBlock
.
Вам нужен другой размер в зависимости от TextBlock
. Это означает, что разные bru sh для каждого TextBlock
. Но вам, вероятно, не нужно объявлять новый bru sh для каждого TextBlock
, который вы объявляете, жестко программируя размер, который подходит. В этом отношении, может быть, вы даже не хотите объявлять новый TextBlock
. WPF работает намного лучше, когда вы используете шаблоны для организации визуального дерева. Использование шаблона позволяет вам жестко кодировать аспекты, которые вы хотите повторить везде, при этом позволяя контексту визуального элемента управлять определенными c аспектами, которые должны варьироваться. Итак, давайте сделаем это!
Сначала вам понадобится модель представления:
class TextAndSizeModel
{
public string Text { get; set; }
public double Size { get; set; }
}
Это вырожденная модель, содержащая только два фрагмента данных, которые различаются в вашем примере, без уведомления об изменении свойства. Мы не собираемся менять значения в этом простом примере, так что это нормально.
Теперь, одна из менее очевидных вещей, которые вам понадобятся, - это конвертер. Это связано с тем, что в каждом случае нам нужен разный размер области просмотра, а размер области просмотра равен Rect
, что является простым значением, а не объектом зависимости. Поэтому нам нужен конвертер, чтобы сделать соответствующее Rect
значение по мере необходимости:
class SquareRectConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double doubleValue = System.Convert.ToDouble(value);
return new Rect(0, 0, doubleValue, doubleValue);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
И теперь мы готовы сделать разметку. Это выглядит так:
<Window x:Class="TestSO61021208TileBrush.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:TestSO61021208TileBrush"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<GeometryDrawing x:Key="geometryDrawing1">
<GeometryDrawing.Geometry>
<GeometryGroup>
<EllipseGeometry Center="50,50"
RadiusX="20"
RadiusY="45"/>
<EllipseGeometry Center="50,50"
RadiusX="45"
RadiusY="20"/>
</GeometryGroup>
</GeometryDrawing.Geometry>
<GeometryDrawing.Brush>
<SolidColorBrush Color="Gray" />
</GeometryDrawing.Brush>
<GeometryDrawing.Pen>
<Pen Thickness="2"
Brush="Black"/>
</GeometryDrawing.Pen>
</GeometryDrawing>
<local:SquareRectConverter x:Key="squareRectConverter1"/>
<DataTemplate DataType="{x:Type local:TextAndSizeModel}">
<TextBlock Text="{Binding Text}"
FontSize="{Binding Size}"
FontFamily="Consolas">
<TextBlock.Background>
<DrawingBrush
TileMode="Tile"
Stretch="Uniform"
Viewbox="0,0,1,1"
ViewboxUnits="RelativeToBoundingBox"
Viewport="{Binding ActualHeight, RelativeSource={RelativeSource AncestorType=TextBlock}, Converter={StaticResource squareRectConverter1}}"
ViewportUnits="Absolute"
Drawing="{StaticResource geometryDrawing1}"/>
</TextBlock.Background>
</TextBlock>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<GridSplitter Grid.Row="0"
Grid.Column="1"
Grid.RowSpan="2"
Width="3"
VerticalAlignment="Stretch"
HorizontalAlignment="Center"
Background="Black"/>
<ContentControl Grid.Row="0" Grid.Column="0">
<ContentControl.Content>
<local:TextAndSizeModel Text="Left text here." Size="12"/>
</ContentControl.Content>
</ContentControl>
<ContentControl Grid.Row="1" Grid.Column="2">
<ContentControl.Content>
<local:TextAndSizeModel Text="Right text here." Size="30"/>
</ContentControl.Content>
</ContentControl>
</Grid>
</Window>
ContentControl
используется, конечно, для сопоставления объекта модели представления с шаблоном. В шаблоне вы увидите три привязки:
- Текстовое значение.
- Значение размера шрифта.
ActualHeight
содержащего TextBlock
элемент к значению размера Viewport
, через преобразователь
Это устанавливает высоту области просмотра точно на высоту TextBlock
. Но это также позволяет окну просмотра быть квадратом, который не относится к ограничивающей рамке, так что он может правильно располагаться по всему фону.
Результат выглядит следующим образом:
Теперь bru sh располагается горизонтально, чтобы соответствовать фону, независимо от фактической ширины TextBlock
.
Конечно, в этом конкретном примере bru sh изменяется высота в соответствии с размером TextBlock
. Я сделал вывод, что это то, что вы хотели, потому что именно так оно и работает в вашем первоначальном примере, и вы не написали ничего, чтобы предположить, что вы хотели этого иначе. Тем не менее, вы должны быть в состоянии изменить технику basi c выше, чтобы получить то, что вы хотите. Вам нужно будет сделать математику по-другому, так что вместо того, чтобы высота и ширина менялись в точности с высотой содержащего элемента, вы выбираете фиксированную ширину для bru sh, используя переданную высоту только для высота области просмотра. Таким образом, bru sh будет отцентрирован по вертикали в элементе с фиксированным размером для элемента graphi c, но все еще будет располагаться горизонтально.
Это будет выглядеть примерно так:
Преобразователь:
class CenteredRectConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
double height = System.Convert.ToDouble(value);
double width = System.Convert.ToDouble(parameter);
return new Rect(0, 0, width, height);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
Шаблон данных:
<DataTemplate DataType="{x:Type local:TextAndSizeModel}">
<TextBlock Text="{Binding Text}"
FontSize="{Binding Size}"
FontFamily="Consolas">
<TextBlock.Background>
<DrawingBrush
TileMode="Tile"
Stretch="Uniform"
Viewbox="0,0,1,1"
ViewboxUnits="RelativeToBoundingBox"
Viewport="{Binding ActualHeight,
RelativeSource={RelativeSource AncestorType=TextBlock},
Converter={StaticResource centeredRectConverter1},
ConverterParameter=14}"
ViewportUnits="Absolute"
Drawing="{StaticResource geometryDrawing1}"/>
</TextBlock.Background>
</TextBlock>
</DataTemplate>
Это выглядит следующим образом: