Excel VSTO - Disable RibbonButton during Cell Edit - excel

I am coding an Excel add in and would like my ribbon buttons to be disabled when the user is clicked into (editing) a cell. I see this happen with other ribbon buttons in Excel and in the TFS Excel add in so I'm hoping there's some way that other developers can accomplish it. Is there some way to determine/handle when an edit begins/ends (i.e. via double clicking/hitting Enter/hitting Escape)?
I was thinking I could manually enable/disable the buttons during these events. I was wondering if the technique described here http://www.codeproject.com/KB/office/Excel_Edit_Mode.aspx is the best way to detect if a cell is currently being edited?
Any guidance would be greatly appreciated.
Thanks

Sorry for the late answer. I just came across your question.
I wanted the same behavior in my project and I succesfuly integrated this solution:
http://www.codeproject.com/KB/office/ExcelInEditMode.aspx
It was painless and worked very well. I just added the class in my project, created an instance of it and attached events to the EditModeOff and EditModeOn events.
Hope that helps (you or someone else)

Here is what I have done to accomplish the same goal as you.
I created a Timer set for 500ms
In the event handler for the Timer, I perform the following check
if (Globals.ThisAddIn.Application.Ready)
{
SetRibbonState()
}
Where SetRibbonState is something like this:
private void SetRibbonState()
{
if (IsEditing())
{
buttonRefresh.Enabled = false;
}
else
{
buttonRefresh.Enabled = true;
}
}
public static bool IsEditing()
{
return !Globals.ThisAddIn.Application.CommandBars.GetEnabledMso(FileNewDefaultIdMso);
}

Related

Excel Custom Task Pane not showing

