WPF TextBlock 中 Run 元素实战------从密码强度检测到 MVVM 绑定
在 WPF 中,当我们需要同一行文本中不同部分显示不同颜色、字体或粗细 时,最标准、最高效的做法是使用 TextBlock 搭配 Run 内联元素(Inline)。本文以经典的"密码强度检测"为例,讲解 Run 的用法、适用场景及 MVVM 改造方式。
一、为什么不用多个 TextBlock?
新手常见的写法是:
xml
<StackPanel Orientation="Horizontal">
<TextBlock Text="密码强度:"/>
<TextBlock Text="强" Foreground="Green" FontWeight="Bold"/>
</StackPanel>
这样做有两个问题:
- 基线对齐困难:字号不同时文本不对齐
- 多余布局开销:嵌套容器增加视觉树深度
Run 是 TextBlock.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.Text和Run,二者互斥 Run数过多(>10~15)考虑Span分组或FlowDocumentRun.Text绑定要求 .NET Framework 4.0+ / .NET Core WPF(WPF 3.5 不支持绑定)
六、一句话总结
TextBlock + Run是 WPF 中"同行异样文本"的标准写法,相当于 HTML 的<span>;简单场景用 Code-behind 直接改Run.Text/Foreground,正式项目推荐 MVVM 绑定Run.Text和Run.Foreground。