Need global reference to main form

(I originally posted this in the Visual C++ Express forums but I realise that I would probably get a better response here)

Ok, so I've got a form with a bunch of ComboBoxes that are created at runtime instead of at design time. I want to give each of those ComboBoxes the same ContextMenu, which is a member of my MainForm:

public ref class MainForm : public System::Windows::Forms::Form
{
// ...
private: ContextMenuStrip^ myComboBoxContextMenu;
// ...
}

I figured I should create a sub-class of ComboBox which automatically assigns the context menu in the constructor:

ref class MyComboBox : public ComboBox
{
public:
MyComboBox()
{
this->ContextMenu = /* reference to context menu in MainForm */
}
};

The context menu is a member of a MainForm object so how can I get a reference to the running mainForm Apparantly I cannot simply have a global MainForm instance as it is a managed type.

Thanks in advance.


Answer this question

Need global reference to main form

  • HotKeeper

    "If you know that there will only ever be one instance of the MainForm form, you could mimic the ActiveForm approach by creating a public static property (read-only) within MainForm that returned a form reference and a private static member to hold the reference to be returned. Then, in the MainForm constructor you could set the private member variable."

    This is what I had originally considered doing. That's a singleton, right

    It just seems that the solutions are a little inelegant. Using OpenForms or ActiveForm would require casting to MainForm so that I could access the ContextMenu. If other forms are open then it just gets messy.

    I was thinking maybe I should use a nested class. Having MyComboBox nested in MainForm would ensure access to the context menu and I think it would be the most elegant solution but I'm not really sure how to use nested classes. Could anyone shed some light on this. If this is not possible then I'll probably settle with the singleton approach.

  • Alexei_shk

    Your ComboBox derives (eventually) from Control so one approach would be to use the TopLevelControl property (this->TopLevelControl) to access the form the ComboBox is contained within. Of course depending on your application's architecture that might be SomeOtherForm and not MainForm.

    You could use the static method Application.OpenForms to retrieve a collection of all the open forms your application is running and find your MainForm that way. That could be relatively expensive if your application opens many forms.

    You could use the static property Form.ActiveForm to retrieve the currently active form, but again the active form and MainForm might be different.

    If you know that there will only ever be one instance of the MainForm form, you could mimic the ActiveForm approach by creating a public static property (read-only) within MainForm that returned a form reference and a private static member to hold the reference to be returned. Then, in the MainForm constructor you could set the private member variable.

    I have the nagging feeling that I've missed something obvious but I can't think what.


  • AntonioP

    The problem is, it's not in my MainForm's code. The context menu is assigned in the combo box constructor, which does not have access to myComboBoxContextMenu because the menu is a member of MainForm.

  • Claudio V.

    Umm, that was my point: don't assign it in the combobox constructor, assign it after it is constructed. If you have to, consider passing the context menu reference as an argument to the constructor.


  • Sean McLellan 360

    nobugz is correct. you don't want to statically assign the context-menu inside a constructor. you need to create a public context-menu property in your combobox derived control. this way your combobox will be reusable.
  • YongZai

    There are other ways to do this. Since its on your main form, Application.OpenForms[0] is very likely to give you a reference to it. However, the real fix that is guaranteed not to fail and doesn't require casting is to simply set the ContextMenuStrip reference when you create the control at run-time. Just like the designer does.


  • Christian Mol

    Could you elaborate on what you mean by "the real fix ... is to simply set the ContextMenuStrip reference when you create the control at run-time."
  • John Bock

    Somewhere in your MainForm's code, you'll have a statement:
    myComboBox1 = gcnew MyComboBox;
    Add:
    myComboBox1->ContextMenu = myComboBoxContextMenu;



  • Need global reference to main form