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

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();}


I wrote a little test program which shows the use of the Dispatcher class. It just requires a WPF-Window and a ListBox with Name "listBox". Should be easy to apply this solution to your problem.

    public void Populate() {        // for comparison, freezing the ui thread        for (int i = 0; i < 1000000; i++) {            listBox.Items.Add(i);        }    }    private delegate void AddItemDelegate(int item);    public void PopulateAsync() {        // create a new thread which is iterating the elements        new System.Threading.Thread(new System.Threading.ThreadStart(delegate() {            // inside the new thread: iterate the elements            for (int i = 0; i < 1000000; i++) {                // use the dispatcher to "queue" the insertion of elements into the UI-Thread                // DispatcherPriority.Background ensures Animations have a higher Priority and the UI does not freeze                // possible enhancement: group the "jobs" to small units to enhance the performance                listBox.Dispatcher.Invoke(new AddItemDelegate(delegate(int item) {                    listBox.Items.Add(item);                }), System.Windows.Threading.DispatcherPriority.Background, i);            }        })).Start();    }