It seams I found part of the answer my self :)

Oh components, I am writing one of them since a week, too much, I know :) 

The last think that I was not able to solve is how to make the component discover where he is exactly during initialization, in other words, on what form is bean placed, and in which project.

I used a similar code in the components to discover the project in the solution that contains, the form, that the component is placed on it.
<b>

_DTE ixDTE = (_DTE)GetService(typeof(_DTE));
EnvDTE.Project ixProject = ixDTE.ActiveDocument.ProjectItem.ContainingProject;

</b>
The above code works fine in the custom controls or components, the only problem is that it is not giving me the right results when I use it in the component constructor initialization.

So, if I place a component on a form, and close and open the form again, the component initialization code will get triggered before the existing form becomes active, and the above code will bring back the previous form’s project, than can be another project in the same solution.


I will make my questions simpler

<b>The first one is:</b> is there is a simple way to get the existing form that the component is placed in during component initialization  and I mean by this is immediately after dragging the component and placing it on a form, or immediately after opening a saved form that have the component on it (during component initialization, from the component designer.)

<b>The second one:</b> is there is a simple way to have a configuration file during design time, inside the project in the solution, imaging I have a solution with 3 projects, I have a form in one of the projects, and I am dragging and dropping a component to the form, I need this component to access the configuration file for that particular project that contains the form, not the entire solution. (One configuration file for a project, shared)


Answer this question

