none
How Do You Create Microsoft.Office.Tools.Word ContentControlEntering Event handler RRS feed

  • Question

  • HI

    I am new to C# and still getting my head around delegates and Event handlers.

    I have implemented some code based on this;

    https://msdn.microsoft.com/en-us/library/cc442765.aspx

    I have content controls that are part of building blocks. These are added to the word template and then user can choose building blocks from a gallery control. I want to trap the On Entering Event. My understanding is that once I run the project the content controls are added as Native / Microsoft.Office.Interop.Word contentcontrols. I have added code to loop through all the controls and convert them to extended/host/Microsoft.Office.Tools.Word content controls.

    I had hoped that this would allow me to capture the On Enter Event:

    this.ContentControlOnEnter += new Microsoft.Office.Interop.Word.DocumentEvents2_ContentControlOnEnterEventHandler(this.ThisDocument_ContentControlOnEnter);

    how ever I think that I have to use the Microsoft.Office.Tools.Word ContentControlEntering Event handler.

    But I have no idea how to add this to the internal start up code block. Please can someone help - there are no examples online - I appreciate this is a complete noob request.

    https://msdn.microsoft.com/en-us/library/microsoft.office.tools.word.contentcontrolenteringeventhandler.aspx

            public void ExtendContentControls()
            {
                if (this.ContentControls.Count <= 0)
                    return;
    
                RDB.BusinessLayer.ReasearchObjects oReasearch = new RDB.BusinessLayer.ReasearchObjects();
                DataSet ds = oReasearch.ContenControlDS;
                DataTable dt = ds.Tables[0];
                var query = from CC in dt.AsEnumerable()
                            select new
                            {
                                CCID = CC.Field<long>("uniqCCGuid"),
                                Type = CC.Field<string>("chrvnContentControlType"),
                                Tag = CC.Field<string>("chrvnContentControlTag")
                            };
    
                 foreach(var q in query)
                {
                    Word.ContentControl NativeControl = FetcHContentControlFromId(q.CCID.ToString());
                    switch (q.Type)
                    {
                        case "wdContentControlRichText":
                            Microsoft.Office.Tools.Word.RichTextContentControl temprtC = this.Controls.AddRichTextContentControl(NativeControl, q.Tag+ q.CCID.ToString());
                            temprtC.Tag = "_" + q.Tag;
                            break;
                        case "wdContentControlPicture":
                            Microsoft.Office.Tools.Word.PictureContentControl tempimgC = this.Controls.AddPictureContentControl(NativeControl, q.Tag + q.CCID.ToString());
                            tempimgC.Tag = "_" + q.Tag;
                            break;
                        case "wdContentControlComboBox":
                            Microsoft.Office.Tools.Word.ComboBoxContentControl tempcbxC = this.Controls.AddComboBoxContentControl(NativeControl, q.Tag + q.CCID.ToString());
                            tempcbxC.Tag = "_" + q.Tag;
                            break;                  
                    }
                }
                    Document hostDoc = Globals.Factory.GetVstoObject(Application.ActiveDocument);
                    ListCCEntries(hostDoc.ContentControls);
    
    
            }

    Monday, March 6, 2017 3:50 PM

Answers

  • Hi Edward,

    In the template document the code did not work. I tried running the Extended control code before and after your code to see if that would work but it did not. However I noticed you had supplied code for an Addin vs my template customization and running the below did work -  published the template and then I opened it with the Add in. if I run the template on its own - i,e with your code when published I get nothing. 

    I don't know why the events wont trigger in the document. But at least there is some work around.

    Thank you

    George

                    Vsto.Document vstoDoc = Globals.Factory.GetVstoObject(Application.Documents.Add(@"M:\word\VS\ResearchTemplate.dotm"));
                    vstoDoc.ContentControlOnEnter += (s) =>{ MessageBox.Show("Clicked"); };
                    return vstoDoc;

    Wednesday, March 8, 2017 2:01 PM

