8

I have a WPF database viewer application: It's a simple main window containing a user control with a data grid showing the data extracted from an SQLite database.
The problem is that this application takes 6 seconds to start until it is usable.

I tried building the user control (and doing all the data loading) in the constructor of the main window:
The splash screen will be shown 5s this way, then followed by 1s of empty main window until the application is ready to be used.
Users said that it takes too long until something (visually) happens.

I then moved the user control creation (and data loading) into the Loaded event handler of the main window: The splash screen will be shown 3s, followed by 3s of empty main window until the application is ready.
Users said that it is "better", but don't like the fact that a half finished main window is shown in disabled state for so long.

Is there some general advice to be found about perceived application load time or are there any other recommendations about how this situation can be improved?
I believe ideally the main window would be shown as fast as possible, along with some hour glass or spinner until the data is loaded. But then I cannot just move the user control creation into a background worker as this would be done on the wrong thread.

Does anybody have any suggestions to this problem?

Edit:
Note that right now I've just assigned a LINQ-to-EF query as the grid data source.
One possible improvement may be to load this data into a data table in background and assign it only once loaded...

Edit2: I'm using .net 4 with System.Data.SQLite and EF4 to load the data. There are more or less 4000 rows and 30 columns.

Marc
  • 9,012
  • 13
  • 57
  • 72
  • How much data are you loading from the database? How are you loading the data - using an ORM (if so, which?) or plain ADO.NET? – alimbada Jan 18 '11 at 13:50
  • Educate the users that a lot is going on. Check out what's really going on and optimize accordingly. A loginscreen, or extended splash (with some wavy animation/progressbar) might be exactly what they are looking for. – CodingBarfield Jan 18 '11 at 13:54
  • @alimbada: I've edited the question to include this information. But it is more a general question than tied to Entity Framework, etc. ADO.NET or any ORM will take its time to load the data, you could also replace this with Thread.Sleep(..). The question is more about how to deal with this kind of situation. – Marc Jan 18 '11 at 13:57

3 Answers3

14

Load your data asynchronous. Present something nice on the GUI for the user while loading. The following code can help you with this:

BackgroundWorker bgWorker = new BackgroundWorker() { WorkerReportsProgress=true};  
bgWorker.DoWork += (s, e) => {      
    // Load here your file/s      
    // Use bgWorker.ReportProgress(); to report the current progress  
};  
bgWorker.ProgressChanged+=(s,e)=>{      
    // Here you will be informed about progress and here it is save to change/show progress. 
    // You can access from here savely a ProgressBars or another control.  
};  
bgWorker.RunWorkerCompleted += (s, e) => {      
// Here you will be informed if the job is done. 
// Use this event to unlock your gui 
};  
bgWorker.RunWorkerAsync();  

The app is not faster but it seems to be much faster because the GUI is immediately visible and responsive. Maybe you also can show the user a part of the loaded data while loading the rest. Use the ProgressChanged-event for doing this.

Update

I'm not sure if I understand your problem right. If your problem is not the time data needs to be loaded, then something is odd in your application. WPF is IMO very fast. Control-creation does not takes a lot of time. I visualize much bigger lists as you mention in some milliseconds.

Try to look if you have something in your UI that hinders the DataGrid to virtualize the Items. Maybe you have a proplem there. To analyse WPF apps, I can recommend you the WPF Profiling Tools.

Conrad Frix
  • 51,984
  • 12
  • 96
  • 155
HCL
  • 36,053
  • 27
  • 163
  • 213
  • Also, this is how Silverlight does it. (Different syntax, the same principle.) – Al Kepp Jan 18 '11 at 13:57
  • Yes, that's how I handled slow operations until now and it worked quite well. The only problem is that before calling bgWorker.RunWorkerAsync() you have to disable the UI as otherwise it may confuse the user. – Marc Jan 18 '11 at 14:00
  • 1
    @Marc: Yes, however maybe you can disable only some parts of the UI, that is a nice experience for the user. As I wrote, if data lies nicely, you also can present the first few records or files loaded and let the user already work with them. But it's clear, all these nice things cost development time and make things more complex. The question is, if the client will pay for it and if it makes sense to incerement project complexity... – HCL Jan 18 '11 at 14:07
  • Spot on. The app is already working, though a bit "slow". Changing it over to some MVVM design, designing nice spinner controls and testing it all again will cost a lot of development time. – Marc Jan 18 '11 at 14:17
  • Thanks for the link to the WPF Profiling Tools, I'll test these as soon as possible. – Marc Jan 18 '11 at 14:34
  • That's the only that worked on my wpf application as an EventAggregator is used during the work. Tried all the task.run, threads, async await implementations and background worker was the only one that didn't freeze the UI. – Damien Aug 31 '22 at 16:36
2

The most obvious thing you can do is to profile your application and find the bottlenecks in start up time. It sounds like the most likely culprit will be the loading of data from your database.

One lesson I've learnt is that if you're using an ORM, when loading large datasets if you favour POCO (Plain Old CLR/C# Objects) over ORM-generated database entities (see example below), the load time will be a lot faster and RAM usage will be significantly decreased too. The reason for this is that EF will try to load the entire entity (i.e. all of it's fields) and possibly a whole load of data related to your entities, most of which you won't even need. The only time you really need to work directly with entities is when you're doing insert/update/delete operations. When reading data you should only get fields that your application needs to display and/or validate.

If you follow the MVVM pattern, the above architecture isn't hard to implement.

Example of loading data into POCOs with EF:

var query = from entity in context.Entities
                select new EntityPoco
                {
                    ID = entity.ID,
                    Name = entity.Name
                };

return query.ToList();

POCOs are very simple classes with autoproperties for each field.

We usually have repositories for each entity in our applications and each repository is responsible for getting/updating data related to that entity. The view models have references to the repositories they need so they don't use EF directly. When users make changes that need to be persisted, we use other methods in the repository that then load only a subset of entities (i.e. the ones the user changed) and apply the necessary updates - with some validation done by the viewmodel and possibly other validation going on in the DB via constraints/triggers, etc.

alimbada
  • 1,392
  • 1
  • 12
  • 27
  • +1 for your recommendations. I did profile the application. It's really more or less 3s app (and framework) initialization which I won't be able to improve. The other 3s are coming from the creation of the user control and the data loading. I also thought about using basic ADO.NET data readers to improve performance. – Marc Jan 18 '11 at 14:13
  • Do you have any good links to MVVM examples which are showing how they handle the data loading in background? What are they doing with the view during the loading? – Marc Jan 18 '11 at 14:13
  • Sorry, I don't have any online examples at hand; it's mostly stuff I learnt from a colleague. I've added my own example and elaborated a bit on my original answer. I can personally vouch that it works, because the application we're currently working on originally took over one and a half minutes to load. It's now down to less than 10 seconds. We're doing between 300k and 400k reads from a SQL Server DB at start up... – alimbada Jan 18 '11 at 14:36
0

There are many reasons for this.

1) Deployment machine might have fairly low configuration.
2) In-Proper or problem with data binding.

Possible solutions would be:
1) Lazy load the data
2) Optimize the performance. http://msdn.microsoft.com/en-us/library/aa970683.aspx

I had saw applications render 5M records less than a second in wpf.

PS:One more least possible reasons may be 30 columns, due to column order access.

Prince Ashitaka
  • 8,623
  • 12
  • 48
  • 71