Max Bündchen
Max Bündchen

Reputation: 1362

Modal-like User Control

I have a multi tabs winform using a split container. In the right tab I show/hide the user controls using the left tab. Some user controls needs to show a new user control on top of it. The problem is that when the original user control shows the new user controls, I would like that the first user control waits the new one to close (some like ShowDialog in forms), but this screen lock should occour in only one tab.

I tried Threads and many other solutions but none works as I want.

{
    var panel = (Panel)this.Parent;
    var searchUserControl = new searchUserControl();
    searchUserControl.Parent = this;
    panel.Controls.Add(searchUserControl);
    this.visible = false; // hides the original form
    // wait
    this.visible = true; // shows the original form again
    var result = searchUserControl.CustomProperty;
}

Upvotes: 1

Views: 1640

Answers (1)

Bradley Uffner
Bradley Uffner

Reputation: 16991

You can use async/await to do this, if you use a few tricks.

The key ingredient is TaskCompletionSource. It represents the "state" of a Task, and lets you "complete" it from another point in code, in this case, a button on the "dialog".

Create a UserControl to represent your "dialog", give it "ok" and "cancel" buttons, or whatever buttons you need.

The code-behind for the UserControl should look something like this:

public partial class DialogControl : UserControl
{
    TaskCompletionSource<DialogResult> _tcs;

    public DialogControl()
    {
        InitializeComponent();
        this.Visible = false;
    }

    public Task<DialogResult> ShowModalAsync()
    {
        _tcs = new TaskCompletionSource<DialogResult>();

        this.Visible = true;
        this.Dock = DockStyle.Fill;
        this.BringToFront();
        return _tcs.Task;
    }

    private void btmCancel_Click(object sender, EventArgs e)
    {
        this.Visible = false;
        _tcs.SetResult(DialogResult.Cancel);
    }

    private void btnOk_Click(object sender, EventArgs e)
    {
        _tcs.SetResult(DialogResult.OK);
        this.Visible = false;
    }

    public string UserName
    {
        get { return txtName.Text; }
        set { txtName.Text = value; }
    }
}

The Button on the main form can use this code to display the "modal control":

private async void btnShowDialogControl_Click(object sender, EventArgs e)
{
    var control = new DialogControl();
    splitContainer1.Panel2.Controls.Add(control);

    //Disable your other controls here


    if (await control.ShowModalAsync() == DialogResult.OK) //Execution will pause here until the user closes the "dialog" (task completes), just like a modal dialog.
    {
        MessageBox.Show($"Username: {control.UserName}");
    }

    //Re-enable your other controls here.

    splitContainer1.Panel2.Controls.Remove(control);
}

Full source code for a working solution can be downloaded from here.

Upvotes: 2

Related Questions