You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.21 17:02:35