InputBox using modal forms

186 views
Skip to first unread message

josebonil...@gmail.com

unread,
Oct 6, 2014, 9:28:13 PM10/6/14
to eto-...@googlegroups.com
Hello, I am trying to create a modal InputBox with Eto.Forms in order to replace my custom WinForms InputBox. My app is made with WinForms, but I am migrating it step by step in order to look better in each platform; but the class Eto.Forms.Form doesn't have a ShowDialog() method.

This means code in the main window will continue no matter the child InputBox isn't closed yet.

How can I launch an InputBox from a parent form without ShowDialog()?

I am posting some WinForms code if it helps:

public static DialogResult Show(string title, string promptText, out string value)
        {
            Form form = new Form();
            Label label = new Label();
            TextBox textBox = new TextBox();
            Button buttonOk = new Button();
            Button buttonCancel = new Button();

            textBox.UseSystemPasswordChar = true;

            form.Text = title;
            label.Text = promptText;
            //textBox.Text = value;

            buttonOk.Text = "OK";
            buttonCancel.Text = "Cancel";
            buttonOk.DialogResult = DialogResult.OK;
            buttonCancel.DialogResult = DialogResult.Cancel;

            label.SetBounds(9, 20, 372, 13);
            textBox.SetBounds(12, 36, 372, 20);
            buttonOk.SetBounds(228, 72, 75, 23);
            buttonCancel.SetBounds(309, 72, 75, 23);

            label.AutoSize = true;
            textBox.Anchor = textBox.Anchor | AnchorStyles.Right;
            buttonOk.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
            buttonCancel.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

            form.ClientSize = new Size(396, 107);
            form.Controls.AddRange(new Control[] { label, textBox, buttonOk, buttonCancel });
            form.ClientSize = new Size(Math.Max(300, label.Right + 10), form.ClientSize.Height);
            form.FormBorderStyle = FormBorderStyle.FixedDialog;
            form.StartPosition = FormStartPosition.CenterScreen;
            form.MinimizeBox = false;
            form.MaximizeBox = false;
            form.AcceptButton = buttonOk;
            form.CancelButton = buttonCancel;

            DialogResult dialogResult = form.ShowDialog();
            value = textBox.Text;
            return dialogResult;
        }

Thanks for your help!

curtis

unread,
Oct 6, 2014, 9:32:29 PM10/6/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Hi,

Thanks for the detailed example!  It looks like all you need to do is swap out Form for Dialog.  Form is always non-modal, whereas Dialog is modal.  Dialog also has AcceptButton and CancelButton, whereas Form does not.

Hope this helps!
Curtis.

Jose Bonilla

unread,
Oct 6, 2014, 9:46:26 PM10/6/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Thanks, this seems really promising. I'm trying now migrating the InputBox this way!

Thanks again for your quick response.

Jose Bonilla

unread,
Oct 7, 2014, 12:05:56 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Please, help me with this issue with Dialogs, I think this is a bug, or I am missing something.

I am implementing the InputBox as suggested, below the code:
using Eto.Drawing;
using Eto.Forms;
using System;

namespace EtoSample
{
    public static class PasswordInputBox
    {
        public static DialogResult ShowDialog(string title, string promptText, out string value)
        {
            var dialog = new Dialog();
            dialog.Title = title;

            var passwordBox = new PasswordBox();

            var buttonOk = new Button { Text = "Ok" };
            buttonOk.Click += buttonOk_Click;

            var buttonCancel = new Button { Text = "Cancel" };

            dialog.DefaultButton = buttonOk;
            dialog.AbortButton = buttonCancel;

            var layout = new DynamicLayout();

            layout.BeginVertical(); // fields section
            layout.AddRow(new Label { Text = promptText });
            layout.AddRow(passwordBox);
            layout.EndVertical();

            layout.BeginVertical(); // buttons section
            // passing null in AddRow () creates a scaled column
            layout.AddRow(null, buttonOk, buttonCancel);
            layout.EndVertical();

            dialog.Content = layout;
            dialog.Topmost = true;

            var center = Screen.PrimaryScreen().WorkingArea.Center;
            center.X -= 80;
            center.Y -= 40;

            dialog.Location = new Point(center);

            dialog.Visible = true;

            var result = dialog.ShowDialog();
            value = passwordBox.Text;

            return result;
        }

        private static void buttonOk_Click(object sender, System.EventArgs e)
        {
            var dialog = (Dialog)((Button)sender).ParentWindow;
            dialog.Close(DialogResult.Ok);
        }
    }
}


When I call the method like this, it works like a charm the first time:
if (PasswordInputBox.ShowDialog("Numbers", "Input: ", out value) == DialogResult.Ok)
{
    MessageBox.Show(value);
}

