c# - 有没有办法设置一个 TileBrush 让它总是 1 瓦高,但不同数量的瓦宽?
问题描述
我正在尝试制作一个TileBrush
,当使用时,它始终是一个瓷砖高和可变数量的瓷砖宽(取决于它所应用的元素有多少空间)。
为了帮助说明我的问题,我编写了一些代码。在所述代码中, a 中有两个TextBlock
s Grid
。两者TextBlock
的背景相同,但字体大小不同。目前,每个TextBlock
的背景总是 1 格高和 4 格宽。
我需要进行哪些更改才能使每个TextBlock
的背景始终始终为 1 块高,但块的宽度可变(取决于 的字体大小TextBlock
及其包含Grid
列的宽度)?
<Window x:Class="WpfTestApp01.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:WpfTestApp01"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.Resources>
<DrawingBrush x:Key="TestBrush"
TileMode="Tile"
Stretch="Uniform"
Viewbox="0,0,1,1"
ViewboxUnits="RelativeToBoundingBox"
Viewport="0,0,0.25,1"
ViewportUnits="RelativeToBoundingBox">
<DrawingBrush.Drawing>
<GeometryDrawing>
<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>
</DrawingBrush.Drawing>
</DrawingBrush>
</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"/>
<TextBlock Text="Left text here."
FontSize="12"
FontFamily="Consolas"
Grid.Row="0"
Grid.Column="0"
Background="{StaticResource TestBrush}"/>
<TextBlock Text="Right text here."
FontSize="30"
FontFamily="Consolas"
Grid.Row="1"
Grid.Column="2"
Background="{StaticResource TestBrush}"/>
</Grid>
</Window>
这是上面的代码产生的:
解决方案
因为您已将视口精确设置为输出边界框相对大小的 1/4,所以您的画笔平铺了四个。只要视口与边界框有这种固定的关系,除了四个之外,你不能得到任何东西。
所以,解决这个问题的方法是删除这种关系并用更合适的东西代替它。最简单的方法当然是将视口模式设置为Absolute
而不是RelativeToBoundingBox
. 但问题是,使用什么绝对值?在您发布的代码中,如果您将绝对大小设置为任何特定的固定值,您将在使用画笔的任何地方获得相同的大小,并且它不适合TextBlock
您想要的。
您需要的是不同的尺寸,具体取决于TextBlock
. 这意味着每个不同的刷子TextBlock
。但是,您可能不想为TextBlock
您声明的每个声明一个新画笔,硬编码大小以适应。就此而言,也许您甚至不想声明一个新的TextBlock
. 当您使用模板来排列可视化树时,WPF 工作得更好。使用模板可以硬编码要在任何地方重复的方面,同时仍然允许视觉元素的上下文控制需要改变的特定方面。所以,让我们这样做吧!
首先,您需要一个视图模型:
class TextAndSizeModel
{
public string Text { get; set; }
public double Size { get; set; }
}
这是一个退化模型,仅包含您的示例中不同的两条数据,没有属性更改通知。我们不会更改这个简单示例中的值,所以这很好。
现在,您需要的不太明显的东西之一是转换器。这是因为我们希望在每种情况下都有不同的视口大小,而视口大小是 a 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
. 但它也允许视口是一个与边界框无关的正方形,这样它就可以在整个背景上正确平铺。
现在水平刷平铺以适应背景,无论TextBlock
.
当然,在这个特定示例中,画笔会根据TextBlock
. 我推断这就是您想要的,因为这就是它在您的原始示例中的工作方式,并且您没有写任何东西来暗示您想要它。但是,您应该能够修改上面的基本技术以获得您想要的。您需要以不同的方式进行数学运算,以便您决定画笔的固定宽度,而不是使高度和宽度与包含元素的高度完全不同,使用传入的高度仅用于高度视口。这样,画笔将在元素中垂直居中,图形元素具有固定大小,同时仍水平平铺。
看起来像这样:
转换器:
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>
推荐阅读
- reactjs - 尝试运行构建时出错
- c# - ASP.Net Core Razor Pages 动态列表
- java - 无法与 Instagram 登录字段交互
- php - 如何根据 PHP 表格列中的某些条件更改文本颜色
- java - FopFactory 类型中的方法 newInstance(FopFactoryConfig) 不适用于参数 ()
- reactjs - 使用参数反应路由器链接
- pandas - 如何找到具有起点和终点的所有城市之间的最短路径
- c++ - 使用 microsoft 的 krabsetw 实用程序解析 ETW 中的结构化类型
- html - 将导航放在横幅 CSS 上方
- python-3.x - Selenium 找不到 geckodriver