Show WinFrm from C# console application and wait t

2019-08-26 09:22发布

问题:

I am trying to show a WinForm (inputbox) from a console application in C# and wait until the user closes the form. It is important for me to have the inputbox ontop and active when it opens. ShowDialog() is not working in my case as in some cases it does not appears as an active form. So I'd like to change my code and use Show(). This way I can manually make find out if the form is active or not and if not activate it myself. With ShowDialog(). my code stops and I can not do anything until the from is closed.

Below is my code. It does show the inputbox, however it is frozen. What am I doing wrong please? As clear the while-loop after "inputBox.Show();" is not doing anything, but if I can manage to run the loop and the inputbox does not freeze, I will sort out the rest myself. I appreciate your help.

public static string mInputBox(string strPrompt, string strTitle, string strDefaultResponse)
    {
        string strResponse = null;
        Form inputBox = new Form();
        inputBox.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
        inputBox.ClientSize = new Size(500, 85);
        inputBox.Text = strTitle;
        inputBox.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        inputBox.Left = (Screen.PrimaryScreen.Bounds.Size.Width / 2) - (inputBox.ClientSize.Width / 2);
        inputBox.Top = (Screen.PrimaryScreen.Bounds.Size.Height / 2) - (inputBox.ClientSize.Height / 2);

        Label lblPrompt = new Label();
        lblPrompt.Text = strPrompt;
        inputBox.Controls.Add(lblPrompt);

        TextBox textBox = new TextBox();
        textBox.Text = strDefaultResponse;
        inputBox.Controls.Add(textBox);

        Button okButton = new Button();
        okButton.Text = "&OK";
        inputBox.Controls.Add(okButton);

        Button cancelButton = new Button();
        cancelButton.Text = "&Cancel";
        inputBox.Controls.Add(cancelButton);

        okButton.Click += (sender, e) =>
        {
            strResponse = textBox.Text;
            inputBox.Close();
        };

        cancelButton.Click += (sender, e) =>
        {
            inputBox.Close();
        };
        inputBox.AcceptButton = okButton;
        inputBox.CancelButton = cancelButton;

        SetWindowPos(inputBox.Handle, HWND_TOPMOST, inputBox.Left, inputBox.Top, inputBox.Width, inputBox.Height, NOACTIVATE);

        inputBox.Show();

        while {true}
            Thread.Sleep(100);

        Application.DoEvents();
        return strResponse;
    }

回答1:

I'm not sure why you are taking this route, I'm sure there are better ways to do it (explain one at the end). however to make your code run you should add Application.DoEvents() inside your loop

the code should be something like this:

        var formActive = true;
        inputBox.FormClosed += (s, e) => formActive = false;
        inputBox.Show();
        inputBox.TopMost = true;
        inputBox.Activate();

        while (formActive)
        {
            Thread.Sleep(10);
            Application.DoEvents();
        }

and the whole method will be:

    public static string mInputBox(string strPrompt, string strTitle, string strDefaultResponse)
    {
        string strResponse = null;
        Form inputBox = new Form();
        inputBox.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
        inputBox.ClientSize = new Size(500, 85);
        inputBox.Text = strTitle;
        inputBox.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        inputBox.Left = (Screen.PrimaryScreen.Bounds.Size.Width/2) - (inputBox.ClientSize.Width/2);
        inputBox.Top = (Screen.PrimaryScreen.Bounds.Size.Height/2) - (inputBox.ClientSize.Height/2);

        Label lblPrompt = new Label();
        lblPrompt.Text = strPrompt;
        inputBox.Controls.Add(lblPrompt);

        TextBox textBox = new TextBox();
        textBox.Text = strDefaultResponse;
        inputBox.Controls.Add(textBox);

        Button okButton = new Button();
        okButton.Text = "&OK";
        inputBox.Controls.Add(okButton);

        Button cancelButton = new Button();
        cancelButton.Text = "&Cancel";
        inputBox.Controls.Add(cancelButton);

        okButton.Click += (sender, e) =>
        {
            strResponse = textBox.Text;
            inputBox.Close();
        };

        cancelButton.Click += (sender, e) =>
        {
            inputBox.Close();
        };
        inputBox.AcceptButton = okButton;
        inputBox.CancelButton = cancelButton;


        var formActive = true;
        inputBox.FormClosed += (s, e) => formActive = false;
        inputBox.Show();
        inputBox.TopMost = true;
        inputBox.Activate();

        while (formActive)
        {
            Thread.Sleep(10);
            Application.DoEvents();
        }

        return strResponse;
    }

but I think it would be a better Idea to Derive from Form and create a InputBox and set TopMost and call Activate OnLoad to create what you need, then simply call ShowDialog, something like:

class Inputbox : Form
        {

            protected override void OnLoad(EventArgs e)
            {
                base.OnLoad(e);

                TopMost = true;
                Activate();
            }
        }

and better to put UI code in InputBox class as the whole code and usage would be like:

class Inputbox : Form
{
    public string Response { get; set; }

    public Inputbox(string strTitle, string strPrompt, string strDefaultResponse)
    {
        //add UI and Controls here

        FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
        ClientSize = new Size(500, 85);
        Text = strTitle;
        StartPosition = System.Windows.Forms.FormStartPosition.Manual;
        Left = (Screen.PrimaryScreen.Bounds.Size.Width/2) - (ClientSize.Width/2);
        Top = (Screen.PrimaryScreen.Bounds.Size.Height/2) - (ClientSize.Height/2);

        Label lblPrompt = new Label();
        lblPrompt.Text = strPrompt;
        Controls.Add(lblPrompt);

        TextBox textBox = new TextBox();
        textBox.Text = strDefaultResponse;
        Controls.Add(textBox);

        Button okButton = new Button();
        okButton.Text = "&OK";
        Controls.Add(okButton);

        Button cancelButton = new Button();
        cancelButton.Text = "&Cancel";
        Controls.Add(cancelButton);

        okButton.Click += (sender, e) =>
        {
            Response = textBox.Text;
            Close();
        };

        cancelButton.Click += (sender, e) =>
        {
            Close();
        };
        AcceptButton = okButton;
        CancelButton = cancelButton;
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        TopMost = true;
        Activate();
    }
}

public static string mInputBox(string strPrompt, string strTitle, string strDefaultResponse)
{
    string strResponse = null;
    Inputbox inputBox = new Inputbox(strPrompt,strTitle,strDefaultResponse);

    inputBox.ShowDialog();

    return inputBox.Response;
}


回答2:

You need to run a message loop:

Application.Run(inputBox);