WPF TextBlock 中 Run 元素实战——从密码强度检测到 MVVM 绑定


WPF TextBlock 中 Run 元素实战------从密码强度检测到 MVVM 绑定

在 WPF 中,当我们需要同一行文本中不同部分显示不同颜色、字体或粗细 时,最标准、最高效的做法是使用 TextBlock 搭配 Run 内联元素(Inline)。本文以经典的"密码强度检测"为例,讲解 Run 的用法、适用场景及 MVVM 改造方式。


一、为什么不用多个 TextBlock?

新手常见的写法是:

xml 复制代码
<StackPanel Orientation="Horizontal">
    <TextBlock Text="密码强度:"/>
    <TextBlock Text="强" Foreground="Green" FontWeight="Bold"/>
</StackPanel>

这样做有两个问题:

  • 基线对齐困难:字号不同时文本不对齐
  • 多余布局开销:嵌套容器增加视觉树深度

RunTextBlock.Inlines 中的内联元素,多个 Run 在同一文本流中渲染,共享基线、内存占用更低,是显示"标签+高亮值"的首选方案。


二、基础示例:Code-behind 版(密码强度检测)

XAML

xml 复制代码
<Window x:Class="PasswordDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="密码强度检测"
        Height="200" Width="300">

    <StackPanel Margin="20" VerticalAlignment="Center">
        <TextBox x:Name="PasswordBox"
                 TextChanged="PasswordBox_TextChanged"/>

        <TextBlock Margin="0,10,0,0">
            <Run Text="密码强度:"/>
            <Run x:Name="StrengthRun" FontWeight="Bold"/>
        </TextBlock>
    </StackPanel>
</Window>

后台代码(C#)

csharp 复制代码
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace PasswordDemo
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void PasswordBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            string pwd = PasswordBox.Text;
            string strength = GetStrength(pwd);
            Color color = GetStrengthColor(strength);

            StrengthRun.Text = strength;
            StrengthRun.Foreground = new SolidColorBrush(color);
        }

        private string GetStrength(string pwd)
        {
            if (pwd.Length < 6) return "弱";
            if (pwd.Length <= 10) return "中";
            return "强";
        }

        private Color GetStrengthColor(string s) =>
            s == "强" ? Colors.Green :
            s == "中" ? Colors.Orange : Colors.Red;
    }
}

运行效果:

复制代码
密码强度:强   ← "强" 为绿色加粗
密码强度:中   ← 橙色
密码强度:弱   ← 红色

Run.Text 从 WPF 4.0 起是 DependencyProperty,支持数据绑定。


三、Run 元素的实际开发使用场景

场景 说明
状态提示 状态: + 已启用(绿色加粗)
价格显示 + 199(红色大号) + 原价¥299(删除线 Span)
表单说明 必填项: + 姓名*(红色)
日志/报表脚注 第 __ 页 / 共 __ 页(中间数字绑定)
带图标文本行 Run + InlineUIContainer(含小型图标)

不适合 :多段富文本编辑(用 RichTextBox)、超长文档排版(用 FlowDocument


四、MVVM 绑定版(推荐写法)

Run 支持绑定,配合 ViewModel 可将逻辑完全解耦。

ViewModel

csharp 复制代码
using System.ComponentModel;

public class MainViewModel : INotifyPropertyChanged
{
    private string _password;
    private string _strengthText = "弱";
    private System.Windows.Media.Brush _strengthBrush = System.Windows.Media.Brushes.Red;

    public string Password
    {
        get => _password;
        set
        {
            _password = value;
            OnPropertyChanged();
            UpdateStrength(value);
        }
    }

    public string StrengthText
    {
        get => _strengthText;
        set { _strengthText = value; OnPropertyChanged(); }
    }

    public System.Windows.Media.Brush StrengthBrush
    {
        get => _strengthBrush;
        set { _strengthBrush = value; OnPropertyChanged(); }
    }

    private void UpdateStrength(string pwd)
    {
        if (pwd.Length < 6)
        {
            StrengthText = "弱";
            StrengthBrush = System.Windows.Media.Brushes.Red;
        }
        else if (pwd.Length <= 10)
        {
            StrengthText = "中";
            StrengthBrush = System.Windows.Media.Brushes.Orange;
        }
        else
        {
            StrengthText = "强";
            StrengthBrush = System.Windows.Media.Brushes.Green;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(
        [System.Runtime.CompilerServices.CallerMemberName] string prop = null)
        => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}

XAML(绑定 Run)

xml 复制代码
<Window x:Class="PasswordDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="密码强度 MVVM"
        Height="200" Width="300">

    <Window.DataContext>
        <local:MainViewModel />
    </Window.DataContext>

    <StackPanel Margin="20" VerticalAlignment="Center">
        <TextBox Text="{Binding Password, UpdateSourceTrigger=PropertyChanged}"/>

        <TextBlock Margin="0,10,0,0">
            <Run Text="密码强度:"/>
            <Run Text="{Binding StrengthText}"
                 Foreground="{Binding StrengthBrush}"
                 FontWeight="Bold"/>
        </TextBlock>
    </StackPanel>
</Window>

✅ 后台 .cs无需任何事件代码

✅ UI 完全由 ViewModel 驱动

Run.Text / Run.Foreground 均可双向/单向绑定


五、常见注意点

  • Run 不支持 Background(需给父 TextBlock 设)
  • 不要同时设置 TextBlock.TextRun,二者互斥
  • Run 数过多(>10~15)考虑 Span 分组或 FlowDocument
  • Run.Text 绑定要求 .NET Framework 4.0+ / .NET Core WPF(WPF 3.5 不支持绑定)

六、一句话总结

TextBlock + Run 是 WPF 中"同行异样文本"的标准写法,相当于 HTML 的 <span>;简单场景用 Code-behind 直接改 Run.Text/Foreground,正式项目推荐 MVVM 绑定 Run.TextRun.Foreground

相关推荐
largecode20 小时前
座机号码认证如何操作?申请热线实名名片,树立统一官方客服形象
linux·sql·华为·c#·.net·wpf·harmonyos
小满Autumn1 天前
WPF 入门:XAML 语法、布局与数据绑定
microsoft·c#·.net·wpf
小满Autumn1 天前
WPF 进阶:样式、触发器与控件模板
c#·.net·wpf
她说彩礼65万2 天前
WPF视觉树 逻辑树
wpf
贺国亚2 天前
分布式并发
分布式·wpf
Iawfy_2 天前
WPF的ComboBox绑定Enum枚举
wpf
她说彩礼65万2 天前
WPF TemplateBinding
wpf
她说彩礼65万2 天前
WPF 三大模板类型 四大属性名称
wpf
无心水2 天前
金融系统数据一致性之战:联机交易与批量作业的冲突处理完全指南
人工智能·金融·wpf·批量作业·顶尖架构师·联机交易·金融架构师