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.
Related
I am new to powerpoint add in and looking to add custom task pane.
https://msdn.microsoft.com/en-us/library/Microsoft.Office.Tools.CustomTaskPane(v=vs.110).aspx
from Above link you can add custompane by using
this.CustomTaskPanes.add()
I cannot find CustomTaskPanes in the intellisense when trying to do it from ribbon control click.
Any ideas?
The CustomTaskPanes collection is a property on the ThisAddIn class.
So, you will be able to access it within the ThisAddIn_Startup method using the "this." syntax. If you're not seeing the collection in intellisense/autocomplete.
The issue may have arised due to some possibilities like :
You're not using VSTO(Visual Studio Tools for Office) 2005 SE.
You're using VSTO 2005 SE but you installed on top of a previous VSTO v3 CTP which was not completely removed.
You're building an add-in for an application that does not support custom task panes (all the Office 2003 apps, Visio 2007).
That's a sample code to create a "Log Pane" and load a control into it. It's defined as a new property of ThisAddin.cs class, so you can invoke it by Global.ThisAddin.LogPane
private OfficeTools.CustomTaskPane _logPane;
public OfficeTools.CustomTaskPane LogPane
{
get
{
if(_logPane==null)
{
//my winforms component to load into the pane
var logViewerComp = new LogViewerComp();
_logPane = CustomTaskPanes.Add(logViewerComp, "Log Pane");
//makes the log component fill the all pane size
logViewerComp.Dock = DockStyle.Fill;
//sets the opening position of the pane into PPT view
_logPane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionBottom;
//does something when the pane shows/hides
//in this case refreshes the Ribbon to enable/disable
//the toggle button status related to the pane
_logPane.VisibleChanged += (snd, ev) =>
{
Ribbon.Reload();
};
}
return _logPane;
}
}
Note: when you create a Pane it belongs to the all app and it is shared between all presentations the user opens.
I am developing an Outlook plugin using add-in-express. I have added an adxOlFormsManager there. Which contains a Forms collection named ‘adxOlFormsCollectionItem1’. I have set the form class name to as “FlowOutlook.Plugins.Chat.ChatExplorerPane”. Yes, ChatExplorerPane is my ADXOlForm.
I implement a custom event for the my ADXOlform using following code:
private void AddinModule_AddinStartupComplete(object sender, EventArgs e)
{
try
{
var currentChatTypeForm = AddinModule.CurrentInstance.adxOlFormsCollectionItem1.FormInstances(0) as ChatExplorerPane;
currentChatTypeForm.OnChatTypeSelected += currentChatTypeForm_OnChatTypeSelected;
}
catch (Exception ex)
{
Debug.DebugMessage(2, "AddinModule : Error in AddinModule_AddinStartupComplete() : " + ex.Message);
}
}
My Problem is :
If I explorer layout as “RightSubpane” this works fine. But after I changing the explorer layout as dock right (using Properties window), adxOlFormsCollectionItem1.FormInstanceCount is 0. (Which means “currentChatTypeForm” will be null).
What I am supposed to do :
private void ChangeExplorerLayout(AddinExpress.OL.ADXOlForm form)
{
if (form == null) return;
form.XXX = AddinExpress.OL.ADXOlExplorerLayout.DockRight;
}
I wrote above method to change the explorer layout by code. I hope I may be able to call that safely inside AddinModule_AddinStartupComplete, after initializing my custom method. But I need to know the code for replacing ‘XXX’ to complete the method and have a try.
Please advice me to change explorer layout as dock right according to my requirements.
Kushan Randima.
Below is a citation from the manual - see section Accessing a Form Instance in the PDF file in the folder {Add-in Express}\Docs on your development PC.
It is essential that Add-in Express panes are built on the windowing of the host application, not on the events of the application's object model. This means that getting an instance of an Add-in Express pane in a certain event may result in getting null (Nothing in VB.NET) if the call is issued before the pane is shown or after it is hidden. For instance, it is often the case with WindowActivate/WindowDeactivate in Excel, Word, and PowerPoint.
...
So, you may encounter a problem if your add-in retrieves a pane instance in an event above. To bypass this problem, we suggest modifying the code of the add-in so that it gets notified about a pane instance being shown or hidden (instead of getting the pane instance by handling the events above). Use the ADXBeforeTaskPaneShow event of the task pane class (Excel, Word, and PowerPoint) and the ADXOlForm.ADXBeforeFormShow (Outlook) event to be notified about the specified pane instance being shown. When the form becomes hidden, you'll get ADXOlForm.ADXAfterFormHide (Outlook) and the ADXAfterTaskPaneHide event of the task pane class (Excel, Word, and PowerPoint).
That is, instead of getting a form instance in the AddinStartupcomplete event, you can handle the ADXOlForm.ADXBeforeFormShow event.
Hope this helps.
I have a CSharp (.NET) application that has created an add-in with a ribbon in Excel. I have buttons in the ribbon. I want to be able to click on the buttons, and open WPF windows.
The code looks like
private void OnNewButtonAction(object sender, RibbonControlEventArgs e)
{
var window = new View.MyWindow()
{
DataContext = new ViewModel.MyViewModel(),
};
window.Show();
}
Where MyWindow is a class of type System.Windows.Window. MyWindow has its own xaml file, which has radio buttons, text fields etc. When I try to run this - and click on the button, I get an XML parse exception as - "'Provide value on 'System.Windows.StaticResourceExtension' threw an exception".
Is it possible to invoke wpf windows from excel add-ins? What am I doing wrong?
Edit: I have already looked at
Using WPF Controls in Office Solutions and it doesn't work. And it adds a separate pane to excel, which is not what I am looking at.
You should use Excel-DNA. Its a really useful piece of software designed just for things like this, it helps to implement Excel with WPF, and you shouldn't have any problems again.
you can get it Here
If however you don't want that there is a step by step tutorial here on how to do it.
You may try to define a WPF window as a custom control and add it to the custom pane of the word. Have a look at the following link, pleases:
Using WPF Controls in Office Solutions
You may have a look at this link as well:
Office 2007 Excel Addin - WPF ComboBox Collapses when Expanded
The common way we add WPF control to custompane is:
Create an Excel add-in project
Add user control (WPF) name UserControl1 and add reference to System.xaml
Code the WPF control and Build the project successfully
Add User Control from Window Form collection, named the control as UserControl2
Drag and drop a UserControl1 to UserControl2, assign the position as you like
Code the ThisAddIn.cs in this way:
UserControl1 myWPF;
UserControl2 winformControl;
Microsoft.Office.Tools.CustomTaskPane pane;
System.Windows.Forms.Integration.ElementHost myHost;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
myWPF = new UserControl1();
winformControl = new UserControl2();
pane = CustomTaskPanes.Add(winformControl, "WPFControl");
pane.Visible = true;
pane.DockPosition = Office.MsoCTPDockPosition.msoCTPDockPositionRight;
}
We can use the button to control the pane's visible property.
Developing a Excel vsto project, how could I handle the Custom Task Pane in the Class which is a Ribbon Control.
For example, I would like to show the Custom Task Pane when I click the button of the Ribbon Control.
Dora
I assume you are working with an Excel VSTO add-in, with the Ribbon Visual Designer. You can achieve what you want by making your custom Task Pane accessible via a property on your Add-In:
public partial class ThisAddIn
{
private CustomTaskPane taskPane;
internal CustomTaskPane TaskPane
{
get
{
return this.taskPane;
}
}
... and adding a button in your Ribbon, and adding an event handler for the click event, accessing the add-in via Globals:
private void MyRibbonButton_Click(object sender, RibbonControlEventArgs e)
{
Globals.ThisAddIn.TaskPane.Visible = true;
}
I wrote a post a while back which describes the process, you may find it useful.
This is also feasible using the xml ribbon.
This can be accomplished by having a Win Forms user control.
I've worked on a project where we had to extend MS Word and needed this functionality, but the same example will apply to Excel.
Another interesting way I stumbled upon on the net is to have a Windows user control and host a WPF user control within the Windows control!
This ofcourse allows you to take advantage of all the awesome tools you get with WPF, here is an example:
1)Drop a ToggleButton on a Ribbon(Visual Designer).This will be used to show hide the task pane.
Using ToggleButton is a good choice as it appears highlighted when pressed down.
2)Add below code to the click event of the ToggleButton
Globals.ThisAddIn.TaskPane.Visible = ((RibbonToggleButton)sender).Checked;
3)Add a reference from your project to the following assembly - WindowsFormsIntegration
4)In your ThisAddIn.cs add the two using directives listed below:
using Microsoft.Office.Tools;
using System.Windows.Forms.Integration;
5)Add two user controls
5.1)User control (name - taskPaneControl1)
5.2)User control(WPF),(name - con)
Using the names I've used will help when copying/pasting the code below but by any means change it if you wish to
6)Add below code to the ThisAddIn.cs class
public CustomTaskPane TaskPane
{
get{return taskPaneValue;}
}
private TaskPaneControl taskPaneControl1;
private CustomTaskPane taskPaneValue;
private WpfControl con;
internal void AddTaskPane()
{
ElementHost host = new ElementHost();
con = new WpfControl();
host.Child = con;
host.Dock = DockStyle.Fill;
taskPaneControl1 = new TaskPaneControl();
taskPaneControl1.Controls.Add(host);
taskPaneValue = this.CustomTaskPanes.Add(taskPaneControl1, "My Taskpane");
taskPaneValue.Visible = true;
}
6)Add the two code below to the Startup event in your ThisAddIn.cs
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
AddTaskPane();
taskPaneValue.Visible = false;
}
When an MS Office Application is opened the task pane will be hidden toggle the Visible property to change this in the Startup event.
Navigate to the ToggleButton and press it a few times to make sure the task pane is showing as expected
Also have a look at the following link most of my code came from here - http://xamlcoder.com/cs/blogs/joe/archive/2007/07/17/using-wpf-with-vsto-office-2007.aspx
This is a difficult challenge since the Ribbon and Task Panes are separate entities. One of the main challenges is that there is only one instance of the Ribbon class and multiple instances of the task pane for each inspector. To this properly requires some advanced understanding of the Office internals.
The solution also depends on whether you are using the Ribbon XML or Ribbon Designer. Which approach are you using?
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