Puzzling Windows Forms positioning predicament


I have a question that I cannot figure out because I can’t figure out how to phrase it in a search engine. Maybe one of my readers has the answer?


Suppose I have an app with 3 forms:

 —    ——————
| | | |
| A | | |
| | | |
— | |
| C |
— | |
| | | |
| B | | |
| | | |
— ——————


This is not an MDI app, but just has 3 separate forms. Only form “C” is to be shown in the taskbar. The other forms reflect summary data about what’s going on in C but aren’t really for user interaction.


My problem is that when the user switches away from form C and then comes back, either by minimizing/maximizing, Alt-Tab or whatever, I need to bring forms A and B to the front again. I tried working with methods like Focus() and BringToFront() as well as the Activate() event, but the problem is that when C is activated, and I bring A or B to front, when I switch back to C then it tries to activate A or B again, so I’m stuck in a loop.


Thanks for any input you might have to this puzzling predicament.


Comments (12)

  1. alp says:

    Assuming that formC is your main form, I think you can get away with just setting formA.Owner and formB.Owner equal to formC. Or, call formC.AddOwnedForm(formA) and formC.AddOwnedForm(formB).

  2. Hi Glen,

    Could you do something like this?

    1. Form C gets Activate()

    2. Form C’s Activate() method sets some sort of Global flag, mutex, etc…

    3. Form C calls Form A’s BringToFront()

    4. Form A’s Activate calls Form B’s BringToFront()

    5. Form B’s Activate calls Form C’s BringToFront()

    6. When Form C’s activate is called for a second time, it checks that flag, finds it’s set, clears the flag, and DOESN’T call the other forms activation methods.

    Just a suggestion…

  3. Another thought… Check out the source code for PAINT.NET. The latest version has a similar concept with some of it’s floating windows. Maybe their code my be useful

  4. Kraki says:

    Have you thought about using some type of Singleton to sync all the activation? Have the Singleton be the only class that can activate the forms and include code in the activation function to prevent reentry into the activation section. Something like this (WARNING: Barely tested code, with little/no design):

    public class Synchronizer

    {

    private static Synchronizer _instance = null;

    private bool _activating = false;

    public static Synchronizer Instance()

    {

    if (_instance == null)

    {

    _instance = new Synchronizer();

    }

    return _instance;

    }

    public void Activate(params Form[] forms)

    {

    if (!_activating)

    {

    _activating = true;

    foreach (Form activateForm in forms)

    {

    activateForm.Activate();

    }

    _activating = false;

    }

    }

    private Synchronizer()

    {}

    }

  5. Hi Glen,

    I found your question very intersting, so I posted a possible solution in my own blog:

    http://diazorm.e-supinfo.net/blog/?p=90

  6. anonymous coward says:

    How about making them owned windows:

    formC_OnLoad(…)

    {

    formA.Show(formC);

    formB.Show(formC);

    That should do most of the work for you.

  7. sbv says:

    You could use EnumChildWindows of the desktop window, find forms a & b and then call something like BringWindowToTop, but ensure that at the end of this code you focus form c

  8. I beleive if you set the Owner field of the "child" forms to me your main form, it will do everything you want automatically. Just set the ShowInTaskbar to false, and you’re good to go… (Note that if you minimize a child window like this, it will minimize above the task bar unless the owner window is minimized also)

    I just tried this with an application I’m working on, and it works exactly the way I understand you want it to.

  9. Ken says:

    Have you tried playing with the Z-Order of forms A & B? Focus implies the user is going to provide input to the form, but the Z-Order will simply bring the forms to the top without taking focus away from form C.

  10. Will Sullivan says:

    Hey from Cola, SC… Have you tried inheriting the form and overriding those events? You might have to dip lower into the call stack and intercept window messages by overriding PreProcessMessage or WndProc… Most likely you’ll have to go low in order to bring your children up without entering your loop…

  11. cfrey says:

    There are a few ways to do this.

    I think what you are looking for is this:

    First set the ShowInTaskbar property to False for each "sub"-form.

    Then load the forms (this could be in the load event of the main form, Form1) passing a reference to the main form in the show method like this (assumes you’ve already created a Form2.cs and Form3.cs in your project):

    Form2 f2 = new Form2();

    f2.Show(this);

    Form3 f3 = new Form3();

    f3.Show(this);

    Now they will show, with just Form1 showing up on the taskbar and in the Alt-Tab list, and all forms display when you bounce back. If you alt-tab back all the forms will retain their position and hold on the whether they were minimized. If you minimize the main form and then show it again all of the subforms will show, so if you want them to stay minimized (if they were) you’d have to track that externally.

    For a totally different approach you could set it up with a main (shell) form and then create your sub forms inside that form (perhaps in panels to help with positioning) like this:

    Form2 f2 = new Form2();

    f2.TopLevel = false;

    f2.Parent = this; // just stick it anywhere

    f2.Show();

    Form3 f3 = new Form3();

    f3.TopLevel = false;

    f3.Parent = panel3; // stick it in a panel

    f3.Show();

    In this case you could also set your sub forms to inherit from the main form.

    Hope that helps,

    Craig

  12. cfrey says:

    Also check out the Form.OwnedForms Property in help. I think is does the same thing as passing "this" in the show method.

    Craig