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

GetFourthColor频繁触发导致性能下降,如何使其仅在点击toggle按钮时执行?

解决方案

问题根源

你遇到的频繁触发问题核心来自两个错误用法:

  1. 不应该在get*系列回调(GetPressedRestricted、GetFourthColor都属于这类)中调用InvalidateControl方法。Office Ribbon的机制是:只要调用Invalidate/InvalidateControl,就会触发对应控件所有get前缀的回调,你在回调内又触发刷新,直接形成了无限循环调用链,导致方法反复执行。
  2. 没有对回调返回值做缓存,每次触发都要执行读注册表、生成位图、业务逻辑判断等重操作,放大了性能损耗。

修复步骤

  1. 将所有Invalidate相关调用从get*回调中移除,仅在需要变更状态的场景(比如点击按钮、切换文档、配置变更)下才调用刷新。
  2. 为get回调的返回值添加缓存,只有状态真的发生变更时才重新计算返回值,平时直接返回缓存结果。
  3. 控制Invalidate的调用范围,仅刷新真正需要更新的控件,不要调用全局ribbon.Invalidate()。

修复后代码示例

首先新增缓存字段

// 缓存GetFourthColor返回的位图
private Bitmap _cachedFourthColor;
// 缓存GetPressedRestricted返回的选中状态
private bool? _cachedPressedRestricted;
// 标记状态是否过期,需要重新计算缓存
private bool _isStateExpired = false;

调整GetFourthColor方法

public Bitmap GetFourthColor(IRibbonControl control)
{
    // 仅缓存为空或者状态过期时才重新生成位图
    if (_cachedFourthColor == null || _isStateExpired)
    {
        // 注意:如果旧位图存在需要先释放,避免内存泄漏
        _cachedFourthColor?.Dispose();
        _cachedFourthColor = ColorHelper.GetBitmapColor(RegeditHelper.GetClassficationTag(4));
    }
    return _cachedFourthColor;
}

调整GetPressedRestricted方法

public bool GetPressedRestricted(IRibbonControl control)
{
    // 移除所有Invalidate相关调用
    if (_cachedPressedRestricted == null || _isStateExpired)
    {
        if (durum)
        {
            _cachedPressedRestricted = MetaDataControl(RegeditHelper.GetClassficationTag(4));
        }
        else
        {
            _cachedPressedRestricted = false;
        }
    }
    return _cachedPressedRestricted.Value;
}

调整点击事件PublicRestricted

public void PublicRestricted(IRibbonControl control, bool pressed)
{
    documentService.SetActiveBook(Globals.ThisAddIn.Application.ActivePresentation);
    documentService.AddorUpdateWorkbookProperty("Tag", RegeditHelper.GetClassficationTag(4));
    
    // 标记状态过期,下次回调会重新生成缓存
    _isStateExpired = true;

    // 仅在点击时刷新需要更新状态的其他控件
    ribbon.InvalidateControl("textButtonpublic");
    ribbon.InvalidateControl("textButton2internal");
    ribbon.InvalidateControl("textButton2confidential");
    // 刷新当前按钮本身
    ribbon.InvalidateControl(control.Id);

    // 重置过期标记
    _isStateExpired = false;

    RibbonInvalidateAndDeleteControl(control, pressed);
}

额外补充

如果存在其他需要更新按钮状态的场景(比如切换当前打开的文档、注册表配置变更),只需要在对应事件触发时,先把_isStateExpired设为true,再调用对应控件的InvalidateControl即可,不需要修改回调逻辑。

内容的提问来源于stack exchange,提问作者Mehmet Ceylan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.10 13:09:01