All replies

  • Hi

    I have just started coding in C# and I am looking to write some smart documents in word. I have created a template that has a set of tables, each table hosting content controls. The code then adds these tables as custom buildingblocks. The user can double click on the document and the select which building blocks he or she adds to the template. 

    Below is my code (simplified). When I run the ThisDocument_Startup what happens is I loop through the tables in the doc add them to buildinglocks collection. I then delete all but 2 of the tables. The user can then add a building block Gallery and choose additional building blocks as they please.

    I have only included the table deletion code as the ContentControlsOnEnterEvent stops working when this is run. I suspect that it has something to do with this line   Word.Template tmpltReasearch = this.AttachedTemplate as Word.Template; 

    I have seen that there are issues with the namespace the event is used in - but I do not fully understand the issue. http://stackoverflow.com/questions/36896184/vsto-winword-bind-to-entering-event-for-dropdownlistcontentcontrol

    https://social.msdn.microsoft.com/Forums/vstudio/en-US/42125cc3-b878-4fb6-b825-da4bce80ee31/contentcontrolonenter-does-not-trigger?forum=vsto @CindyMeister

    https://social.msdn.microsoft.com/Forums/office/en-US/aa30a7db-8c47-4851-8459-ffeb2ec784b0/content-control-event-handlers-does-not-trigger-when-document-opened-from-sharepoint?forum=worddev @CelesteLi

    It looks like ContentControls are tricky to implement in some aspects, however they are pretty useful for collecting data and I can query /manipulate easily with Linq. @EricWhite .  I have managed to recreate the issue starting afresh - the original template was dotm and I had copied and remanded a number of the word tables and content controls. In the new dotx solution I built each table from afresh and added the content controls individually.

    I would like the OnEnter Event so that I can then fire off different methods depending on which Content control is selected - e.g Open file Dialogue browser to capture filepath, import an image or populate with dynamic content from database.

    I have tried adding the OnEnterEvent at the individual content control level. In this case the OnExit Event fires but the on Enter remains silent.

    I would be grateful for any and all suggestions as the OnEnterEvent is pretty essential to my planned solution.  

    I am using VS 2015, Word 2016

    Thanks in advance

    George



    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.Xml.Linq;
    using Microsoft.Office.Tools.Word;
    using Microsoft.VisualStudio.Tools.Applications.Runtime;
    using Office = Microsoft.Office.Core;
    using Word = Microsoft.Office.Interop.Word;
    using System.IO;
    using System.Data.Sql;
    using System.Data.SqlClient;
    using RDB.DataLayer;
    
    namespace ResearchTemplate2
    {
        public partial class ThisDocument
        {
            public Dictionary<string, int> dicBuildingBlocks = new Dictionary<string, int>();
            public static string strBBGalleryID;
            public static int iBBGalleryCount = 0;
            public static bool blGalleryExits = true;
            public static int iTableCount = 2;
    
            private void ThisDocument_Startup(object sender, System.EventArgs e)
            {
                //add the tables to Building Block Collection, for each building block we specify which document type it is assciated with and its name
                // Document types are Update, Initiation and New Issue
                Word.Template tmpltReasearch = this.AttachedTemplate as Word.Template;
    
                //if (tmpltReasearch != null)
                //{
                //    AddBuildingBlockEntries(tmpltReasearch);
                //}
    
                if (!this.FormsDesign)
                {
                    this.ToggleFormsDesign();
                }
    
                foreach (Word.Table tbl in this.Tables)
                {
                    string strTestVal = tbl.Title;
                    if (strTestVal == "tblDocSetting")
                    {
                        dicBuildingBlocks.Add("tblDocSetting", 1);
                    }
                    else
                        if (strTestVal == "tblRecommendation")
                    {
                        dicBuildingBlocks.Add("tblRecommendation", 2);
                    }
                    else
                        tbl.Delete();
                }
    
                this.ToggleFormsDesign();
    
      
        } 
    
            private void ThisDocument_Shutdown(object sender, System.EventArgs e)
            {
            }
    
            private void ThisDocument_ContentControlOnEnter(Word.ContentControl CC)
            {
                MessageBox.Show("Working");
            }
            #region VSTO Designer 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(ThisDocument_Startup);
                this.Shutdown += new System.EventHandler(ThisDocument_Shutdown);
                this.ContentControlOnEnter += new Microsoft.Office.Interop.Word.DocumentEvents2_ContentControlOnEnterEventHandler(ThisDocument_ContentControlOnEnter); 
            }
    
            #endregion
                //public void AddBuildingBlockEntries(Word.Template template)
                //{
                //    string strName;
                //    string strCategory;
                //    string strDescription;
                //    int iTablePos;
    
                //    try
                //    {
                //        RDB.DataLayer.ResearchDatabase ReasearchDatabase = new RDB.DataLayer.ResearchDatabase(@"PC1-PC", "MKT_DATA");
                //        DataSet ds = ReasearchDatabase.FillDataSet(@"SELECT * FROM [MKT_DATA].[dbo].[tblTableType]");
                //        DataTable dt = ds.Tables[0];
    
                //        foreach (DataRow dr in dt.AsEnumerable())
                //        {
    
                //            strName = dr.Field<string>("chrvnBuildingBlockName");
                //            strCategory = dr.Field<string>("chrvnBuildBlockCategory");
                //            strDescription = dr.Field<string>("chrvnTableDescription");
                //            iTablePos = dr.Field<int>("intTableTemplateIndex");
                //            if (dr.Field<string>("chrvnBuildingBlockType") == "Custom 2")
                //            {
                //                template.BuildingBlockEntries.Add(strName,
                //                Word.WdBuildingBlockTypes.wdTypeCustom2, strCategory, this.Tables[iTablePos].Range, strDescription,
                //                Word.WdDocPartInsertOptions.wdInsertContent);
                //            }
                //            else
                //            {
                //                template.BuildingBlockEntries.Add(strName,
                //                Word.WdBuildingBlockTypes.wdTypeCustom1, strCategory, this.Tables[iTablePos].Range, strDescription,
                //                Word.WdDocPartInsertOptions.wdInsertContent);
                //            }
                //        }
                //    }
                //    catch (Exception Ex)
                //    {
                //        MessageBox.Show(Ex.ToString());
                //    }
    
                //}
    
        }
    }



    Sunday, March 5, 2017 3:24 PM
  • Hi TheGr8Destructo,

    According your describtion,i think what you want is binding functions with content controls individually,right?

    I find the control's tag property could be a workarounds for this.

    You could set the control's tag property before you insert it into the document.

    Here is the example

    private Microsoft.Office.Tools.Word.RichTextContentControl richTextControl1;
            private void AddRichTextControlAtRange()
            {
                this.Paragraphs[1].Range.InsertParagraphBefore();
                this.Paragraphs[1].Range.Select();
                richTextControl1 = this.Controls.AddRichTextContentControl("richTextControl1");
                richTextControl1.PlaceholderText = "Control";
                richTextControl1.Tag = "rich1";
                this.ContentControls.Add(Word.WdContentControlType.wdContentControlRichText);
            }

    Then you could binding function depending on the tag.

    private void ThisDocument_ContentControlOnEnter(Word.ContentControl CC)
            {
                if (CC.Tag == "rich1") {
                    //what you want to do
                }
            }

    Hope that can help you.

    Best regards,

    Terry

    Tuesday, March 7, 2017 8:30 AM
  • Hi Terry,

    Thanks for looking at this with me. The issue I am having is that the OnEnter Event of the content controls is not firing. Once I can get this working then I will employ a solution as you suggest, but the real issue is that any native OnEnter or extended OnEntering event are currently silent. 

    I have been reading around the issue and it appears that whilst ContentControls are of an Extended type (Microsoft.Office.Tools.Word) when the project runs they are treated as Native (Microsoft.Office.Interop.Word) . This then appears to interfere with the event handler (ThisDocument_ContentControlOnEnter - which is native).

    This Microsoft link covers the need to persist extended controls: https://msdn.microsoft.com/en-us/library/cc442765.aspx

    Having looked at that I have then written a loop that aims to convert Native controls to Extended. I then attach the Extended "entering" Event to the extended control.

    The code runs - but I am still left with content controls that do not trigger on the  Extended "Entering" Event.

    I do not know whether it is because I am running the Native to Extended conversion in the wrong part of the project - "thisDocument_Startup", or if I have incorrectly hooked up the controls to the events. I have manually gone into the template found a rich text box and hooked it up to the Extended "Entering" event but no joy.

    Thanks for taking the time to help me,

    George

    public void ExtendContentControls()
            {
                if (this.ContentControls.Count <= 0)
                    return;
    
                RDB.BusinessLayer.ReasearchObjects oReasearch = new RDB.BusinessLayer.ReasearchObjects();
                DataSet ds = oReasearch.ContenControlDS;
                DataTable dt = ds.Tables[0];
                var query = from CC in dt.AsEnumerable()
                            select new
                            {
                                CCID = CC.Field<long>("uniqCCGuid"),
                                Type = CC.Field<string>("chrvnContentControlType"),
                                Tag = CC.Field<string>("chrvnContentControlTag")
                            };
    
                foreach (var q in query)
                {
                    Word.ContentControl NativeControl = FetcHContentControlFromId(q.CCID.ToString());
                    switch (q.Type)
                    {
                        case "wdContentControlRichText":
                            Microsoft.Office.Tools.Word.RichTextContentControl temprtC = this.Controls.AddRichTextContentControl(NativeControl, q.Tag + q.CCID.ToString());
                            temprtC.Entering += TemprtC_Entering;
                            break;
                        case "wdContentControlPicture":
                            Microsoft.Office.Tools.Word.PictureContentControl tempimgC = this.Controls.AddPictureContentControl(NativeControl, q.Tag + q.CCID.ToString());
                            tempimgC.Entering += TempimgC_Entering;
                            break;
                        case "wdContentControlComboBox":
                            Microsoft.Office.Tools.Word.ComboBoxContentControl tempcbxC = this.Controls.AddComboBoxContentControl(NativeControl, q.Tag + q.CCID.ToString());
                            tempcbxC.Entering += TempcbxC_Entering;
                            break;
                    }
                }
                Document hostDoc = Globals.Factory.GetVstoObject(Application.ActiveDocument);
                ListCCEntries(hostDoc.ContentControls);
    
    
            }
    
            private void TempcbxC_Entering(object sender, ContentControlEnteringEventArgs e)
            {
                MessageBox.Show("TaDaaa");
            }
    
            private void TempimgC_Entering(object sender, ContentControlEnteringEventArgs e)
            {
                MessageBox.Show("TaDaaa");
            }
    
            private void TemprtC_Entering(object sender, ContentControlEnteringEventArgs e)
            {
                MessageBox.Show("TaDaaa");
            }
    
        }
    


    Tuesday, March 7, 2017 9:47 AM
  • Hi,

    For adding ContentControlOnEnter event, I suggest you try something like below:

    namespace WordDocumentAddIn
    {
        public partial class ThisDocument
        {
            private void ThisDocument_Startup(object sender, System.EventArgs e)
            {
                this.ContentControlOnEnter += ThisDocument_ContentControlOnEnter;
            }
    
            private void ThisDocument_ContentControlOnEnter(Word.ContentControl ContentControl)
            {
                MessageBox.Show("On Enter");
            }
    
            private void ThisDocument_Shutdown(object sender, System.EventArgs e)
            {
            }
    
            #region VSTO Designer 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(ThisDocument_Startup);
                this.Shutdown += new System.EventHandler(ThisDocument_Shutdown);
            }
    
            #endregion
        }
    }
    

    If it did not work for you, it would be helpful if you could share us how you tried and where it did not work.

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Wednesday, March 8, 2017 3:15 AM
  • Hi Edward,

    In the template document the code did not work. I tried running the Extended control code before and after your code to see if that would work but it did not. However I noticed you had supplied code for an Addin vs my template customization and running the below did work -  published the template and then I opened it with the Add in. if I run the template on its own - i,e with your code when published I get nothing. 

    I don't know why the events wont trigger in the document. But at least there is some work around.

    Thank you

    George

                    Vsto.Document vstoDoc = Globals.Factory.GetVstoObject(Application.Documents.Add(@"M:\word\VS\ResearchTemplate.dotm"));
                    vstoDoc.ContentControlOnEnter += (s) =>{ MessageBox.Show("Clicked"); };
                    return vstoDoc;

    Wednesday, March 8, 2017 2:01 PM
  • Hi George,

    I am glad you have found a workaround, and I would suggest you mark your reply as answer, and then others who run into the same issue would find the solution easily.

    Best Regards,

    Edward


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, March 10, 2017 8:31 AM