It seams I found part of the answer my self :)

  • real green

    I am killing my self for a month trying to figure out how to do it, and it just was one line of code :) 

    I just try it and it does work, 

    Thanks man.



    public override void Initialize(IComponent ioComponent)
    {
    base.Initialize (ioComponent);
    try

    LxThemeManager.Initialize((EnvDTE.ProjectItem)GetService(typeof(EnvDTE.ProjectItem)), null);
    }
    catch(Exception ixException)
    {
    MessageBox.Show(ixException.Message, "Error !" ,MessageBoxButtons.OK
    ,MessageBoxIcon.Error);
    }


  • Amal Kamel

    A new piece of code that seams finally to be working


    internal static void Initialize(EnvDTE._DTE ixDTE, IDesignerHost ixHost, Assembly ioAssembly)
    {
    if(ixDTE != null)
    {
    if(!ixInitialized)
    {
    EnvDTE.Project ixProject = null;

    // Find where is the form that contains the control in the solution.
    foreach(EnvDTE.Document ixDocument in ixDTE.Documents)
    {
    if(ixDocument.ProjectItem.FileCodeModel != null)
    {
    foreach(EnvDTE.CodeElement ixCodeElement in ixDocument.ProjectItem.FileCodeModel.CodeElements)
    {
    EnvDTE.CodeClass ixCodeClass = ixCodeElement as EnvDTE.CodeClass;
    if(ixCodeClass != null)
    {
    if(ixCodeClass.Name == ixHost.RootComponentClassName)
    {
    ixProject = ixDocument.ProjectItem.ContainingProject;
    }
    }
    else
    {
    EnvDTE.CodeNamespace ixCodeNamespace = ixCodeElement as EnvDTE.CodeNamespace;
    if(ixCodeNamespace != null)
    {
    foreach(EnvDTE.CodeElement ixCodeElementN in ixCodeNamespace.Members)
    {
    EnvDTE.CodeClass ixCodeClassN = ixCodeElementN as EnvDTE.CodeClass;
    if(ixCodeClassN != null)
    {
    if(ixCodeClassN.Name == ixHost.RootComponentClassName)
    {
    ixProject = ixDocument.ProjectItem.ContainingProject;
    }
    }
    }
    }
    }
    }
    }
    }

    // Creating the shared themes file, or loading it if it does exist.
    if(ixProject != null)
    {
    ............................. 
    }
    }
    }
    }



    and in the component designer



    public override void Initialize(IComponent ioComponent)
    {
    base.Initialize (ioComponent);
    try
    {
    LxThemeManager.Initialize(((_DTE) ioComponent.Site.GetService(typeof(_DTE)))
    ,(IDesignerHost) ioComponent.Site.GetService(typeof(IDesignerHost))
    , null);
    }
    catch(Exception ixException)
    {
    MessageBox.Show(ixException.Message, "Error !" ,MessageBoxButtons.OK
    ,MessageBoxIcon.Error);
    }




    I will publish the entire code as part of the second part of the SmartLibrary (0.2) on my web site soon.

  • Kaktusbluete

    ooooooo...nice!
  • RPaulo

    Actually, there is a short cut to getting the current project item:

    DTE.ProjectItem item = (DTE.ProjectItem)GetService(typeof(DTE.ProjectItem));

    The code parser adds this service at boot up so you can get at it easily.  We chose this because from ProjectItem you can navigate back up the rest of the hierarchy if you want.

  • ika

    hrmm..Interesting... What about something like the following:

    1-  Through DTE, get the ActiveDocument.
    2-  Access the ProjectItem Property of the ActiveDocument.
    3-  Access the FileNames Property of the ProjectItem.

    If your component is currently on a form, then those steps should return YourForm.vb and YourForm.resx ...  Just a stab in the dark, but it may just workout...

    If, on the other hand, you are trying to access the Config File (as you mentioned in your original post), then once you acquire the ProjectItem you need, you should be able to retrieve what you need through the ConfigurationManager property...

    Hope this is helpful.

  • BSHOE

    a new discovery  :)  

    Form ixForm = (Form) ixHost.RootComponent;

  • Skizznott

    Maybe some of this will help. In a designer, you can get IDesignerHost (the host) by calling GetService(typeof(IDesignerHost)). Once you have that you can do most anything. You can get the DTE the same way. Below is some code, given the host, finds the root component associated with it, then changes some code in its class file.

    internal class CodeInjector
    {
        public static void InsertCode(DTE dte, IDesignerHost host, string code)
        {
            Document ourDoc = FindOurDocument(dte, host);
            //            OpenCodeDoc(dte, ourDoc);    // may not be necessary
            // find our class
            string className = host.RootComponentClassName;
            FileCodeModel cm = ourDoc.ProjectItem.FileCodeModel;
            CodeClass cc = null;
            foreach (CodeElement ce in cm.CodeElements)
            {
                cc = FindClass(ce, className);
                if (cc != null)
                    break;
            }
            if (cc != null)
            {
                // first create codedom
                CodeCommentStatement comment = new CodeCommentStatement(code);
                // cannot generate code from a method -- have to use a type, or
                // hope the method is already there
                //                CodeMemberMethod method = new CodeMemberMethod();
                //                method.Name = "test";
                //                method.Comments.Add(comment);

                // generate a string from the codedom
                CodeDomProvider provider;
                if (ourDoc.Language == "CSharp")
                    provider = new Microsoft.CSharp.CSharpCodeProvider();
                    // TODO: need to test this -- don't know which string to use
                else if (ourDoc.Language == "VB")
                    provider = new Microsoft.VisualBasic.VBCodeProvider();
                else
                    return;
                ICodeGenerator generator = provider.CreateGenerator();
                StringBuilder sb = new StringBuilder();
                TextWriter writer = new IndentedTextWriter(new StringWriter(sb));
                generator.GenerateCodeFromStatement(comment, writer, null);
                writer.Flush();
                
                // if the method already exists, delete body
                EditPoint start = null;
                foreach (CodeElement ce in cc.Members)
                {
                    CodeFunction cf = ce as CodeFunction;
                    if (cf != null && cf.Name == "test")
                    {
                        start  = cf.StartPoint.CreateEditPoint();
                        start.LineDown(2);
                        start.StartOfLine();
                        EditPoint end  = cf.EndPoint.CreateEditPoint();
                        end.LineUp(1);
                        end.EndOfLine();
                        start.Delete(end);
                        break;
                    }
                }

                if (start == null)
                {
                    if (ourDoc.Language == "CSharp")
                    {
                        CodeFunction cf = cc.AddFunction("test", vsCMFunction.vsCMFunctionFunction,
                            vsCMTypeRef.vsCMTypeRefInt, -1, vsCMAccess.vsCMAccessPrivate, null);
                        start = cf.StartPoint.CreateEditPoint();
                        start.LineDown(2);
                        start.StartOfLine();
                    }
                    else
                    {
                        // TODO: here error message
                    }
                }

                // insert the string into the function
                start.Insert(sb.ToString());
            }
        }

        private static CodeClass FindClass(CodeElement root, string className)
        {
            CodeClass cc = root as CodeClass;
            if (cc != null)
            {
                if (cc.FullName == className)
                    return cc;
                foreach (CodeElement ce in cc.Members)
                {
                    if (ce is EnvDTE.CodeNamespace || ce is CodeClass)
                    {
                        cc = FindClass(ce, className);
                        if (cc != null)
                            return cc;
                    }
                }
            }
            else
            {
                EnvDTE.CodeNamespace cn = root as EnvDTE.CodeNamespace;
                if (cn != null)
                {
                    foreach (CodeElement ce in cn.Members)
                    {
                        if (ce is EnvDTE.CodeNamespace || ce is CodeClass)
                        {
                            cc = FindClass(ce, className);
                            if (cc != null)
                                return cc;
                        }
                    }
                }
            }
            return null;
        }

        private static Document FindOurDocument(DTE dte, IDesignerHost host)
        {
            foreach (Document doc in dte.Documents)
            {
                if (doc.Kind != Constants.vsDocumentKindText)
                    continue;
                foreach (Window window in doc.Windows)
                {
                    IDesignerHost windowHost = window.Object as IDesignerHost;
                    if (windowHost != null && windowHost == host)
                        return doc;
                }
            }
            return null;
        }

        private static void OpenCodeDoc(DTE dte, Document document)
        {
            bool codeOpen = dte.get_IsOpenFile(Constants.vsViewKindCode, document.FullName);
            if (!codeOpen)
            {
                ItemOperations ItemOp = dte.ItemOperations;
                ItemOp.OpenFile(document.FullName, Constants.vsViewKindCode);
            }
        }    
    }

  • drdexter33

    It seams I found part of the answer my self :) 

    To find the name of the form that the component is placed on during initialization from the component designer, you can use this code:


    internal class LTGlobalDesigner : IDesigner
    {
    …………………. Code

    public void Initialize(System.ComponentModel.IComponent component)
    {
    this.component = component;
    IDesignerHost ixHost = (IDesignerHost)this.component.Site.GetService(typeof(IDesignerHost));
    IContainer ixContainer = ixHost.Container;
    Form ixForm = (Form) ixContainer.Components[0];
    MessageBox.Show(ixForm.Name); // just for verification
    }

    ……………… code
    }



  • dholt

    The problem with the Active Document is that it can't be used during component initialization (from the component designer) when the form is getting opened, it is still not the active document, the active documents is null or the previous opened document that maybe is in another project.
  • f_scholer

    Now the question is how can I use DTE to obtain the file name that the form is saved in (using the form name)  I’ve spend 5 hours trying to do that and no results yet  :( 
  • Marc68

    i just discovered that a couple days ago and I'm curious if the first component is always going to be the Container.  As I mentioned over <a href="http://www.windowsforms.net/Forums/ShowPost.aspx tabIndex=1&tabId=41&PostID=2689">here</a>, it seems sorta hoaky to me!  :P 
  • audreynsarah

    Yeah, I was afraid that might be the case...  So, just to restate the ultimate goal here:  Given a Type, you would like to acquire the name of the file in which that type is defined   I wonder if reflection might work...

  • AndyPowell

    One thousand thanks  :) 

    That last piece of code has just solved my one of the biggest initialization problems; I finally know when the control is getting initialized at design time


    Unfortunately I still have many other problems writing the themed controls, but at least I am one step ahead now.


    Because of your code I was finally able to load the themes properly to a static buffer at design time.


        internal static void Initialize(EnvDTE._DTE ixDTE, IDesignerHost ixHost)
        {
          ixInitialized = true;
          if(ixDTE != null)
          {
            
            EnvDTE.Project ixProject = null;
            
            foreach(EnvDTE.Document ixDocument in ixDTE.Documents)
            {
              foreach (EnvDTE.Window ixWindow in ixDocument.Windows)
              {
                IDesignerHost ixWindowHost = ixWindow.Object as IDesignerHost;
                if (ixWindowHost != null && ixWindowHost == ixHost)
                {
                  ixProject = ixDocument.ProjectItem.ContainingProject;
                }
              }
            }

            if(ixProject != null)
            { 
              string ixFilePath = ixProject.Properties.Item("FullPath").Value.ToString() + "SmartLibrary Themes.resx";
              ResXResourceWriter ixThemeFile = new ResXResourceWriter(ixFilePath);
              
              ixThemeFile.AddResource("File Version", "SmartLibrary 0.2 Theme File");
              ixThemeFile.AddResource("Themes List", ixThemeStoreCollection);
              
              ixThemeFile.Generate();
              ixThemeFile.Close();   

              ixProject.ProjectItems.AddFromFile(ixFilePath);
              ixProject.ProjectItems.Item("SmartLibrary Themes.resx").Properties.Item("BuildAction").Value = 3;
            }
          }
          else
          {
            MessageBox.Show("Runtime");
          }
        }



    By calling the code from the control at design time:

    public override ISite Site
    {
    get
    {
    return base.Site;
    }
    set
    {
    base.Site = value;
    LxThemeManager.Initialize(((_DTE)value.GetService(typeof(_DTE))),
    (IDesignerHost) value.GetService(typeof(IDesignerHost)) );
    }
    }



    Of course the my code is still not completed yet and have some bugs, but the idea works

  • _Igor

    Just found a new problem in that code, it does not work with all computers, when debugging it I discovered that some times the document that contains the control, still does not have a window created (depending on the computer speed), and this means the code will fail.

    I have it working on some computers and not working on other, or working sometimes on the same computer and sometimes not.

    Is it that complicated Microsoft  Millions of lines of documentation, and there is no single line explaining how for sure to get the existing EnvDTE.Projectitem that the form or component is stored in.

    All what I want is: when the component gets initialized (in the designer), I need the EnvDTE.ProjectItem that the component is stored in it!

  • It seams I found part of the answer my self :)