Background: I want to show a custom message box to the user with Yes/No buttons and if the user clicks each of these buttons I will return the result to the caller. Also, if the user doesn't show any reaction again I want to return a third result (using a Timer
event). In a word, either after some time elapsed or after a button click the method (Display
in my code) should return a value; and I want to wait for either of them to happen.
Problem: The UI looks frozen and only the Timer
event triggers.
Code which will be used in the real project (with descent names!):
namespace MessageBox
{
public partial class Form2 : Form
{
public Form2()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
MyForm.Display();
}
}
public class MyForm : Form
{
public MyForm()
{
List<Button> _buttonCollection = new List<Button>();
FlowLayoutPanel _flpButtons = new FlowLayoutPanel();
Panel _plFooter = new Panel();
_plFooter.Dock = DockStyle.Bottom;
_plFooter.Padding = new Padding(5);
_plFooter.BackColor = Color.FromArgb(41, 47, 139);
_plFooter.Height = 75;
this.FormBorderStyle = FormBorderStyle.None;
this.BackColor = Color.FromArgb(20, 37, 105);
this.StartPosition = FormStartPosition.CenterScreen;
this.Padding = new Padding(3);
this.Width = 400;
_flpButtons.FlowDirection = FlowDirection.RightToLeft;
_flpButtons.Dock = DockStyle.Fill;
_plFooter.Controls.Add(_flpButtons);
this.Controls.Add(_plFooter);
Button btnYes = new Button();
btnYes.Click += ButtonClick;
btnYes.Text = "Yes";
Button btnNo = new Button();
btnNo.Click += ButtonClick;
btnNo.Text = "No";
_buttonCollection.Add(btnYes);
_buttonCollection.Add(btnNo);
foreach (Button btn in _buttonCollection)
{
btn.ForeColor = Color.FromArgb(170, 170, 170);
btn.Font = new System.Drawing.Font("Eurostile", 12, FontStyle.Bold);
btn.Padding = new Padding(3);
btn.FlatStyle = FlatStyle.Flat;
btn.Height = 60;
btn.Width = 150;
btn.FlatAppearance.BorderColor = Color.FromArgb(99, 99, 98);
_flpButtons.Controls.Add(btn);
}
}
static Task taskA;
private void ButtonClick(object sender, EventArgs e)
{
_event.Set();
Button btn = (Button)sender;
if (btn.Text == "Yes")
Result = 1;
else
{
Result = 2;
}
this.Close();
this.Dispose();
}
static AutoResetEvent _event = new AutoResetEvent(false);
private static MyForm form;
public static int Display()
{
form = new MyForm();
StartTimer();
form.Show();
_event.WaitOne();
form.Close();
form.Dispose();
return Result;
}
private static void StartTimer()
{
_timer = new System.Timers.Timer(10000);
_timer.Elapsed += SetEvent;
_timer.AutoReset = false;
_timer.Enabled = true;
}
private static System.Timers.Timer _timer;
public static int Result { get; set; }
private static void SetEvent(Object source, System.Timers.ElapsedEventArgs e)
{
_timer.Start();
Result = -1;
var timer = (System.Timers.Timer) source;
timer.Elapsed -= SetEvent;
_event.Set();
}
}
}
Note: I know the problem is that the UI control is created in a thread which is frozen but what's the solution?