How to refresh whole ribbon (not just control)? - c#

I have an VSTO Office/Outlook add-in and ribbon that I want to reload at some point. Unfortunatelly ribbon.invalidate is not something that suits my case, because it just re-fires getLabel etc. methods, while I need to rebuild whole ribbon/group.
I need to force executing method GetCustomUI().
Do you know how can I do it?

There is no way to force Office applications invoke the GetCustomUI callback. If you need to keep your custom ribbon UI hidden at startup by default you can use the getVisible callback for the ribbon controls, including tabs, and when required you may call the IRibbonUI.Invalidate to get your controls callback invoked, so you could return an appropriate value and get your controls appeared on the ribbon.
For example, if an add-in writer implements the getVisible callback procedure for a button, the function is called once, the state loads, and then if the state needs to be updated, the cached state is used instead of recalling the procedure. This process remains in place until the add-in signals that the cached values are invalid by using the Invalidate method, at which time, the callback procedure is again called and the return response is cached. The add-in can then force an immediate update of the UI by calling the Refresh method.

No way to do that - by design, Ribbon is static, even though some controls can be hidden initially and be shown later when their getVisible callback is invoked.
Note that control contents can be populated dynamically (sounds like that is what you actually want), that applies to the dropDown control. In that case, you need to specify getItemCount/getItemLabel/getItemImage/getSelectedItemIndex callbacks.
See the dropDown control description on MSDN: https://learn.microsoft.com/en-us/openspecs/office_standards/ms-customui/700e4451-8706-40c5-8d7b-896e4ae21b69

Related

Can VSTO update/refresh an Office 2007 Ribbon XML menu control

I am already using the Ribbon with XML to add controls to the inspector of a received mail item in Office 2007.
I now want to add a menu/Combo box as well. The problem is that it takes too long to generate the list of items.
Basically is it possible to let the Ribbon be generated and then add the items once they are ready?
I envisage something like:
Create the ribbon with an empty menu
Start a new thread and send it off to get data (thread safe stuff no office)
Get back on the office thread and add the list to the menu
Is it possible to do this?
IMHO, it is difficult to achieve. In Standard ribbon control, values are rather static. They are loaded in to the controls before the ribbon is actually shown. I am not sure if there is a way to intercept it.
It appears it is possible with the use of a DynamicMenu control. Using a numbered list for my answer here is what I did.
Let office show the UI (in this case an Outlook Inspector)
Get the text of the Email Item and then start a new thread to process
When processing is finished get back onto the main UI Thread.
In the Ribbon XML an "empty" DynamicManu exists with a callback for its data
If the result is there is no data then call invalidate and the getVisible call back sets the control to false. Control dissappears.
If there is data to add then invalidate and allow the control to now read the data in the callback.
I would like to thank my secretary for editing my post

Add controls to GUI in background worker

I have a form with a top and bottom panel.
The user will be making selections in the top panel, and each time they change a value on one key field I destroy the controls in the bottom panel, then make a time-consuming call to another application (via COM) and add a list of new controls being added. This refresh process takes several seconds.
I'd like to be able to disable the bottom panel while it's being refreshed, and allow the user to be able to keep working in the top panel. Of course, this is all one GUI running on one thread.
Illustrated:
I played with BackgroundWorker, but of course it cannot directly create controls on the main thread's GUI.
Is it possible for me to do this, i.e. allow one part of the GUI to be disabled and rebuilt in the background, while the user continues to work in on another part?
Is it possible for me to do this, i.e. allow one part of the GUI to be disabled and rebuilt in the background, while the user continues to work in on another part?
In general, no. GUI elements/controls must all be created and used on the UI thread, and nowhere else.
The best way to create this type of scenario is typically to use a BackgroundWorker or other technique to get the required data on a background thread, then build your UI after the data has been loaded completely.

VSTO: Enable ribbon button only when a document is loaded

