如何获取Viewbox中TextBlock的渲染字体大小并同步至外部TextBlock
问题与解决方案
问题
有两个TextBlock控件:tb1和被Viewbox包裹的tb2。当tb2的布局尺寸变化时,受Viewbox的缩放影响,tb2实际渲染的字体大小会改变,但它的FontSize属性值始终保持不变。需要让tb1的字体大小跟随tb2的实际渲染大小同步变化。
环境:WPF (.NET 6.0)
用户原始代码:
XAML代码
<Window x:Class="LiveCharts2Test.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:LiveCharts2Test" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="50*"/> <RowDefinition Height="47*"/> <RowDefinition Height="338*"/> </Grid.RowDefinitions> <TextBlock x:Name="tb1" Grid.Row="0" Grid.Column="0" Text="apple" /> <Viewbox Stretch="Uniform" Grid.Row="1" Grid.Column="0"> <TextBlock x:Name="tb2" Text="testtesttesttesttesttesttesttesttesttest" LayoutUpdated="tb2_LayoutUpdated" /> </Viewbox> </Grid> </Window>
C#代码
using System.Windows; namespace LiveCharts2Test { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void Window_Loaded(object sender, RoutedEventArgs e) { System.Diagnostics.Debug.WriteLine(tb1.FontSize); System.Diagnostics.Debug.WriteLine(tb2.FontSize); } private void tb2_LayoutUpdated(object sender, EventArgs e) { System.Diagnostics.Debug.WriteLine(tb2.FontSize); } } }
解决方案
方法一:通过LayoutUpdated事件计算实际渲染字体大小
Viewbox的缩放是通过ScaleTransform实现的,我们可以获取tb2的渲染变换,计算出实际缩放比例,再乘以tb2的原始FontSize得到实际渲染大小,最后赋值给tb1。
修改tb2_LayoutUpdated事件处理代码:
private void tb2_LayoutUpdated(object sender, EventArgs e) { if (tb2.RenderTransform is ScaleTransform scaleTransform) { // 实际渲染字体大小 = 原始FontSize × 缩放比例(x/y方向缩放一致,取其一即可) double actualFontSize = tb2.FontSize * scaleTransform.ScaleX; tb1.FontSize = actualFontSize; System.Diagnostics.Debug.WriteLine($"tb2实际渲染字体大小: {actualFontSize}"); } }
方法二:使用绑定+自定义转换器(MVVM友好)
如果希望避免后台事件,采用MVVM模式,可以创建自定义转换器,通过绑定自动计算并同步字体大小。
1. 创建自定义转换器
using System.Globalization; using System.Windows.Data; using System.Windows.Media; namespace LiveCharts2Test { public class ScaleTransformToFontSizeConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is ScaleTransform scaleTransform && parameter is double originalFontSize) { return originalFontSize * scaleTransform.ScaleX; } return DependencyProperty.UnsetValue; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } }
2. 修改XAML代码
在Window资源中注册转换器,然后给tb1的FontSize添加绑定:
<Window x:Class="LiveCharts2Test.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:LiveCharts2Test" mc:Ignorable="d" Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded"> <Window.Resources> <local:ScaleTransformToFontSizeConverter x:Key="ScaleToFontSizeConverter"/> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Grid.RowDefinitions> <RowDefinition Height="50*"/> <RowDefinition Height="47*"/> <RowDefinition Height="338*"/> </Grid.RowDefinitions> <TextBlock x:Name="tb1" Grid.Row="0" Grid.Column="0" Text="apple" FontSize="{Binding RenderTransform, ElementName=tb2, Converter={StaticResource ScaleToFontSizeConverter}, ConverterParameter={Binding FontSize, ElementName=tb2}}"/> <Viewbox Stretch="Uniform" Grid.Row="1" Grid.Column="0"> <TextBlock x:Name="tb2" Text="testtesttesttesttesttesttesttesttesttest" /> </Viewbox> </Grid> </Window>
说明
- 方法一实现简单,适合快速解决问题,依赖后台事件处理;
- 方法二更符合WPF的MVVM设计思想,无需后台代码介入,扩展性更强。
内容的提问来源于stack exchange,提问作者J. hlz
相关产品推荐
相关产品推荐