But whenever I call the same a second, third, etc. time it "bypass" (don't stop) in the ShowDialog:

var result = dialog.ShowDialog();

And always return "None". Nevertheless, the parent window keeps disabled (you cannot clic any button, etc.).

Thanks again for your time.

On Monday, October 6, 2014 8:32:29 PM UTC-5, curtis wrote:

curtis

unread,
Oct 7, 2014, 12:10:22 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
It is an unfortunate 'feature' of windows forms. You cannot reuse Forms/Dialogs after they are closed, and you must re-create them each time you want to show them.  (see http://stackoverflow.com/questions/440051/is-it-possible-to-reuse-a-net-winforms-form-object)

If you want to keep a form, you will have to use Visible to hide/show it manually, but I would recommend against that.  Creating the form again isn't usually a performance problem though.

Cheers!
Curtis.

curtis

unread,
Oct 7, 2014, 12:23:16 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Oops, sorry.. I just realized you are creating the form each time.. I'm assuming you're using winforms?  or wpf?  I got an error on winforms using your code because of the Visible = true line before ShowDialog()...

A few things that might help.. 

1. you shouldn't set the form to Visible before calling ShowDialog().
2. if you pass the parent window/control to the ShowDialog() call, it will automatically center the dialog to the parent, so no need to set it manually.
3. You shouldn't need to set the dialog.TopMost = true, it is a dialog and will show atop the current window regardless.

Hope this helps!

Jose Bonilla

unread,
Oct 7, 2014, 12:24:50 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Thanks again. But I think this is not the case.

I also tried recreating the object, but the problem is the same.

using Eto.Drawing;
using Eto.Forms;
using System;

namespace EtoSample
{
    public class PasswordInputBox : Dialog
    {
        public string Text { get; set; }

        PasswordBox passwordBox;

        public PasswordInputBox(string title, string promptText)
        {            
            this.Title = title;

            this.passwordBox = new PasswordBox();

            var buttonOk = new Button { Text = "Ok" };
            buttonOk.Click += buttonOk_Click;

            var buttonCancel = new Button { Text = "Cancel" };

            this.DefaultButton = buttonOk;
            this.AbortButton = buttonCancel;

            var layout = new DynamicLayout();

            layout.BeginVertical(); // fields section
            layout.AddRow(new Label { Text = promptText });
            layout.AddRow(passwordBox);
            layout.EndVertical();

            layout.BeginVertical(); // buttons section
            // passing null in AddRow () creates a scaled column
            layout.AddRow(null, buttonOk, buttonCancel);
            layout.EndVertical();

            this.Content = layout;
            this.Topmost = true;

            var center = Screen.PrimaryScreen().WorkingArea.Center;
            center.X -= 80;
            center.Y -= 40;

            this.Location = new Point(center);            
        }        

        private void buttonOk_Click(object sender, System.EventArgs e)
        {
            this.Text = passwordBox.Text;
            this.Close(DialogResult.Ok);
        }
    }
}


And calling like this:

            var pBox1 = new PasswordInputBox("Numbers", "Input: ");

            if (pBox1.ShowDialog() == DialogResult.Ok)
            {
                MessageBox.Show(pBox1.Text);
            }

            var pBox2 = new PasswordInputBox("Numbers", "Input: ");

            if (pBox2.ShowDialog() == DialogResult.Ok)
            {
                MessageBox.Show(pBox2.Text);
            }

Please, let me know if I understood well, or if this is some kind of issue with Dialogs.

Regards.

Jose Bonilla

unread,
Oct 7, 2014, 12:38:24 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
You are right, I am using this on Windows, and tried with both Winforms and WPF.

Hope you could read my last reply, unfortunatly I cannot pass the parent control/window because I am calling this from Winforms (the parent is not an Eto.Forms), but you can comment all the location stuff and it doesn't change the result. I only set the visible hoping it helps with the problem in the second call, but you can comment it also.

By the way, it tried the same code in the "EtoSample" solution to discard problems with mi app, and it fails the same way.

I really liked this library, and hope there is a solution for calling a custom Dialog more than once. 

I know your time is very important, so I am very thankful for your help.

curtis

unread,
Oct 7, 2014, 12:45:18 AM10/7/14
to eto-...@googlegroups.com, josebonil...@gmail.com
Ah, that makes sense.

A few things you could try to resolve this:

1. Use the develop branch of Eto (I'm assuming you are using 1.3.0 from nuget.org?) A link to the nuget repo for the develop branch is on the github page.  There have been some enhancements regarding using Eto.Forms within existing apps on this branch.
2. If you are embedding in an app, you must run this before using any eto.forms code:
new Eto.Forms.Application().Attach();

Please let me know if that works!

I'll be creating a new wiki page on how to embed eto.forms within existing apps soon, as it seems to be a common trend lately.

Cheers!
Curtis.
Reply all
Reply to author
Forward
0 new messages