Search code examples
c#outlookuser-controlsvstocustomtaskpane

System.InvalidCastException while adding User control to CustomTaskPane


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;
                }));
            });
        }

Solution

  • 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).