I'm showing a custom task pane in an excel VSTO add-in, I'm building it and showing it as thus:
var ctrl = new CellTaskPane();
var pane = CustomTaskPanes.Add(ctrl, "Custom Sheet");
pane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
pane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
pane.Visible = true;
This is being done in the ThisAddin.cs file and it working just fine on my machine, both under a Debug session and with the add-in installed via the click-once installer.
However, installing the add-in on a colleague's machine is proving troublesome.
The add-in is functioning and the context menu / ribbon is working perfectly, but the pane just refuses to show.
I have a toggle button on the ribbon which toggles the Visible property on the pane and even clicking that isn't forcing the pane to show.
Any help on this would be greatly appreciated, Google is proving useless for this.
Thanks.
I should mention that CellTaskPane is just a UserControl as per the docs on MSDN: http://msdn.microsoft.com/en-us/library/aa942846.aspx
Turns out it wasn't anything we were doing directly!
There was another add-in installed (third party) which for some bizarre reason was interfering with the pane being shown (no idea why or how).
Shame that Excel doesn't show any sort of error or at least throw an exception.
Ah well.
I suggest you try a very, very simple custom task pane first to see if this works. I put together the most simple example I could think of, basically a single text box that gets a value pushed into it and this is returned to the ribbon when a button is pushed.
If you were to try this then I would do it as a new solution. Create a new VSTO project with a "Designer mode" ribbon. Add a toggle button and a normal button below it. Then copy in this code:
ThisAddIn.cs
using System;
using Office = Microsoft.Office.Core;
namespace ExcelAddIn1
{
public partial class ThisAddIn
{
private Microsoft.Office.Tools.CustomTaskPane pane;
private CellTaskPane ctrl = new CellTaskPane();
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
pane = CustomTaskPanes.Add(ctrl, "Custom Sheet");
pane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
pane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
pane.Visible = true;
pane.VisibleChanged += new EventHandler(taskPaneValue_VisibleChanged);
ctrl.SetName("test");
}
private void taskPaneValue_VisibleChanged(object sender, System.EventArgs e)
{
Globals.Ribbons.Ribbon1.toggleButton1.Checked = pane.Visible;
}
public Microsoft.Office.Tools.CustomTaskPane TaskPane
{
get
{
return pane;
}
}
public CellTaskPane MyContainer
{
get
{
return ctrl;
}
}
private void ThisAddIn_Shutdown(object sender, System.EventArgs e)
{
}
#region VSTO generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InternalStartup()
{
this.Startup += new System.EventHandler(ThisAddIn_Startup);
this.Shutdown += new System.EventHandler(ThisAddIn_Shutdown);
}
#endregion
}
}
Add a new class called CellTaskPane.cs:
using System;
using System.Windows.Forms;
using System.Drawing;
using System.ComponentModel;
namespace ExcelAddIn1
{
public class CellTaskPane : System.Windows.Forms.UserControl
{
public System.Windows.Forms.TextBox test;
public CellTaskPane()
{
InitializeComponent();
}
public void InitializeComponent()
{
test = new System.Windows.Forms.TextBox();
test.Location = new System.Drawing.Point(120, 8);
test.Size = new System.Drawing.Size(232, 20);
test.TabIndex = 0;
Controls.AddRange(new System.Windows.Forms.Control[] { test });
Size = new System.Drawing.Size(375, 150);
}
public void SetName(string text)
{
test.Text = text;
}
public string GetName()
{
return test.Text;
}
}
}
Add the following code to Ribbon1.cs:
using System;
using Microsoft.Office.Tools.Ribbon;
namespace ExcelAddIn1
{
public partial class Ribbon1
{
private void toggleButton1_Click(object sender, RibbonControlEventArgs e)
{
Globals.ThisAddIn.TaskPane.Visible = ((RibbonToggleButton)sender).Checked;
}
private void button1_Click(object sender, RibbonControlEventArgs e)
{
button1.Label = Globals.ThisAddIn.MyContainer.GetName();
}
}
}
Obviously you will need to do a little tweaking to get this to work, I tried to take the default names for a new project and the buttons.
When you run this you should get a custom task pane. When you switch to the "TabAddIn" and click the toggle button it should show/ hide the task pane. When you click the normal button the contents of the only field in the task pane should be copied as the button name. I defaulted this to "test", so even if the task pane isn't visible you can see if it is in memory or not?
I tested this and it appears to work fine. Basically this is just a hacked up version of the examples on MSDN. If you wanted you could probably do this yourself anyway? If nothing else this will enable you to see if there is anything in the more complex ribbon you are working on that causes issues... or if this is a fundamental problem with your colleague's machine.
I had the same problem, but it was not any addin I could disable (COM+ or Excel).
I had my excel configured to open files at startup
(Excel Options -> Advanced -> General)
There, I had an .XLAM that customized the ribbon.
When I cleared this configuration, my addin started working.
I ran into exactly this problem while trying to get the Microsoft sample code for "Walkthrough: Synchronizing a Custom Task Pane with a Ribbon Button" working. Here's a link to the page:
http://msdn.microsoft.com/en-us/library/bb608590.aspx
After starting from scratch about three times and scouring the Internet for a clue as to what I might have been doing wrong, I came across this question and Clint's answer that an add-in was causing his problem. I had a few add-ins enabled, but with some trial and error I found the culprit: Microsoft's own "Analysis Toolpack"!
Once I disabled Analysis Toolpack, the custom pane started appearing and disappearing as expected.
So, as Clint discovered, the first thing you should probably try if you run into this issue is to disable all add-ins and see if that does the trick. If so, then you can go back and begin turning them on until you find the one that is interfering with your custom pane visibility.
Well, after following #GaryP's advice, disabling my other add-ins, and thinking that I'd solved the problem (albeit without access to my other add-ins), I discovered that the add-in would disappear whenever I opened more than one workbook.
But at that point, I didn't just get a missing taskpane or a silent fail, I actually got an error:
The taskpane has been deleted or is otherwise no longer valid
So it seems that disabling add-ins isn't solving the problem in itself, but rather disabling add-ins is reducing the number of open workbooks (even if add-ins aren't visible, they can still have a Ribbon handle)...
The underlying cause is the use of SDI in 2013 and later.
So, now I can have all of my add-ins loaded.
Create a new instance of the task pane for each workbook. Make the following changes to your code and the task pane works even with addins enabled.
private void Application_WorkbookActivate(Microsoft.Office.Interop.Excel.Workbook wb)
{
pane = CustomTaskPanes.Add(ctrl, "Custom Sheet");
pane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
pane.DockPositionRestrict = Office.MsoCTPDockPositionRestrict.msoCTPDockPositionRestrictNoChange;
pane.Visible = true;
pane.VisibleChanged += new EventHandler(taskPaneValue_VisibleChanged);
ctrl.SetName("test");
}
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.WorkbookActivate += new Excel.AppEvents_WorkbookActivateEventHandler(
Application_WorkbookActivate);
}
If you find that even after closing all other add-ins, the TaskPane still doesn't show, it may be because it is loaded in your "Personal.xlsb" workbook. After closing it, I tried making the pane visible again and I received an error that it had been closed.
I had the same problem and didn't fix it by disableing the analysis toolpack, but, rather i had to move the XLAM out of its installed folder (Break the reference to it, since you couldn't remove it through Excel) and it started working.
I've sense added the files back and it continues to work. Activating the addin does cause my custom taskbar to break. Not sure what this long term fix is here.
I know this is very old, but it can be useful for anyone who may look up for an answer, but here we go:
if you are adding the new taskpane under ThisAddIn_Startup, it will only add it once at the start of the excel, and it will not be present for any other Excel session, so based on the following link that shows how to handle multiple sessions:
https://learn.microsoft.com/en-us/previous-versions/office/developer/office-2007/bb264456(v=office.12)?redirectedfrom=MSDN#Anchor_2
I came up with the conclusion that I should create a new taskpane under the other events that can fire when I needed the taskpane, then validate if the current window has the taskpane or not, and create a new one if not and show it. the event can be any trigger like ribbon button, open document, etc.
Dim CurrentTaskPane As Microsoft.Office.Tools.CustomTaskPane = Nothing
Globals.ThisAddIn.RemoveOrphanedTaskPanes() 'to remove any unused taskpane
For Each ctp As Microsoft.Office.Tools.CustomTaskPane In Globals.ThisAddIn.CustomTaskPanes
If ctp.Window.Hwnd = Excel.Application.ActiveWindow.Hwnd Then
CurrentTaskPane = ctp
Exit For
End If
Next
If CurrentTaskPane Is Nothing Then
CurrentTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(New ControlName, "My TaskPane", Excel.Application.ActiveWindow)
End If
CurrentTaskPane.Visible = True
You can find the 'RemoveOrphanedTaskPanes' code from the link provided.
Summarizing other answers: It appears that this is due to loading other Add-ins, .XLAM files, etc. These can be loaded from many different places, and you need to check them all, and remove them. You may be able to reenable them later, so back everything up. Here is a checklist:
File -> Options -> Advanced -> General -> "At startup, open all files in..." Remove those files and disable the option.
File -> Options -> Add-ins -> Check all the Active application add-ins. Near the bottom of the dialog, use the Mange: Excel/Com Add-ins to view the Add-ins and disable or remove them. Even the Microsoft included ones could be causing it, so disable them as well. They do not allow you to remove them, which is fine, as long as they are disabled.
C:\Users\$USERNAME\AppData\Roaming\Microsoft\Excel\XLSTART Remove all files from this directory.
C:\Users\$USERNAME\AppData\Roaming\Microsoft\AddIns Remove all files from this directory.
After this, try again to load the Add-In. Then, add back the things you need one by one and keep testing. They may break it again, or not, there does not appear to be consensus on what kind of Add-In does and does not break the task pane.
If anyone discovers more places to look for Add-Ins, I will add them to the list.

