CBreeze
CBreeze

Reputation: 2973

Wait Message Whilst Performing Time-Consuming Tasks

I have a number of time-consuming tasks in my program such as loading large DataGrids, updating multiple Databases etc. etc. What I would like to do is display a "Please wait..." MessageBox or Form whilst these tasks are running. I've had a look at BackgroundWorker but can't seem to get my head round it.

To minimize the amount of code needed, ideally I would like a method that can be called from anywhere as this will be used in many places in my program, though I know that might be tricky.

public CompanyManagement()
{
    InitializeComponent();
    FillDataGrid(); // This method takes all the time
}

private void FillDataGrid()
{
    //Display a message until this has completed
    var _cDS = new CompanyDataService();
    var Companies = new ObservableCollection<CompanyModel>();
    Companies = _cDS.HandleCompanySelect();
    CompanyICollectionView = CollectionViewSource.GetDefaultView(Companies);
    CompanyICollectionView.SortDescriptions.Add(new SortDescription("CompanyName", ListSortDirection.Ascending));
    DataContext = this;

    cancelButton.Visibility = Visibility.Hidden;

    if (compNameRad.IsChecked == false && 
        compTownRad.IsChecked == false && 
        compPcodeRad.IsChecked == false)
    {
        searchBox.IsEnabled = false;
    }
    dataGrid.SelectedIndex = 0;
}

Is there a way to have a completely separate method to call? I guess this would be hard as there is no way then for that method to know when the tasks have been completed, unless it is surrounding the code to be checked.

EDIT: using Matthew's example;

    public CompanyManagement()
    {
        InitializeComponent();
        var wait = new PleaseWait("My title", "My Message", () => FillDataGrid());
        wait.ShowDialog();
    }

Upvotes: 1

Views: 438

Answers (1)

Matthew Watson
Matthew Watson

Reputation: 109617

Here's an approach you can take if you're using .Net 4.5 or later (so you can use await and async.

1) Create a Window class called "PleaseWait" and add to it a Label called label.

2) Add the following field and constructor to the class:

readonly Action _action;

public PleaseWait(string title, string message, Action action)
{
    _action = action;
    InitializeComponent();
    this.Title = title;
    this.label.Content = message;
}

3) Handle the window's loaded event and name the handler loaded, then implement it as follows:

private async void loaded(object sender, RoutedEventArgs e)
{
    await Task.Run(() => _action());
    this.Close();
}

Now when you want to show a "please wait" message, create a PleaseWait object passing to it the title, the message and an Action that encapsulates the code you want to run. For example:

private void button_Click(object sender, RoutedEventArgs e)
{
    var wait = new PleaseWait("My title", "My Message", myLongRunningMethod);
    wait.ShowDialog();
}

private void myLongRunningMethod()
{
    Thread.Sleep(5000);
}

Or (using a Lambda):

private void button_Click(object sender, RoutedEventArgs e)
{
    var wait = new PleaseWait("My title", "My Message", () => Thread.Sleep(5000));
    wait.ShowDialog();
}

This is just a basic outline. There's more work for you to do, including making the "PleaseWait" dialog look nice and disabling the user's ability to close it manually.

Upvotes: 2

Related Questions