如何在VSTO中重新加载Ribbon(功能区)的显示?
解决VSTO中Ribbon控件显示不更新的问题
1. 改用回调机制控制Button2的可见性
VSTO的Ribbon控件状态(比如是否可见)不能直接通过属性赋值生效,必须用回调方法来绑定状态:
- 在Ribbon设计器里选中Button2,打开属性面板找到
Visible,点击下拉选「Add Callback」,自动生成GetVisible回调函数。 - 定义两个全局变量:
Private _isButton2Visible As Boolean = False ' 控制Button2显示状态 Private _ribbonUI As Office.IRibbonUI ' 保存RibbonUI实例,用来触发刷新 - 在Ribbon的
Load事件里保存RibbonUI引用:Private Sub Ribbon1_Load(ByVal sender As Object, ByVal e As RibbonUIEventArgs) Handles Me.Load _ribbonUI = e.RibbonUI End Sub - 实现
GetButton2Visible回调,返回全局变量的值:Public Function GetButton2Visible(ByVal control As Office.IRibbonControl) As Boolean Return _isButton2Visible End Function
2. 把耗时操作放到后台线程,避免阻塞UI
你的循环操作会卡住UI线程,导致Ribbon的刷新请求根本没机会处理。用Async/Await配合Task把耗时操作移到后台:
Private Async Sub Button1_Click(sender As Object, e As RibbonControlEventArgs) Handles Button1.Click ' 标记Button2要显示,然后刷新该控件 _isButton2Visible = True _ribbonUI.InvalidateControl("Button2") ' 只刷新Button2,比全局Invalidate更高效 ' 后台执行耗时的Excel操作 Await Task.Run(Sub() Dim WB = Globals.ThisAddIn.Application.ActiveWorkbook For iSheet = 1 To WB.Sheets.Count Dim oSheet = WB.Sheets(iSheet) For irow = 1 To 1000 If bStop Then Exit For For icol = 1 To 20 If bStop Then Exit For ' Excel对象不能跨线程访问,必须切回主线程操作 Globals.ThisAddIn.Application.Invoke(Sub() oSheet.Cells(irow, icol).Value = "Cell" & irow & icol End Sub) Next Next Next End Sub) ' 操作完成后隐藏Button2 _isButton2Visible = False _ribbonUI.InvalidateControl("Button2") End Sub
注意:Excel对象模型不允许跨线程访问,所以后台线程里操作单元格时,必须用Application.Invoke切回主线程执行。
3. 原代码无效的原因
- 直接赋值
Button2.Visible = True没用:Ribbon控件的状态由回调方法决定,不是直接改属性就能生效的。 - 耗时操作阻塞UI线程:就算调用了
Invalidate()和DoEvents(),UI线程被循环占着,根本没时间处理Ribbon的刷新请求,所以Button2显示不出来。
内容的提问来源于stack exchange,提问作者D T
相关产品推荐
相关产品推荐