How to track opportunity closed as won outside the form,Like from a view

I open a webresource (HTML) when an opportunity is closed as won.
This is triggered only by clicking on the button in the opportunity form.
I use the following code to achieve the same:
function FrmOnSave(prmContext) {
var lclSaveMode;
if (prmContext != null && prmContext.getEventArgs() != null) {
lclSaveMode = prmContext.getEventArgs().getSaveMode();
if(lclSaveMode==5)
{
window.openStdWin(url,"myWindow");
}
However this does not get triggered when the opportunity is closed from the "Open Opportunity" view. Is there a way to achieve the same? Thank you all!
The best thing to do here, would be to hide the existing close button, add a new button which looks the same and does all the same things but also opens that window.
You can debug using IE (F12) to see which javascript function is being called on your case, or what is actually happening.
#James Wood answer is a good advice though, it is the safest way to achieve what you want.

MonoTouch.Dialog: Dismissing keyboard by touching anywhere in DialogViewController

NOTE: There are two similar SO questions (1) (2), but neither of them provides an answer.
TL;DR: How can one dismiss the keyboard in a MonoTouch.Dialog by letting the user touch any empty space in the view?
I'm writing an app using MonoTouch.Dialog and a UITabBarController. One of my tabs is "Settings"...
When the user starts typing, the keyboard obstructs the tabbar...
Using MonoTouch.Dialog, the only way to dismiss the keyboard is to go to the last field and press the "return" key. Considering the fact that the user cannot press any tab until the keyboard is gone, I would like a better way to do it. Namely, to dismiss if the user taps anywhere else on the screen.
Without MonoTouch.Dialog, it's a snap: simply override TouchesBegan and call EndEditing. But this doesn't work with MT.D. I've tried subclassing DialogViewController and overriding TouchesBegan there, but it doesn't work. I'm currently at a loss.
Or, I wonder, would I be better off ditching the tabbar so I can use a UINavigationController with a "Back" button on top, which won't be hidden by the keyboard?
I suggest you use a tap gesture recognizer that will not cause interference with the TableView event handlers:
var tap = new UITapGestureRecognizer ();
tap.AddTarget (() => dvc.View.EndEditing (true));
dvc.View.AddGestureRecognizer (tap);
tap.CancelsTouchesInView = false;
You missed my question about it also: Can the keyboard be dismissed by touching outside of the cell in MonoTouch.Dialog?
:-)
This is my #1 feature request for MonoTouch.Dialog.
To answer your question: No. It is not possible. I have searched and asked around and have not found any answers.
I assume because it is just a sectioned (grouped) table and if it wasn't sectioned, there wouldn't be any spot to click. However, that is just my speculation.
I wish that miguel or someone that works on monotouch would answer this and say if it is even possible. Possibly a future enhancement?
I figured out a workaround that satisfies me well enough, so I'm answering my own question.
// I already had this code to set up the dialog view controller.
var bc = new BindingContext (this, settings, "Settings");
var dvc = new DialogViewController (bc.Root, false);
// **** ADD THIS ****
dvc.TableView.DraggingStarted += (sender, e) => {
dvc.View.EndEditing (true);
};
This will dismiss the keyboard whenever the user drags the view a little bit. There's no touch event I could find associated with the tableview, so this is the next best thing. I'd welcome any other ideas. Cheers!
One workaround to use the dragging gesture instead of the tap as proposed (that do not interfere with the table view gestures) is to override MonoTouch.Dialog.DialogViewController.SizingSource (or MonoTouch.Dialog.DialogViewController.Source if you don't want uneven rows) and give it to the DialogViewController. I don't know if it is very clean or safe.
public class CustomTableViewSource : MonoTouch.Dialog.DialogViewController.SizingSource
{
public CustomTableViewSource(MonoTouch.Dialog.DialogViewController dvc) : base(dvc)
{
}
public override void DraggingStarted(UIScrollView scrollView)
{
base.DraggingStarted(scrollView);
if (scrollView != null)
{
scrollView.EndEditing(true);
}
}
}

Best way to programmatically create/maintain SharePoint Quick Launch menu

We have a solution that deploys a number of lists and pages. We wan't to create links for them on the Quick Launch menu automatically when a feature is activated.
The structure could be something like this.
Customers
Active
Inactive
Sales
Quotes
Orders
And so on. The site collection admin might add another link between the "Active" and "Inactive" links. When the feature is deactivated I don't want to remove the items, but if the feature is activated again i don't want the navigation to be added again :)
Is there a built in API that you can use? I know about the SPWeb.Navigation.QuickLaunch and the SPNavigationNode(Collection) structure etc. But is there another way?
Hope you can help :)
What kind of other way would you be looking for?
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
SPWeb web = (SPWeb)properties.Feature.Parent;
// Check for an existing link to the list.
SPNavigationNode listNode = web.Navigation.GetNodeByUrl(list.DefaultViewUrl);
// No link, so create one.
if (listNode == null)
{
// Create the node.
listNode = new SPNavigationNode(list.Title, list.DefaultViewUrl);
// Add it to Quick Launch.
web.Navigation.AddToQuickLaunch(listNode, SPQuickLaunchHeading.Lists);
}
}
We have used the method above for a while and it tends to work out just fine.
If you can let me know what kind of thing you are trying to accomplish that manipulating SPWeb.Navigation wont let you do, I might be able to be of some more help

