Link to home
Start Free TrialLog in
Avatar of exptech
exptechFlag for United States of America

asked on

Z-Order problem with usercontrols

Ok, here is my problem. It would seem like there is a simple solution but so far it has eluded me. I have a usercontrol which consists of a Developers Express (using their components) group box which is docked to all sides so it always fills the usercontrol. Inside of the groupbox there are a few buttons and a DE memoedit control docked to the bottom of the groupbox. I don't think the contents of the group box make a difference anyway. I am able to drag the control onto a form with no trouble, but I wanted to be able to place other controls inside the usercontrol at design time so I added the following above the usercontrol class definition:

[Designer(typeof(ParentControlDesigner))]

This now allowed me to place other controls into my usercontrol at design time. When I move the usercontrol the controls move with it and they are clearly inside the usercontrol when you look at the document outline window, but here is the problem. When you place any control on the usercontrol it's z-order puts it behind the contents already in the usercontrol (the DE Group Box). If you select it in the document outline and then click on a handle and select move to front, the control places itself on top of everything else and all is well. That is until you save and reopen the form. When you reopen the form all of the controls you placed are once again behind the usercontrol contents. You would think when you saved the form the z-order would be saved but it does not work. The problem is there are going to be many of these usercontrols with a good deal of controls placed on top. Going from control to control and correcting them is not an option. I have even tried implementing a custom designer for a textbox control that I modified and is now a usercontrol. Here is the code:

            public override void InitializeNewComponent(System.Collections.IDictionary defaultValues)
            {
                base.InitializeNewComponent(defaultValues);

                ILTextEdit ilTextEdit = (ILTextEdit) Component;

                ilTextEdit.BringToFront();
            }

Hopefully this is the right way to access the component itself, I have very little experience with designers or the programming the visual studio IDE, though I have a decent amount of experience with C# applications. In any event when I drag this component unto the usercontrol now it is the top most control and it looks like the
problem is solved. Again, that is until you save the form and reopen it, just to find out the control is once again hidden.

Anyone have any idea how to correct this?
ASKER CERTIFIED SOLUTION
Avatar of Bob Learned
Bob Learned
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of exptech

ASKER

Please excuse my lack of knowledge and experience with designers and automating the IDE. Here is what I don't understand which as you will see will relate to your answer. My understanding is that each control on the windows form will use a designer, so there will be multiple designers for a form if I am correct. What brings them all together? Let me give you an example: If I write a very simple custom designer for my usercontrol and I override the Initialization Method with code such as this:

public override void Initialize(IComponent component)
            {
                base.Initialize(component);

                MyUserControl myControl = (MyUserControl)Component;

                Messagebox.Show(myControl.Controls.Count.ToString());
            }

What I am trying to do here is to bring to front all of the added controls, but unfortunately the count shows that they are not there. In other words any control dragged unto my usercontrol do not show up at this point. This leads me to believe that the designer is just for the usercontrol itself. In addition I have tried the code that brought the textbox to the front when it is first dragged unto the control (which worked until you closed the form), but instead of putting it just into the InitializeNewComponent method of the designer I created for the textbox (child control of the usercontrol), I also put it into the initialization method thinking it would be called every time the form is created. It did not work, the text box was still behind the content in the usercontrol. So there must be something that co-ordinates the two designers and this is where I am not sure how to use your answer. You say the z-order must be saved as a property in the designer file. What designer file are you referring to? In addition how would you represent the z-order as a property. What would you do with this property to get the textbox up front. The only ways to layer controls I am familiar with is the SendToBack and MoveToFront Methods, I am not aware of any Z-order property or anything else like that.

Again, I apologize for not understanding your answer right away I am sure it must seem pretty basic to you.

Thanks again
When you create a Form is created, there are 2 other files created.  For a form named Form1.cs, that would be Form1.resx, and Form1.Designer.cs.  The .resx extension is for any resources stored in an XML file.  The .Designer file stores any information that is required for the form.  The concept is called "partial classes".  

The Form1.cs has a declaration with the partial keyword:

 public partial class Form1 : Form

Open in new window


The Form1.Designer.cs has another declaration for the same class name, also with the partial keyword:

 partial class Form1

Open in new window


Any time the Form1 class is created, the constructor is called (in Form1.cs):

   
    public Form1()
        {
            InitializeComponent();
        }

Open in new window


Any properties that need to be persisted are stored in the Form1.Designer.cs file.  If you can't see the code in the InitializeComponent method, expand the region "Windows Form Designer generated code", which can hide the code in that method.

 private void InitializeComponent()
        {
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.SuspendLayout();
            // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
            // 
            // Form1
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.ClientSize = new System.Drawing.Size(545, 445);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);

        }

Open in new window

Avatar of exptech

ASKER

Sorry about the delay TLO, my Mom is pretty sick right now (cancer) and being an only child, it it up to my wife and myself to make sure she gets the treatment she needs. Now back to the question at hand.

Duh !!! I feel like an idiot. Windows Forms structure (.cs, .Designer.cs, and .resx), as well as partial classes are Windows Forms 101. I was looking for a more complicated answer when I should have started more simple. Rarely do I have to modify the .Designer.cs or resx files, most of my work revolves around business applications and systems programming and using the forms with the built in and purchased controls has always done the job. What is happening is that my UserControls are becoming far more intricate and wide ranging in their scope. Problem is that with this comes the problem of usability, and being able to work with them like a built in control in the IDE is quickly becoming a necessity. I think one of the reasons I did not consider the .Designer.cs file, and this is one of the final questions I have, is that I know a great deal of it is generated by VS and I know I read somewhere that MS did not recommend modifying it ( or modifying certain areas of it) due to the fact that your changes can be wiped out. So the question is do your changes get wiped out, is there a special place in the file they should go, or is there an attribute that protects them.

Now for my final question, regardless 0f the methodology that I use to store the Z-order property (simple 0 - X,. Enum, etc) how do actually implement the order. Again, I am only aware of the SendToBack and BringToFront Methods and no properties for layering windows controls. Am I missing something ? If I am correct then I can design an algorithm that would track the order and using these methods correctly layer the controls but this seems to be crude way to do it and it was be nice if there were a more elegant solution.

Even though I still have these two questions I am going to award you the points. You really have answered the question I presented and I am sure one way or another I will be for the most part using the answer.

Thank you for your help.
Eric
Persisting properties in the .Designer file is the suggested way to keep all of your properties for custom user controls.  The suggestion about modifying the designer file is sound, but not a hard and fast rule.  It is a guideline to help developers understand that those properties can be changed without notice.  That guideline doesn't apply 100% of the time.  You still need to be able to save property values in for the form, and the designer file is the place to do that.

My suggestion for implementing a Z-Order is to get a list of the controls in descending order by the ZOrder property.  Loop through the list, and send the current control to the back.  The control with the highest ZOrder will be the last, and will be the bottom control in z-order stack.