WPF实现DataGrid选中行联动RichTextBox公式内容格式变更
实现WPF中DataGrid选中项与RichTextBox公式对应部分联动高亮
这个需求我之前做过类似的,核心思路是给公式里的每个源项片段打上标记,然后在DataGrid选中行时,通过标记定位到RichTextBox里对应的文本并修改样式。咱们一步步来实现:
1. 先定义数据模型
首先创建一个CalculationItem类,用来表示DataGrid里的源项,实现INotifyPropertyChanged方便后续绑定更新:
using System.ComponentModel; using System.Runtime.CompilerServices; public class CalculationItem : INotifyPropertyChanged { private string _id; public string Id { get => _id; set { _id = value; OnPropertyChanged(); } } private string _displayName; public string DisplayName { get => _displayName; set { _displayName = value; OnPropertyChanged(); } } private decimal _value; public decimal Value { get => _value; set { _value = value; OnPropertyChanged(); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }
2. 解析公式并加载到RichTextBox
我们需要把公式字符串中的[MR:xxx]片段提取出来,在插入RichTextBox时给每个片段的Run附加一个Tag(存储对应的源项ID),这样后续就能通过ID快速定位到对应的文本:
using System.Text.RegularExpressions; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Media; private void LoadFormulaIntoRichTextBox(string formulaText) { richTextBox.Document.Blocks.Clear(); var paragraph = new Paragraph(); // 匹配[MR:xxx]格式的正则,xxx可以是任意非]的字符 var regex = new Regex(@"\[MR:([^]]+)\]"); int lastTextPosition = 0; foreach (Match match in regex.Matches(formulaText)) { // 添加匹配片段之前的普通文本 if (match.Index > lastTextPosition) { var plainText = formulaText.Substring(lastTextPosition, match.Index - lastTextPosition); paragraph.Inlines.Add(new Run(plainText)); } // 处理匹配到的源项片段 var itemId = match.Groups[1].Value; var formulaRun = new Run(match.Value) { Tag = itemId, // 用Tag存储ID,方便后续查找 Foreground = Brushes.Black, FontWeight = FontWeights.Normal }; paragraph.Inlines.Add(formulaRun); lastTextPosition = match.Index + match.Length; } // 添加公式末尾剩余的文本 if (lastTextPosition < formulaText.Length) { paragraph.Inlines.Add(new Run(formulaText.Substring(lastTextPosition))); } richTextBox.Document.Blocks.Add(paragraph); }
3. 处理DataGrid选中事件
当DataGrid的选中项变化时,先把RichTextBox里所有高亮的文本恢复默认样式,再找到对应选中项ID的Run,修改它的样式(比如加粗+变色):
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e) { // 先重置所有Run的样式为默认 ResetAllFormulaRunsStyle(); // 获取当前选中的源项 var selectedItem = dataGrid.SelectedItem as CalculationItem; if (selectedItem == null) return; // 遍历RichTextBox里的所有Run,找到对应ID的并高亮 foreach (Block block in richTextBox.Document.Blocks) { if (block is Paragraph paragraph) { foreach (Inline inline in paragraph.Inlines) { if (inline is Run run && run.Tag?.ToString() == selectedItem.Id) { run.Foreground = Brushes.DarkRed; run.FontWeight = FontWeights.Bold; // 可选:自动滚动到高亮位置 run.BringIntoView(); richTextBox.Focus(); break; } } } } } // 重置所有公式片段的样式 private void ResetAllFormulaRunsStyle() { foreach (Block block in richTextBox.Document.Blocks) { if (block is Paragraph paragraph) { foreach (Inline inline in paragraph.Inlines) { if (inline is Run run && run.Tag != null) // 只重置带标记的公式片段 { run.Foreground = Brushes.Black; run.FontWeight = FontWeights.Normal; } } } } }
4. XAML界面布局
把DataGrid和RichTextBox放在界面上,绑定数据并关联选中事件:
<Window x:Class="FormulaHighlightDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="公式联动高亮演示" Height="450" Width="800"> <Grid Margin="10"> <Grid.ColumnDefinitions> <ColumnDefinition Width="200"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <DataGrid x:Name="dataGrid" Grid.Column="0" SelectionChanged="DataGrid_SelectionChanged" AutoGenerateColumns="False" Margin="0 0 10 0"> <DataGrid.Columns> <DataGridTextColumn Header="源项ID" Binding="{Binding Id}" Width="80"/> <DataGridTextColumn Header="名称" Binding="{Binding DisplayName}" Width="*"/> <DataGridTextColumn Header="数值" Binding="{Binding Value}" Width="80"/> </DataGrid.Columns> </DataGrid> <RichTextBox x:Name="richTextBox" Grid.Column="1" IsReadOnly="True" Padding="5"/> </Grid> </Window>
5. 初始化测试数据
在窗口构造函数里加载测试数据和公式:
using System.Collections.ObjectModel; public MainWindow() { InitializeComponent(); // 初始化DataGrid的源项数据 var sourceItems = new ObservableCollection<CalculationItem> { new CalculationItem { Id = "123", DisplayName = "原材料A", Value = 150 }, new CalculationItem { Id = "456", DisplayName = "原材料B", Value = 300 } }; dataGrid.ItemsSource = sourceItems; // 加载公式到RichTextBox var formula = "[MR:123] + [MR:456] * 0.8"; LoadFormulaIntoRichTextBox(formula); }
额外注意点
- 如果你的公式格式有变化(比如
[MR:XXX-YYY]),只需要调整正则表达式@"\[MR:([^]]+)\]"即可,这个正则能匹配[MR:和]之间的任意内容。 - 如果需要支持多选,只需要修改
SelectionChanged事件,遍历dataGrid.SelectedItems,把每个选中项对应的Run都高亮。 - 要是公式很长,
BringIntoView()可以确保高亮的部分在可视范围内。
内容的提问来源于stack exchange,提问作者Clint T
相关产品推荐
相关产品推荐