How to control application from WebBrowser Control?

I've googled it, but came out empty. And the worst thing is that I know it is possible.
Anyway, I'm developing an application that uses the WebBrowser control to display information regarding an object (like Outlook does with the Rules and Alerts dialog box).
My question is how do I do for the click on a, say, hyperlink in the WebBrowser execute some function within the Windows Form?
For instance, say I have a link like this and when I click it I want the application to display an specific form, like the Outlook does when you click on hyperlinks like People and Distribution List
This looks useful: How to: Implement Two-Way Communication Between DHTML Code and Client Application Code
ChrisW's answer will work, but there's another way if you're just relying on hyperlinks.
In Comicster, I have links in my WebBrowser control like this:
New Collection
And then in the WebBrowser's Navigating event, I have some code to check if the user has tried to navigate to an "action:" link, and intercept it:
private void webBrowser1_Navigating(object sender,
WebBrowserNavigatingEventArgs e)
{
if (e.Url.Scheme == "action")
{
e.Cancel = true;
string actionName = e.Url.LocalPath;
// do stuff when actionName == "FileNew" etc
}
}
With a little bit of code you can even parse the URL parameters and "pass them through" to your host application's action, so I can do things like:
Edit this issue
... which will open a properties dialog for the issue with ID 1.

Resources