WPF loading animation on a separate UI thread? (C#)

There is only one UI thread. What you need to do is to load the data in the DataTable on a different thread.

If you want to show progress to the DataTable loading along the way (either directly, or through a ProgressBar or some other mechanism), the BackgroundWorker is a fairly straight-forward way to do that.

UPDATE: Very Simple Background Worker example
Here is a fairly simple example. It adds 100 random numbers to a collection, pausing the thread for a short time between each to simulate a long loading process. You can simply cut and paste this into a test project of your own to see it work.

The thing to notice is that the heavy lifting (the stuff that takes a while) is done in the DoWork, while all UI updates are done in ProgressChanged and RunWorkerCompleted. In fact, a separate list (numbers) is created in the DoWork handler because the global mNumbers collection is on the UI thread, and can’t interact in the DoWork handler.

XAML

<Button x:Name="btnGenerateNumbers"
        Grid.Row="1"
        HorizontalAlignment="Center"
        VerticalAlignment="Center"
        Content="Generate Numbers" />

C# Code-Behind

BackgroundWorker bgWorker = new BackgroundWorker();
ObservableCollection<int> mNumbers = new ObservableCollection<int>();

public Window1()
{
    InitializeComponent();
    bgWorker.DoWork += 
        new DoWorkEventHandler(bgWorker_DoWork);
    bgWorker.ProgressChanged += 
        new ProgressChangedEventHandler(bgWorker_ProgressChanged);
    bgWorker.RunWorkerCompleted += 
        new RunWorkerCompletedEventHandler(bgWorker_RunWorkerCompleted);
    bgWorker.WorkerReportsProgress = true;

    btnGenerateNumbers.Click += (s, e) => UpdateNumbers();

    this.DataContext = this;
}

void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    progress.Visibility = Visibility.Collapsed;
    lstItems.Opacity = 1d;
    btnGenerateNumbers.IsEnabled = true;
}

void bgWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    List<int> numbers = (List<int>)e.UserState;
    foreach (int number in numbers)
    {
         mNumbers.Add(number);
    }

    progress.Value = e.ProgressPercentage;
}

void bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
    Random rnd = new Random();
    List<int> numbers = new List<int>(10);

    for (int i = 1; i <= 100; i++)
    {
        // Add a random number
        numbers.Add(rnd.Next());            

        // Sleep from 1/8 of a second to 1 second
        Thread.Sleep(rnd.Next(125, 1000));

        // Every 10 iterations, report progress
        if ((i % 10) == 0)
        {
            bgWorker.ReportProgress(i, numbers.ToList<int>());
            numbers.Clear();
        }
    }
}

public ObservableCollection<int> NumberItems
{
    get { return mNumbers; }
}

private void UpdateNumbers()
{
    btnGenerateNumbers.IsEnabled = false;
    mNumbers.Clear();
    progress.Value = 0;
    progress.Visibility = Visibility.Visible;
    lstItems.Opacity = 0.5;

    bgWorker.RunWorkerAsync();
}

Leave a Comment