How does one set a ribbon button in a Word add-in to be enabled when a document is loaded and disabled when no documents are loaded, just Like most of the built-in buttons?
Can one bind a global flag to the "Enabled" property of the button, or is it more complicated than that? I know I could create a timed loop that checks for changes in Application.Documents, but I'm looking for something "cleaner" if possible.
I've already looked at Disable Own Word 2007 Add-In If No Document Loaded and other related questions.
There are several ways to handle this.
first, you can create a publicly exposed function that returns true or false for the enabled state of your button (however you want to determine that), you then define your ribbon xml to point to that function for the Enabled property getter. If you're dealing with an IExtensibility based addin, then this is the way you'd have to go.
If you're dealing with VSTO, then define your ribbon button in the ribbon designer and make it DISABLED by default.
Then, during the STARTUP event, hook the WORD object, specifically the NEWDOCUMENT, DOCUMENTOPEN and WINDOWACTIVATE events.
In the event handler code for each of those events, enable or disable your buttons as applicable depending on which event fired and which document was activated at the time.
Use the DocumentChange event instead. Hook up will be something like this:
Globals.ThisAddIn.Application.DocumentChange += new EventHandler(OnDocumentChange);
And the Handler
void OnDocumentChange()
{
this.myButton.Enabled = wordApp.Documents.Count > 0;
}
Interesting, my VSTO Contrib project (http://vstocontrib.codeplex.com/documentation) has some features which make ribbon management simpler.
The cleanest way is to use my ribbon factory, but the project will need to be updated to disable buttons if there are no viewmodels to query for the status of the button. In fact it is a scenario I havent really covered.
You have 3 parts an add-in is interested in, the view (window), the context (the document) and the ribbon. VSTO Contrib means you get a view model per context, and it manages/abstracts the ribbon and view so it appears you have a ribbon per context, and it tells you the current active view (for multiple windows showing same document scenarios).
The missing part is if there is a ribbon, but no contexts and no viewmodels, it should invalidate that ribbon control and disable it. It should be a pretty simple change, email me if you are interested in giving VSTO Contrib's RibbonFactory a spin and I can make this change for you.

Cut,Copy and Paste Any UserDefined UserControl from/on the MDIForm

I am creating many usercontrols in an windows application in C# 3.5. I want to copy any usercontrol and paste it on another location of the MDIForm. Similarly in case of Cut option. I am using these three options in a contextmenustrip. And theses options are visible when I right click on the usercontrol. Can anyone tell me how It will be done at run time?
That requires giving the controls a new Parent. Explicitly supported by Winforms, they can even have no parent, quite a trick. You can do it directly by assigning the Parent property. Or by adding the control to another Controls collection, it will be automatically removed from the one it was in before.
Be careful, this flexibility comes with a price. It is also a source of a nasty leak that can crash your program after a while. That's caused by the no-parent trick, otherwise triggered by a Cut without a subsequent Paste. If you use Controls.Remove() or Controls.Clear() then the control is moved to the 'parking window', an invisible window created by the Winforms plumbing that acts as a temporary host. If you then don't either move the control to another parent or forget to call its Dispose() method then the control will live forever. Until your program runs out of resources or the user terminates the program.
The out of resources bomb ("cannot create window") typically happens after a few hours so is easily missed when debugging. You can see it in TaskMgr.exe, Processes tab. View + Select Columns and tick USER objects. Also tick GDI Objects and Handles to feel good about your program not leaking.
If you put the controls on a Panel then you can move them all together with just a single line of code by moving the panel.
You could remove the control from the ControlCollection in case of cut and cache it to add that control to some other form when pasted like you could do
panel1.Controls.Add(newPanelButton);// To add, you might have to change the control `Location` as per your need
panel1.Controls.Remove(newPanelButton);//To remove
In case of having cut/copy effect on the same form you could just change the Location of the control to the new location where you want to paste that control.

Updating UI objects in windows forms

Pre .net I was using MFC, ON_UPDATE_COMMAND_UI, and the CCmdUI class to update the state of my windows UI.
From the older MFC/Win32 reference:
Typically, menu items and toolbar buttons have more than one state. For
example, a menu item is grayed
(dimmed) if it is unavailable in the
present context. Menu items can also
be checked or unchecked. A toolbar
button can also be disabled if
unavailable, or it can be checked.
Who updates the state of these items
as program conditions change?
Logically, if a menu item generates a
command that is handled by, say, a
document, it makes sense to have the
document update the menu item. The
document probably contains the
information on which the update is
based.
If a command has multiple
user-interface objects (perhaps a menu
item and a toolbar button), both are
routed to the same handler function.
This encapsulates your user-interface
update code for all of the equivalent
user-interface objects in a single
place.
The framework provides a convenient
interface for automatically updating
user-interface objects. You can choose
to do the updating in some other way,
but the interface provided is
efficient and easy to use.
What is the guidance for .net Windows Forms? I am using an Application.Idle handler in the main form but am not sure this is the best way to do this. About the time I put all my UI updates in the Idle event handler my app started to show some performance problems, and I don't have the metrics to track this down yet. Not sure if it's related.
I've found it easiest to have the menu item event handler spawn a background thread that disables the menu item, does the work, and then re-enables the menu item. That way, the UI is available to handle other UI requests, and I don't need to poll for when the operation is complete.
I usually include logic that prevents more than one operation that uses the same resources to happen simultaneously. This means creating a function to disable/enable all similar resources at once. e.g. I might only allow 1 file operation to happen at a time, so I would create a function to disable/enable all the menu items associated with file operations and call it from every one of those menu items.
Just change their property, e.g.
obj.Enabled = true;
or
obj.Enabled = false;
The property of that object will automatically call .Invalidate() or .Refresh() for you, so the control should be repainted automatically.
If you want to do a BIG task which would block the UI for multiple seconds, it's worth using Threads + Delegates.
AFAIK, in the standard .NET System.Windows.Forms world, this functionality is not available out the box.
This problem can be answered in a few ways. The links below are useful resources:
•OnUpdate equivalent
•ActionLists for Windows forms
•Command UI Updating Windows Forms in C#

Categories