12

I have a WPF user control that contains a DataGrid. I'm binding an ObservableCollection of view models to it. Each view model has another collection of view models that I'm using to bind another DataGrid to. So the effect is a DataGrid with a nested DataGrid contained in the row details template.

Normally the binding is quite quick, but sometimes when there's a lot of data it can hang the UI while the binding/drawing is taking place.

Is there a way where I can either show a loading animation or progress bar while the binding/drawing is in progress?

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
RogueX
  • 1,973
  • 2
  • 15
  • 14

2 Answers2

2

I had the same problem and this is how I solved it.

I discovered that DataGrid will only start creating controls when it displays the grid. In my case this was the time consuming process. After some tracing I found that creating the controls happens during measuring !

My solution is to override MeasureOverride and put the wait cursor around the base class call. I encapsulated my wait cursor setting in a class. So the code looks like this.

    protected override Size MeasureOverride(Size availableSize)
    {
        using (new DisposableWaitCursor(this))
        {
            return base.MeasureOverride(availableSize);
        }
    }
2

There's probably a more formal, or at least simpler solution, but you could use a modal popup window that is shown in a worker thread and is closed asynchronously when your is grid done loading:

Window waitWindow = new Window { Height = 100, Width = 200, WindowStartupLocation = WindowStartupLocation.CenterScreen, WindowStyle = WindowStyle.None };
waitWindow.Content = new TextBlock { Text = "Please Wait", FontSize = 30, FontWeight = FontWeights.Bold, HorizontalAlignment = HorizontalAlignment.Center, VerticalAlignment = VerticalAlignment.Center };

BackgroundWorker worker = new BackgroundWorker();
worker.DoWork += delegate
{
    Dispatcher.BeginInvoke(new Action(delegate { waitWindow.ShowDialog(); }));

    DataLoader dataLoader = new DataLoader(); // I made this class up
    dataLoader.DataLoaded += delegate
    {
        Dispatcher.BeginInvoke(new Action(delegate() { waitWindow.Close(); }));
    };

    dataLoader.LoadData();
};

worker.RunWorkerAsync();

You can replace the TextBlock with something pretty like a loading bar, and you could make the code re-usable by parameterizing the object that handles the loading of the grid(s) and passing it in to a commonly used method.

I hope that works for you.

Mike Pateras
  • 14,715
  • 30
  • 97
  • 137
  • I put the call to ShowDialog inside the worker thread's DoWork delegate to handle the case where the data is loaded before the the window is opened (showing the window outside of the worker required it to be done at the end, since ShowDialog blocks). I don't know how likely it would be (if it's even possible) for such a thing to happen, but I thought I'd play it safe than to introduce a rare, difficult to track bug. – Mike Pateras Jan 22 '10 at 05:47