如何配置XAML单元格模板,使SSN仅在Tooltip弹出时按需解密
实现方案
核心逻辑完全匹配需求:仅在Tooltip实际满足弹出条件时触发单条查询,绝不批量加载全量SSN数据,适配.NET Framework 4.5.2开发环境。
第一步:修改SSN列的XAML模板
原有DelayToolTip样式无需改动,仅调整SSN列CellTemplate内的Tooltip结构,添加命名控件方便后台更新文本,绑定Tooltip打开事件:
<DataGridTemplateColumn Header="SSN"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Text="Hidden" Foreground="DarkOrange" Background="Aquamarine" Margin="3,1" Style="{StaticResource DelayToolTip}" Padding="3" ToolTipOpening="SsnCell_ToolTipOpening"> <TextBlock.ToolTip> <StackPanel Orientation="Horizontal"> <TextBlock Text="SSN: " FontWeight="Bold" /> <!-- 给结果展示TextBlock加命名,方便后台赋值 --> <TextBlock x:Name="SsnResultDisplay" Text="准备加载" /> </StackPanel> </TextBlock.ToolTip> </TextBlock> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn>
第二步:添加后台事件处理逻辑
在当前UserControl的代码后置中实现以下逻辑,包含单条查询、线程安全缓存、后台异步执行、状态异常保护:
- 初始化线程安全缓存,仅存储用户实际触发过查询的SSN值,避免重复打库
- 在Tooltip触发打开时,先查缓存,未命中则后台调用解密存储过程
- 全程不操作非悬停行的SSN数据,严格满足禁止批量加载的要求
using System.Collections.Concurrent; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; public partial class YourUserControl : UserControl { // 线程安全的局部缓存,仅保留用户悬停触发过的SSN后四位,缓存生命周期随UserControl private readonly ConcurrentDictionary<int, string> _ssnLocalCache = new ConcurrentDictionary<int, string>(); public YourUserControl() { InitializeComponent(); } private async void SsnCell_ToolTipOpening(object sender, ToolTipEventArgs e) { // 获取当前触发行的绑定上下文 var currentTextBlock = (TextBlock)sender; var currentPerson = (Person)currentTextBlock.DataContext; var tooltipRoot = (StackPanel)currentTextBlock.ToolTip; var resultDisplay = (TextBlock)tooltipRoot.FindName("SsnResultDisplay"); var tooltipInstance = (ToolTip)currentTextBlock.ToolTip; // 标记Tooltip状态,避免查询返回时Tooltip已关闭导致的UI操作异常 bool isTooltipClosed = false; void CloseHandler(object s, RoutedEventArgs args) => isTooltipClosed = true; tooltipInstance.Closed += CloseHandler; // 优先读缓存,避免重复查询 if (_ssnLocalCache.TryGetValue(currentPerson.ID, out var cachedLast4)) { if (!isTooltipClosed) resultDisplay.Text = $"**{cachedLast4}"; tooltipInstance.Closed -= CloseHandler; return; } // 缓存未命中,先展示加载状态 resultDisplay.Text = "正在加载..."; try { // 后台线程执行数据库解密查询,不阻塞UI线程 var last4 = await Task.Run(() => { // 替换为你已写好的解密存储过程调用方法,传当前行的Person.ID作为参数 return DecryptSsnStoredProc.GetSsnLast4ById(currentPerson.ID); }); // 写入缓存 _ssnLocalCache.TryAdd(currentPerson.ID, last4); // 回到UI线程更新展示 if (!isTooltipClosed) { resultDisplay.Text = $"**{last4}"; } } catch { if (!isTooltipClosed) { resultDisplay.Text = "信息加载失败"; } } finally { tooltipInstance.Closed -= CloseHandler; } } }
关键适配说明
- 触发时机完全匹配你配置的延迟规则:
ToolTipOpening事件仅在鼠标悬停满InitialShowDelay(1秒)、Tooltip即将真正弹出时触发,不会因为用户快速划过单元格就产生无意义查询 - 严格遵守不批量加载的要求:全流程仅对用户悬停过的单个PersonID发起解密查询,其他行的加密SSN完全不读取,相比全量解密45分钟的性能损耗是数量级提升
- 兼容.NET Framework 4.5.2:所用API均为该框架原生支持的能力,无需升级版本或引入第三方依赖
- 异常保护逻辑覆盖了Tooltip提前关闭、数据库查询超时等常见场景,不会出现UI卡顿或运行时报错
内容的提问来源于stack exchange,提问作者Rod
相关产品推荐
相关产品推荐

