I am trying to add a User control
on Microsoft.Office.Tools.CustomTaskPane myCustomTaskPane
by using following line:
myUserControl = new IssueAddition(categoryList);
myCustomTaskPane = this.CustomTaskPanes.Add(myUserControl, "Issue Reporting Pane"); --> errornous line
myCustomTaskPane.Visible = true;
I am getting the below exception:
An exception of type 'System.InvalidCastException' occurred in Microsoft.Office.Tools.Common.Implementation.dll but was not handled in user code
Additional information:
Unable to cast COM object of type 'System.__ComObject' to interface type 'Microsoft.VisualStudio.Tools.Office.Runtime.Interop.ICustomTaskPaneSite'.
This operation failed because the QueryInterface call on the COM component for the interface with IID '{3CA8CD11-274A-41B6-A999-28562DAB3AA2}' failed due to the following error: No such interface supported (Exception from HRESULT: 0x80004002 (E_NOINTERFACE)).
I am unsure about what could be the cause for System.InvalidCastException
exception.
Edit 1: Adding the code of the latest implmentation which is also giving the same error:
I have a separate class,IssueAddition
inheriting System.Windows.Forms.UserControl
class like below:
public partial class IssueAddition : UserControl
{
public IssueAddition()
{
InitializeComponent();
}
public IssueAddition(List<String> categories)
{
InitializeComponent();
foreach (string cat in categories)
this.i_issue_category.Items.Add(cat);
}
public string IssueCategoryInputText
{
get { return (string)this.i_issue_category.SelectedItem; }
set { this.i_issue_category.SelectedItem =
this.i_issue_category.FindStringExact(value); }
}
public string MessageInputText
{
get { return this.i_error_message.Text; }
set { this.i_error_message.Text = value; }
}
}
And it's being used in ThisAddIn.cs
like below:
Declaration:
#region Instance Variables
Outlook.Application m_Application;
internal static List<Outlook.Explorer> m_Windows; // List of tracked explorer windows.
internal static List<Outlook.Inspector> m_InspectorWindows;// List of traced inspector windows.
private IssueAddition myUserControl; <--
Usage:
public async void AddIssue()
{
List<String> categoryList = new List<String>();
await Task.Run(() =>
{
categoryList = dAO.loadCategoryAsync("all").GetAwaiter().GetResult();
if (categoryList == null)
categoryList = new List<String>();
myUserControl = new IssueAddition(categoryList);
Add add = new Add(MyCustomControlAdd);
Globals.ThisAddIn.myUserControl.Invoke(add);
});
}
delegate void Add();
private void MyCustomControlAdd()
{
Globals.ThisAddIn.CustomTaskPanes.Add(myUserControl, "test").Visible = true;
}
Edit 2: I also tried Invoke
method on but it also throws same exception. I am unable to understand how to overcome this problem.
public async void AddIssue()
{
List<String> categoryList = new List<String>();
await Task.Run(() =>
{
categoryList =
dAO.loadCategoryAsync("all").GetAwaiter().GetResult();
if (categoryList == null)
categoryList = new List<String>();
myUserControl = new IssueAddition(categoryList);
if (!Dispatcher.CurrentDispatcher.CheckAccess())
Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
{
Globals.ThisAddIn.CustomTaskPanes.Add(myUserControl, "test").Visible = true;
}));
else
Dispatcher.CurrentDispatcher.Invoke(new Action(() =>
{
Globals.ThisAddIn.CustomTaskPanes.Add(myUserControl, "test").Visible = true;
}));
});
}
Edit 3: Adding the code changes to make it work as suggested by the accepted answer:
Add Dispatcher _dispatcher;
instance variable in ThisAddIn.cs
.
Intialise it in ThisAddIn_Startup
function:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
_dispatcher = Dispatcher.CurrentDispatcher;
}
Usage:
public async void AddIssue()
{
List<String> categoryList = new List<String>();
await Task.Run(() =>
{
categoryList = dAO.loadCategoryAsync("all").GetAwaiter().GetResult();
if (categoryList == null)
categoryList = new List<String>();
myUserControl = new IssueAddition(categoryList);
_dispatcher.Invoke(new Action(() =>
{
Globals.ThisAddIn.CustomTaskPanes.Add(myUserControl, "test").Visible = true;
}));
});
}
Most likely you are calling that code on a secondary thread.
If you absolutely must do so from a secondary thread, use Dispatcher.Invoke
(where Dispatcher
object is retrieved from Dispatcher.CurrentDispatcher
on the main thread).