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.
Related
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.
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?
I created a user control and it shows up on the tool box as form components. Then when I try to drag and drop the user control on to a form , I get this visual studio error.
" The specified named connection is either not found in the configuration ,not intended to be used with the entity client provider or not valid."
Why am I getting this error?
But some other user controls I can drag and drop which are under the same project. I don't know what I missed in creating this user control.
Beware that code in the UserControl class runs at design time. The constructor, the OnLoad method and Load event. But also methods like OnPaint(). If this code does anything that depends on the environment being setup properly, that code is liable to throw an exception and cause the designer to change its mind about adding the control to the form. That certainly seems to be the case when you get a "not found in the configuration" error, there is no configuration file yet.
Use the DesignMode properly to skip such code. Like this:
protected override void OnLoad(EventArgs e) {
if (!this.DesignMode) {
// Do stuff...
}
base.OnLoad(e);
}
As Hans says, you might need to use the DesignMode property in the Constructor or OnLoad. Also, make sure any public properties that use the connection have this attribute:
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public string Foo
{
get;
set;
}
That way, the designer won't attempt to set them when you add the control to a form. This is always a good habit to get into anyway for properties that you won't be setting at design time.
this error show if you put the code of loading data from database into the constructor of userControl.
"loading data or initialize entity framework"
so the solution is to move the code of loading data from constructor to a method. you can call it "loadData".
and call this method "loadData" in the constructor of the parent form
I created a user control using C# for windows form application. This user control has some properties. In runtime, if the user does not enter values for this properties I want to show a message box and exit the application.
The problem is when I write the checking code in the Load event of User Control. When I drag & drop it on the form the message box will appear.
private void UserControl1_Load(Object sender, EventArgs e)
{
if (_getFirstPageArgument==null || _getFirstPageArgument.Length==0)
{
throw new Exception("Some Message");
}
}
How do I distinguish between load on the form and load on run time?
I fear there is a larger problem here. But to solve your immediate problem (if I understand correctly...) There is a form attribute called DesignMode. When you are in the visual studio design mode, this will be true. At runtime, this will be false.
For beginners, #Nimas case can be a good study point to understand that Visual Studio actually runs and executes parts of our code even when we are in design time, which is why the constructor is invoked. Even "DesignMode" property is not 100% reliable. You can find an interesting note here related to that http://weblogs.asp.net/fmarguerie/archive/2005/03/23/395658.aspx
If you only want to know when the type itself has been loaded into the runtime (not a specific instance), you can put code into the static constructor for that class.
If I'm misinterpreting your question, please clarify using a timeline when you want specific events to happen.
I'm writing a shared addin for Excel. It adds a CommandBarButton that when clicked opens a WPF window to collect some information from the user.
I wanted to keep the same WPF dialog in memory and reuse it so that if the user clicks the CommandBarButton again their previous values would still be there.
So I made a reference to my WPF dialog as a private member of my addin object that implements Extensibility.IDTExtensibility2.
I created the window during OnStartupComplete(), but for some reason when I run Excel the window immediately opens even though I never called ShowDialog() and when I do call ShowDialog() when the CommandBarButton is clicked to reopen the window it fails to load.
Does anyone know why this happens and what the correct way to handle this is?
Thanks very much for any help.
CODE UPDATE:
public void OnStartupComplete(ref System.Array custom)
{
MyDialog dlg = new MyDlg(); //This will open the dialog ?!?!
}
....
public MyDialog()
{
InitializeComponent();
Loaded += new RoutedEventHandler(OnLoaded);
}
OnLoaded just wires up some event handlers for buttons and sets some ItemSources. Even if I comment it out it still open the window.
I have picked up on the fact that once a WPF window is closed it can't be reoped and this is by design. But why it opens automatically when constructed inside an excel addin is a mystery.
I've been able to reproduce your problem. In the WPF designer, make sure that the form's Visbility property is set to Collapsed. If you have it as Visible, it will automatically show when the dialog is created.