firant
firant

Reputation: 15

How do I make my application wait for my UI to refresh?

Without using extra threads I would simply like to display a "Loading" label or something similar to the user when a large amount of data is being read or written. If I however attempt to modify any UI elements before calling the IO method, the application freezes for a while and then displays the "Loading" message after all the work is already done. This obviously doesn't help. How can I ensure that any UI changes are applied and visible before calling the IO method?

        DataSet ds = STT_Import.ImportExcelToDataSet(filePath);

        bool result = false;

        if (ds != null)
        {
            int cellCount = ds.GetTotalCellCount();

            if (Popup.ShowMessage(string.Format("Your file contains {0} cells. Inserting data will take approximately {1} seconds. Do you want to continue?",
                cellCount, CalculateTime(cellCount)), "Confirm", MessageType.Confirm) == MessageBoxResult.Yes)
            {
                // Tell user the application is working:
                StatusLabel.Content = "Writing to database...";

                // Do actual work after user has been notified:
                result = DB.StoreItems(_currentType, ds);
            }
        }

I tried looking for answers but couldn't find anything that answered my specific question, so I'm sorry if the question has been asked before.

Upvotes: 0

Views: 554

Answers (5)

paparazzo
paparazzo

Reputation: 45096

If you don't want the UI to be responsive I use a busy indicator.
There are prettier cursors - this is an in house application.

using (new WaitCursor())
{
    // very long task
    Search.ExecuteSearch(enumSrchType.NextPage);
}

public class WaitCursor : IDisposable
{
    private Cursor _previousCursor;

    public WaitCursor()
    {
        _previousCursor = Mouse.OverrideCursor;

        Mouse.OverrideCursor = Cursors.Wait;
    }

    #region IDisposable Members

    public void Dispose()
    {
        Mouse.OverrideCursor = _previousCursor;
    }

    #endregion
}

Upvotes: 0

Rachel
Rachel

Reputation: 132548

When working with WPF, you can use the Dispatcher to queue commands on the UI thread at different DispatcherPriorities

This will allow you to queue your long-running process on the UI thread after everything in the DispatcherPriority.Render or DispatcherPriority.Loaded queues have occurred.

For example, your code may look like this:

// Tell user the application is working:
StatusLabel.Content = "Writing to database...";

// Do actual work after user has been notified:
Dispatcher.BeginInvoke(DispatcherPriority.Input,
    new Action(delegate() { 
        var result = DB.StoreItems(_currentType, ds);     // Do Work
        if (result)
            StatusLabel.Content = "Finished";
        else
            StatusLabel.Content = "An error has occured";
     }));

It should be noted though that its usually considered bad design to lock up an application while something is running.

A better solution would be to run the long-running process on a background thread, and simply disable your application form while it runs. There are many ways of doing this, but my personal preference is using the Task Parallel Library for it's simplicity.

As an example, your code to use a background thread would look something like this:

using System.Threading.Tasks;

...

// Tell user the application is working:
StatusLabel.Content = "Writing to database...";
MyWindow.IsEnabled = False;

// Do actual work after user has been notified:
Task.Factory.StartNew(() => DB.StoreItems(_currentType, ds))
    // This runs after background thread is finished executing
    .ContinueWith((e) =>
    {
        var isSuccessful = e.Result;

        if (isSuccessful)
            StatusLabel.Content = "Finished";
        else
            StatusLabel.Content = "An error has occured";

        MyWindow.Enabled = true;
    });

Upvotes: 1

Garry
Garry

Reputation: 5074

The Approach you are using is not efficient way so I would suggest to go with Async Programing or threading

Async programming:

Visual Studio 2012 introduces a simplified approach, async programming, that leverages asynchronous support in the .NET Framework 4.5 and the Windows Runtime. The compiler does the difficult work that the developer used to do, and your application retains a logical structure that resembles synchronous code. As a result, you get all the advantages of asynchronous programming with a fraction of the effort. Support .Net framework 4.5
It will save your time to implementing System .Threading and very efficient for the task same as your where we have to wait for some operation

http://msdn.microsoft.com/en-ca/library/vstudio/hh191443.aspx
http://go.microsoft.com/fwlink/?LinkID=261549

or

Threading:

The advantage of threading is the ability to create applications that use more than one thread of execution. For example, a process can have a user interface thread that manages interactions with the user and worker threads that perform other tasks while the user interface thread waits for user input.Support .Net fremework 4.0 or Older

http://msdn.microsoft.com/en-us/library/aa645740%28v=vs.71%29.aspx

Upvotes: 0

Servy
Servy

Reputation: 203802

It is provably impossible to keep your UI responsive without utilizing additional threads unless your database provides an asynchronous version of the method you're using. If it does provide an asynchronous version of the method then you simply need to use that. (Keep in mind that async does not mean that it's using any other threads. It's entirely possible to create an asynchronous method that never uses additional threads, and that's exactly what's done with most network IO methods.) The specifics of how to go about doing that will depends on the type of DB framework you're using, and how you're using it.

If your DB framework does not provide async methods then the only way to keep the UI responsive is to perform the long running operation(s) in a non-UI thread.

Upvotes: 0

Jon
Jon

Reputation: 437326

You are trying to solve the problem in the wrong manner. What you should be doing here is run the time-consuming task in a worker thread; this way, your UI will remain responsive and the current question will become moot.

There are several ways you can offload the task to a worker thread; among the most convenient are using the thread pool and asynchronous programming.

Upvotes: 0

Related Questions