kurabdurbos
kurabdurbos

Reputation: 277

Issues with loading winform for notification

I have created a small C# application to read some data from an event log and then display some results.

The program does a basic SQL query to get its initial data(this can take some time if querying several days worth of data), then it does some processing before it displays the results.

What I am trying to do is when the Submit button is pressed a message appears stating that it will take a few moments to retrieve and process the data. So, when the submit button is pressed I create a form with a message on it and display it.

This is code from the submit button and the associated methods:

private void btnSubmit_Click(object sender, EventArgs e)
{
    DisplayCustomMessageBox("Please Wait");

    ProcessRequest();

    HideCustomMessageBox();
}


private void DisplayCustomMessageBox(string title)
{
    CustomMessageBox = new frm_Message { Text = title };
    CustomMessageBox.SetText("Please wait ");
    CustomMessageBox.Show();
    this.Enabled = false;
}

private void HideCustomMessageBox()
{
    this.Enabled = true;
    CustomMessageBox.Close();
}

Whats happening is that I have the form showing BUT the text in the form never displays. If I comment out the HideCustomMessageBox method the form displays without the text until the ProcessRequest method finishes. Then the form will finally display the text.

I assume its some sort of timing issue but I am not sure about how to fix it.

Thanks in advance.

Upvotes: 1

Views: 158

Answers (2)

noseratio
noseratio

Reputation: 61666

I'd do this using a modal dialog (Form.ShowDialog) and Task.Run to run ProcessRequest on a background thread. Async/await is very handy while implementing this.

using System;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsForms_21739538
{
    public partial class MainForm : Form
    {
        public MainForm()
        {
            InitializeComponent();

            // test the btnSubmit_Click
            this.Load += async (s, e) =>
            {
                await Task.Delay(2000);
                btnSubmit_Click(this, EventArgs.Empty);
            };
        }

        private async void btnSubmit_Click(object sender, EventArgs e)
        {
            try
            {
                // show the "wait" dialog asynchronously
                var dialog = await DisplayCustomMessageBox("Please Wait");

                // do the work on a pool thread
                await Task.Run(() =>
                    ProcessRequest());

                // close the dialog    
                dialog.Item1.Close();

                // make sure the dialog has shut down
                await dialog.Item2;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        // show a modal dialog asynchrnously
        private async Task<Tuple<Form, Task<DialogResult>>> DisplayCustomMessageBox(string title)
        {
            //CustomMessageBox = new frm_Message { Text = title };
            var CustomMessageBox = new Form();

            CustomMessageBox.Text = "Please wait ";

            var tcs = new TaskCompletionSource<bool>();

            CustomMessageBox.Load += (s, e) =>
                tcs.TrySetResult(true);

            var dialogTask = Task.Factory.StartNew(
                ()=> CustomMessageBox.ShowDialog(),
                CancellationToken.None,
                TaskCreationOptions.None,
                TaskScheduler.FromCurrentSynchronizationContext());

            // await the dialog initialization
            await tcs.Task;

            return Tuple.Create(CustomMessageBox, dialogTask);
        }

        void ProcessRequest()
        {
            // simulate some work
            Thread.Sleep(2000);
        }
    }
}

Upvotes: 0

Matt
Matt

Reputation: 3680

Here is some threaded code to get you started.

private void btnSubmit_Click(object sender, EventArgs e)
{
    DisplayCustomMessageBox("Please Wait");

    Thread t = new Thread(()=>
    {
        ProcessRequest();
        this.BeginInvoke(new Eventhandler((s,ee)=>{
            HideCustomMessageBox();
        }));
    });
    t.Start();
}

Upvotes: 1

Related Questions