1

I'm trying to build an Application UI using Winform for which will be having multiple pages inside it. Say software will be asking for a Login credentials on startup and then landing in a Dashboard. Then the user will have the option to go different pages like: Page1 - Page2 - Page3.

Now I'm planning to make one Form and all these pages will be separate UserControls. So as per requirement I will be changing the visibility of these UserControls.

Now to do this I'm putting the below code inside Form1.cs

  ControlLogin ucLogin = new ControlLogin();
  ucLogin.Location = new System.Drawing.Point(12, 67);
  this.Controls.Add(ucLogin);

This works fine. But while opening any UserControl from this ControlLogin.cs how will I add the new UserControl (say Page1Control) to the list of Form1?

hypheni
  • 756
  • 3
  • 17
  • 37
  • The RAD way is to use a [TabControl without tabs](http://stackoverflow.com/a/2798241/17034). – Hans Passant Jun 26 '15 at 00:02
  • You simply need to have a reference to the form in the user control. In a simple, generic way you already do as `button_loadStuff_Click(..){Form myParent = this.Parent; NextPage nextPage = new NextPage(); myParent .Controls.Add(nextPage);}` For a more pwerful ref you need to declare it as the real from type, by default called `Form1`. With this you also can access all (public) fields in the Form.. – TaW Jun 26 '15 at 05:34

2 Answers2

1

You need to develop some transaction logic for your pages. I suggest that on your main form you use a panel to use as container. In this container you will place current user control, the one that user selects.

For example:

internal void ReplaceUserPage(Control container, UserControl userRequest)
{
    if (container.Controls.Count == 1)
    {
        container.Controls.RemoveAt(0);
    }
    container.Controls.Add(userRequest);
    userRequest.Dock = DockStyle.Fill;
}

If you don't have dynamic pages, you can make all of them singletons. This way, instance of each will be created on demand and live in memory, ready to reuse. So, when user clicks on a menu or a button to open the page, you can do

UserControl requested = Page1Control.GetInstance();
ReplaceUserPage(container, requested);

With singleton, you don't even need to keep list of your controls. I don't say that this is best or perfect or one-fits-all way. There are many control transaction approaches. It depends on system complexity and other factors.

T.S.
  • 18,195
  • 11
  • 58
  • 78
  • I understand your singleton concept and my initial plan were to do the same. Let me get into the project more on tonight. Will back with comments afterwards. Thanks for sharing. – hypheni Jun 26 '15 at 08:25
1

The basic layout you chose looks fine to me.

Your actual question seems to be: How to reference the form from those UCs?

This is closely related to the questions: How to reference a form or parts of it from other forms? This has been asked here very often..

Here is what I suggest you should do:

  1. Create a public function for opening each of your UCs openLogin, openPageOne..
  2. Change the constructors of each UC to include a Form1 as a parameter (assuming your form has the default name) and call it accordingly like this: ControlLogin ucLogin = new ControlLogin(this);
  3. In the UCs constructors you want to store the passed in form in a class variable.

In the form you write:

public void openLogin(Form1 f)
{
  ControlLogin ucLogin = new ControlLogin(this);
  ucLogin.Location = new System.Drawing.Point(12, 67);
  this.Controls.Add(ucLogin);
}


public void openPageOne(Form1 f)
{
  ..
}

And in the UC(s):

public ControlLogin(Form1 form1)
{
    InitializeComponent();
    mainForm = form1;
}

Form1 mainForm = null;

Now you can reference all public fields and methods in the form, maybe like this

if (logingIsOK) mainForm.openPageOne();
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Thanks for sharing. This is what I was looking for. Now on top of this could you guide me some more.. that is, I'm planning to implement some grouping mechanism which will be like this.. Each group can have multiple pages(UCs). Once one group has been into view all other groups should be invisible. This way I can implement the inner pages under PageOne, PageTwo. Can I just add these control to a List of multiple arrays(Groups) and loop through them for changing the visibility? – hypheni Jun 26 '15 at 12:30
  • Yes and yes. Putting them in a List is probably a good idea. Then you can hide all in the openXXX function before showing the new one. however you need to decide on this: Do you want to keep them all around? If so fine, if not you would have to dispose of them. That really depends on what they contain. Maybe DB-connections you want either free or keep open? You decide! One may even want to create all beforehand - but again it depends: Will that slow things down too much initially or will it feel quicker later.. - Also: do you want to move forth and back between pages..?... – TaW Jun 26 '15 at 12:37
  • .. But a `List myPages` is certainly a good idea and also a `ucBaseClass currentPage` variable.. – TaW Jun 26 '15 at 12:38
  • Well. Circulating between pages will be there.. But each time a page opens it will show it's initial stage i.e. all fields with blank values. Show I think Show/Hide would be fine for me. And yes, if some db connectivity issue arise there I will have to think on disposing. – hypheni Jun 26 '15 at 13:19
  • OK, but do keep in mind that show/hide will __not__ reset any fields. So either go for removing and where necessary disposing the uc or maybe write a reset function so you can reset soem and keep other values.. Also note the difference between 'Dispose' and 'remove'. You only need to dispose of things that are `IDisposable`! Stream are one example and most GDI+ things like Bitmaps are another example.. Also note that disposing will not work recursively by itself! You will need to go through all nested IDisposables yourself.. So for a List you need to enumerate them all.. – TaW Jun 26 '15 at 14:09