Enable/Disable Ribbon Buttons in Word 2007 Addin - c#

Currently i am working on a word Addin, where i have added controls to the ribbon dynamically. Now, I need to catch the dynamic button "btnSubmit" and based on the condition i need to enable/disable the button.
when the document is opened for the first time it should be enabled and Once the Button is clicked it should be disabled.
This should be done on a boolean condition. Any help would be greatly appreciated.
thanks,
KSR Prasad

It is possible through RibbonXML using the getEnabled event.
Ribbon XML:
<button id="button1" onAction="button1_Click" getEnabled="button1_EnabledChanged" />
Code:
public void button1_Click(Office.IRibbonControl control)
{
if (control.Id == "button1")
{
// your code
clicked = true; // a boolean variable
}
}
public bool button1_EnabledChanged(Office.IRibbonControl control)
{
if (control.Id == "button1")
return !clicked;
}

If you've already created the button, just create a regional scope WITHEVENTS variable to hold it in, assign it, then react to the click event to disable the button (the button object has an enabled property).
Private WithEvents _MyButton As Ribbon.RibbonButton
....
Set _MyButton = {the just created button}
then handle the click event

My preference for this type of issue is to use RibbonXml rather than the designer.
A really simple option would be have a Dictionary which you can then store in the ribbon callback class. If you wanted a nicer option, VSTO Contrib (http://vstocontrib.codeplex.com/) allows you to create a 'viewmodel' per document quite easily, then you simply can bind the button enabled to a property on the viewmodel.
More info on ribbon xml: http://jake.ginnivan.net/vsto-ribbon-designer-in-depth
More info on vsto contrib and how it can help you: http://jake.ginnivan.net/vsto-contrib/ribbon-factory
Cheers,
Jake

Related

How to disable the "Save As" tab in Word 2016

I have a VSTO add-in that I developed for Word 2010 and I'm currently in the process of upgrading to Office 2016. One of the things I do is, in the ribbon xml, disable the save as command (<command idMso="FileSaveAs" getEnabled="IsFileSaveAsEnabled" ...>) with certain documents. However, it appears that Microsoft have added a new Save As tab to the backstage view in Word 2016 that I can't dynamically disable.
The disabling of the save as command effects the Save As button if it's added to the quick access toolbar, but it does not effect the tab on the back stage view. I've tried changing other things on this tab and it appears to ignore any changes I attempt to make.
I'm developing in VS 2017 and automatically migrated the project to Office 2016.
If I add
<backstage>
...
<tab idMso="TabSave" getEnabled="IsFileSaveEnabled" />
...
</backstage>
to my ribbon.xml the IsFileSaveEnabled isn't invoked.
public bool IsFileSaveEnabled(IRibbonControl control)
{
return false; // Not the actual implementation, but you get the idea.
}
In fact even setting the enabled attribute to false does nothing, however this
<backstage>
...
<tab idMso="TabSave" visible="false" />
...
</backstage>
does actually hide the tab. Though this is no good because this will happen for all documents, but I want it to be conditional.
So is it just not possible to disable this tab the way I want to or is there something new I need to do? I can't really find anything else on the web about this.
I'm going to answer my own question here as I thought of a work around. Instead of trying to interact with the built in save as tab I'm just going to permanently hide it and add my own copy of this tab that I create from scratch to look and behave exactly like the built in tab. Bit more work, but can't think of any other way of doing this.
If the visibility should be conditional then the setting needs to be dynamic. That means it requires a callback rather than a static setting:
<tab idMso="TabSave" getVisible="procedureName" />
This procedure needs to be in the Ribbon1.cs (or whatever the class is called in your VSTO project) and the logic for making the control visible (or not) - same as IsFileSaveEnabled. The callback will trigger when the Ribbon loads the first time, and any time the control (or entire Ribbon) is invalidated (Ribbon.Invalidate / InvalidateControl(controlID)). This would usually be done in an event such as DocumentOpen, DocumentClose, DocumentChange, etc.
I'm assuming you already have procedures to initialize a Ribbon object in your code (GetCustomUI and Ribbon_Load).
Here's a simple example I have in a test project, that toggles the visibility of a Group:
private Office.IRibbonUI ribbon; //initialized via Ribbon's load event
bool bGetVisible = false;
//triggered by clicking a Ribbon control
public void ShowFontGroup_Click(Office.IRibbonControl ctl)
{
bGetVisible = true;
ribbon.Invalidate(); //triggers all "get" callbacks in the Ribbon
}
//callback triggered by invalidating the Ribbon
public bool GroupFont_GetVisible(Office.IRibbonControl ctl)
{
return bGetVisible;
}
I don't have Word 2016 so I can't verify this, but you could probably intercept the save event and abort when it's a Save As.
// this is for a document-level add-in; do this in your startup method
BeforeSave += new SaveEventHandler(ThisDocument_BeforeSave);
private void ThisDocument_BeforeSave(object sender, SaveEventArgs e)
{
e.Cancel = e.ShowSaveAsDialog;
return;
}
I do something similar in my add-in and it works well.

Custom task pane with multiple open workbooks

I've successfully implemented the Microsoft sample "Walkthrough: Synchronizing a Custom Task Pane with a Ribbon Button" found here:
http://msdn.microsoft.com/en-us/library/bb608590.aspx
Initially I ran into a problem with the task pane not showing, which turned out to be the result of some conflict between my add-in and Microsoft's "Analysis Toolpack". Once I disabled Analysis Toolpack the custom task pane began to show and hide as expected.
I then wrote some code to alter cells in a selected range when the user presses a button. That seemed to work just fine -- until I opened another workbook! Each workbook window got its own add-in ribbon, but when I clicked the toggle button to open/close the custom task pane it would only open/close the custom task pane for the first window that was created. This is regardless of which window I click the toggle button in.
The code instantiates the CustomTaskPane object in ThisAddIn_Startup (just like in the example code). The only thing I've added really is the button action in the UserControl:
using xl = Microsoft.Office.Interop.Excel;
namespace SynchronizeTaskPaneAndRibbon
{
public partial class TaskPaneControl : UserControl
{
public TaskPaneControl()
{
InitializeComponent();
}
private void actionButton1_Click(object sender, EventArgs e)
{
xl.Range selection_rng = Globals.ThisAddIn.Application.Selection;
foreach (xl.Range cell in selection_rng.Cells)
{
if (cell.Value is string)
{
string v = cell.Value;
cell.Value = v + "*";
}
}
}
}
}
The rest of the code is just as it is in the example.
Is there a way to change the example so that it will work for open multiple workbooks? What I want is for the same Add-In to appear in each workbook window, with the same Ribbon and with the same Custom Pane. And, of course, to have any ribbon actions (such as a button press) route to the custom task pane that appears within the same window.
Yes there is another example on MSDN which talks about managing custom taskpanes in multiple documents. Do note that this is from the perspective of Word/InfoPath but the underlying idea will be same for Excel too.
Broadly speaking, you need to add a new taskpane for current workbook if it does not have one. So move the adding of custom taskpane logic from Addin startup to ribbon button click event. Doing this in button click event gives you opportunity to add a new taskpane to current document when ribbon is clicked.
Link: https://msdn.microsoft.com/en-us/library/bb264456(v=office.12).aspx?f=255&MSPPError=-2147217396#Anchor_2
Putting the useful code snippets below in case the link goes dead in future:
//Add a custom taskpane to active Word document
public void AddCalendarTaskPane(Word.Document doc)
{
ctpCalendar = this.CustomTaskPanes.Add(new CalendarControl(),
"Select a date", doc.ActiveWindow);
ctpCalendar.Visible = true;
}
Instead of removing, I recommend hiding the taskpane by toggling Visible flag to false but YMMV. Hope this helps.

Create a Checkbox for a Winform

I searched myself through for about 1 hour only to realise that I might be the biggest beginner, but since everybody must have been at that point in a time, i hope for your patience.
My question: i have an empty Winform which is opened after a button is pressed on a custom created outlook properties button.
the button code:
private void FensterOeffnen(object sender, IRibbonControl control, bool pressed)
{
EinstellungenFenster fenster = new EinstellungenFenster();
fenster.ShowDialog();
}
the Winform code:
public partial class EinstellungenFenster : Form
{
public EinstellungenFenster()
{
InitializeComponent();
Text = "Outlook Add-in Einstellungen";
}
}
the Reason i need a checkbox:
i want to implement a popup (Debug so to say) window on each and every method that i have on my Outlook Add-in if the button is checked, so that if the code stopps working at a certain point after deployment, i can still easily tell where the problem is.
Thanks a lot!
Open the toolbox on vs by going to view and toolbox then expand all windows forms and scroll down to check-box and drag it on to the form.
and then implement the checked procedure by adding on the button clicked
if (Checkboxname.Checked = true)
{
// Do Stuff when checked
}
hope this helps

Sharepoint Ribbon: Circumventing Context sensitivity

I'm new to sharepoint development and I'm trying to modify the behaviour of the Sharepoint ribbon. As you all know, the ribbon is such that when something else gains focus(e.g a list item), the ribbon automatically switches to an appropriate tab or tab group(e.g the List tools tab group).
I'd like to disable this constant switching of tabs and make the browse tab to always be the active tab, unless the user explicitly clicks on another tab.
I've tried doing the following in the Page_Load() of a Usercontrol, but it only works once, when the page is initially loaded. What am I doing wrong? More importantly, how could I do it right, if at all?
Basically, I'm hoping someone could point me to the event that's fired when the context changes and the ribbon switches, and how I could hook up to this event and force the ribbon to switch back to the browse tab.
protected void Page_Load()
{
string showBrowseTabScript = string.Empty;
showBrowseTabScript = #"
function ShowBrowseTab() {
var ribbon = SP.Ribbon.PageManager.get_instance().get_ribbon();
SelectRibbonTab(""Ribbon.Read"", true);
}
SP.SOD.executeOrDelayUntilScriptLoaded(function() {
var pm = SP.Ribbon.PageManager.get_instance();
pm.add_ribbonInited(function() {
ShowBrowseTab();
});
var ribbon = null;
try
{
ribbon = pm.get_ribbon();
}
catch (e) { }
if (!ribbon) {
if (typeof(_ribbonStartInit) == ""function"")
_ribbonStartInit(_ribbon.initialTabId, false, null);
}
else {
ShowBrowseTab();
}
},
""sp.ribbon.js"");
";
this.Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "BrowseTabScript", showBrowseTabScript, true);
}
Here is my solution to the problem, in case anyone is interested.
Taking Ken Henderson's suggestion into consideration, I was able to achieve what I've been trying to do, although I achieved this by modifying the code of the SP.Ribbon.js and SP.Ribbon.debug.js files. I'm using the SP.Ribbon.debug.js to show my solution below, since it is not as cryptic as the SP.Ribbon.js.
Basically, I use the code below to trick the ribbon into thinking that the User is on a different tab and has clicked on the "Browse" tab. You will notice that I set the old tab information in the code. It will still work without me doing this, but I did it just in case the ribbon needs that information for something else I'm not aware of. This code, in combination with the Page_Load() function I posted in the first post, cause the ribbon to behave just like I needed it to.
SP.Ribbon.PageManager.prototype = {
executeRootCommand: function (commandId, properties, commandInfo, root) {
ULSMg8: ;
var $v_0;
if (!SP.ScriptUtility.isNullOrUndefined(commandInfo) && commandId !== 'RibbonEvent' && (commandId !== 'CommandContextChanged' || (!SP.ScriptUtility.isNullOrUndefined(properties) && properties['ChangedByUser']))) {
// My changes to SP.Ribbon
if (properties["ChangedByUser"] === false) {
properties["ChangedByUser"] = true;
var $NewContextId = properties["NewContextId"];
var $NewContextCommand = properties["NewContextCommand"];
properties["OldContextId"] = $NewContextId;
properties["OldContextCommand"] = $NewContextCommand;
properties["NewContextId"] = "Ribbon.Read";
properties["NewContextCommand"] = "ReadTab";
SelectRibbonTab("Ribbon.Read", true);
}
// End of changes to SP.Ribbon
// the rest of the code has been ommitted for clarity
return $v_0;
}
}
To the best of my knowledge SharePoint doesn't expose any events to detect when the ribbon tabs update (either tabs adding/removing or which is active). At least I was unable to find any a few weeks ago when I was trying to detect when tabs were added/removed (I didn't care which was active just the number/width of them).
(Sorry for the lack of details, the SharePoint dev environment at the office is unavailable at the moment so I can't look up the details very easily.)
There are two possiblities for solving this problem (each has risks/problems):
Override JS Functionality
Figure out what JavaScript function is being called when the user clicks on an item that updates the ribbon. You might be able to replace that function with your own that provides the behavior you want. This would be similar in concept to a custom master page that scrolls on the window and has to change the behavior of the width sizing. I'm unable to verify the details at the moment but it looks like the function is called SingleItemSelect in core.js.
This could be a problem if you have exceptions to when to override this behavior and if MS changes anything in the future you're implementation may break and/or need to be updated.
Add your own event handler
In your JavaScript code try to find an appropriate DOM event to attach an event handler to in the ribbon to detect when MS's code changes the ribbon. There is a good chance given the limitations of the DOM events that there will not be an event to attach a handler to. You may end up adding a function that is called periodically (polling loop/timer) that detects ribbon tab changes and resets the active one.
Honestly this will not work well since there will be flickering as MS's ribbon code changes the active tab and your's changes it back. Additionally you'll need to detect when the user clicks on a tab so that you don't undo their changes.
Wrap up
Honestly I would push back and get this requirement changed so that the ribbon behavior works the way MS designed and not try to fight it. If the ribbon showing up when the user clicks on an item is really an issue then I would propose to the client that instead of forcing the Browse tab as active to add an additional link in the ribbon area somewhere that allows the ribbon (or at least the part that expands over the title area) to be toggled as hidden/shown independently of what MS's JavaScript is doing to the ribbon.

WPF Ribbon collapse and expand programmatically

With the latest (October 2010) WPF Ribbon libraries, there exists a menu item to minimize/maximize (or collapse/expand, if you prefer) the ribbon control.
Does anyone know if there's also a way to hook into the events that control this behaviour so that it could be controlled programmatically from separate UI?
Or, better yet, is there a way to get a collapse/expand button to display in the ribbon like the 2010 Office apps do?
You can use the boolean property IsMinimized on the Ribbon class to show/hide the ribbon itself. It is a dependency property, so you can bind to its value to support the scenarios you describe.
As far as I know, the default template does not have a show/hide button, like Office does, but it shouldn't be too hard to modify the template (using Blend) to add one.
If what you need is know when the bar gets minimized (this happens when you double click a tab header) you could hook to the IsMinimizedChanged event, but er.. it is missing.
Hopefully it is a DependencyProperty so you can successfully hook to any DependencyProperty change this way:
DependencyPropertyDescriptor.FromProperty(Ribbon.IsMinimizedProperty, typeof(Ribbon))
.AddValueChanged(ribbon, (o, args) => /* your code here */);
What I wanted to do (and hence got here) is to prevent it from minimizing when double clicking the header so I ended up using this code:
DependencyPropertyDescriptor.FromProperty(Ribbon.IsMinimizedProperty, typeof(Ribbon))
.AddValueChanged(ribbon, (o, args) => ribbon.IsMinimized = false);
Is not so fancy but gets the job done.
Add a toggle button(simple button and set its content to v or ^ depending upon the operation requested) and then you can use ContentControl in button click to fulfill your requirement:
ContentControl contentControl = FindVisualChildataBankyName<ContentControl>(rbnName, "mainItemsPresenterHost");
contentControl.Visibility = System.Windows.Visibility.Collapsed;
Use contentControl.Visibility = System.Windows.Visibility.Visible; in order to maximize the ribbon

Categories

Resources