0

I am having a problem with developing an SDI windows forms application. I am making use of a single window and different user controls that gets swapped out as the user progresses through the application.

The problem: I have a user control called Login that handles the log in process. After the user has successfully logged in the Login user control is supposed to dissappear and the Homepage user control should take front.

The Login user control needs to remove itself and transfer control to the Homepage user control.

I have tried sending the desired user control as a parameter to a method in the MainForm, although it doesn't change the user controls.

How can I achieve this? Am I using the approach wrong?

Please excuse me I am a beginner with user controls.

maddog550
  • 35
  • 2
  • 11
  • 2
    Please add some relevant code. Like the code where you transfer control and the method you are calling (And whatever else that seems fitting) – Cybrus Sep 01 '17 at 12:11
  • Easy approach is to split screens you see (pages) into different `UserControl`s (e.g. `UserControlLogin`, `UserControlSettings`, etc.) and add/remove those from `Controls` of single form (main form). Another, probably easier for beginner approach, is to use [headless `TabControl`](https://stackoverflow.com/q/10316567/1997232), where you just switch from tab to tab and have all the code in single form (sic!). Start with something. – Sinatr Sep 01 '17 at 12:38
  • @Sinatr thanks for your reply. I will try the headless tabcontrol approach. Is there not something like wpf pages in a frame for winforms apps? – maddog550 Sep 01 '17 at 12:46
  • *"wpf pages in a frame for winforms apps"* - pages are `UserControl`s, frame is any control what can contain [children](https://msdn.microsoft.com/en-us/library/system.windows.forms.control.controls(v=vs.110).aspx). – Sinatr Sep 01 '17 at 12:51

1 Answers1

1

You need to remove the old control from the form and add the new one.

public class MainForm: Form {
    //...
    private Control currentControl;

    public void ChangeControl(Control newControl) {
        if(newControl == null) {
            throw new ArgumentNullException("newControl");
        }
        if(currentControl != null) {
            Me.Controls.Remove(currentControl);
        }
        Me.Controls.Add(newControl);
        currentControl = newControl;
    }

    public void ShowHomePage() {
        // You could use a previously created control
        this.ChangeControl(this.homePageControl);
        // Or create a new one.
        // this.ChangeControl(new HomePageControl());
    }
    //...
}

public class LoginControl: Control {
    private void LoginButton_Click(Object sender, EventArgs e) {
        if(DoLogin(...)) {
            ((MainForm)this.Parent).ShowHomePage()
        }
        else {
            // Show some error message
        }
    }
}

Personally I prefer to comunicate to MainForm only via events, and never one control to another:

public class MainForm: Form {
    private Control currentControl;

    public void ChangeControl(Control newControl) {
        if(newControl == null) {
            throw new ArgumentNullException("newControl");
        }
        if(currentControl != null) {
            Me.Controls.Remove(currentControl);
            // Optionally you could dispose old control
            // currentControl.Dispose();
        }         
        Me.Controls.Add(newControl);
        currentControl = newControl;
    }

    // Optional generic method
    public void ChangeControl<TControl>() where TControl: Control, new() {
        this.Changecontrol(new TControl());
    }

    private void OnLoggedIn(Object sender, LoggedInEventArgs e) {
       this.ChangeControl<HomePageControl>();
    }

    private Login_ParentChanged(Object sender, EventArgs e) {
        var control = sender as LoginControl;
        if(control != null && control.Parent == null) {
            control.LoggedIn -= OnLoggedIn;
            control.ParentChanged -= Login_ParentChanged
        }
    }

    private void LogOut_Click(Object sender, EventArgs e) {
       var control = new LoginControl();
       control.LoggedIn += OnLoggedIn;
       this.ChangeControl(control);
       control.ParentChanged += Login_ParentChanged
    }
}

public class LoginControl: Control {
    public event EventHandler<LoggedInEventArgs> LoggedIn;

    private void LoginButton_Click(Object sender, EventArgs e) {
        if(DoLogin(...)) {
            if(LoggedIn != null) {
               LoggedIn(this, new LoggedInEventArgs(...))
            }
            else {
               // Show some error message
            }
        }
    }
}
Shago
  • 605
  • 4
  • 12
  • Thanks for your quick response! I have tried your method and it still doesn't want to change. In the Login user control I make a new object instance of the Mainform and call the method passing the desired user control. – maddog550 Sep 01 '17 at 12:58
  • You can't make a new instance of the Mainform object because then you aren't changing the original instance. Instead add an internal static instance variable in mainform so you can call Mainform.instance.ChangeControl(control) – RyanTimmons91 Sep 01 '17 at 14:19
  • Personally I prefer the MainForm to handle the transitions, and controls only comunicate to the main form via events. I updated my answer to reflect this. – Shago Sep 01 '17 at 18:29