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