0

I have a simple C# MVVM WPF Application where I have a MainWindow holding a Ribbon and a ContentControl. Based on Ribbon Actions i switch to different UserControls and show the in the ContentControl.

To load data inside the ViewModel i basically do this:

public class ProductsViewModel : BaseViewModel
{
    public CollectionViewSource ProductsCollection { get; private set; }
    private MyDataContext _ctx;

    public ProductsViewModel ()
    {
        ProductsCollection = new CollectionViewSource();
        _ctx = new MyDataContext();

        Load()
    }

    public void Load()
    {
        _ctx.Products.Load();
        ProductsCollection.Source = _ctx.Products.Local;
    }
}

Now the LoadMethod is called everytime i show the UserControl with this ViewModel as DataContext.

Is there any way to avoid this? Because _ctx.Products.Load()takes some serious time (for 11K Records) and accessing the ObservableCollection with _ctx.Products.Localis very slow too.

I like working with a DataContext for every UserControl and the .LocalCollection as it's easy to keep UI in Sync with the Database. But if there is a better approach just let me know.

I am very new to EF and MVVM/WPF so every help is greatly appreciated!

P.S.: I am using EF 6, Database First with SQL Server 2014

CeOnSql
  • 2,615
  • 1
  • 16
  • 38
  • First question is: why load all records? – Gert Arnold Jul 04 '16 at 20:50
  • because i have a DataGrid, where the user can edit records, and there is at least no easy solution for implementing paging in a WPF DataGrid afaik... – CeOnSql Jul 05 '16 at 06:13
  • There are several ways to increase performance but it depends on your application's logic. You could add some filters to your data retrieval or you could put the data retrieval on a higher level (e.g. on the root of your page instead of a user control, making it some kind of static/singleton). Just another detail: I don't think it's necessary that you call the .Load() method on the DbContext Set instance. Also: can you show us your Entity Framework configuration (lazy loading for instance) – hbulens Jul 05 '16 at 08:31
  • It is necessary to call .Load() method! I did not change any EF configuration at all, since i used database first lazy loading should be enabled by default!? – CeOnSql Jul 05 '16 at 08:49

1 Answers1

0

Since you mentioned this is a ‘simple’ desktop application, there’s a chance you are creating an app that edits data by a single user. If that’s your intention, allow me to suggest an alternative to MVVM. MVVM is a very good architecture, but might be over-kill for simple desktop applications.

Here’s an alternative solution I use that works very well for a single-user app using EF Database First:

Use a single DBContext for your main window, and all UserControls, and have a single “Save” button/menu item to commit all changes. You can also check for changes when the user tries to exit and prompt for saving first. Also, if your objects implement INotifyPropertyChange and ObservableCollections, your changes in one location are reflected elsewhere in your app. There are various ways to make this DBContext available throughout your application, such as using a Singleton pattern, or simply creating a static class and placing it in there (as a public static member). Then have all controls use this instance.

As for implementing INotifyPropertyChange and ObservableCollections, you have two options: Option 1) Implement it using Database first with EntityFramework 4. This creates object inheriting from EntityObject, which implement INotifyPropertyChange. Also, associations are implemented as EntityCollections, which implement AssociationChanged. All of these are useful for simple WPF applications. You can bind your data directly to controls. This is a very simple way to create a nicely fully functional single-user desktop app. This is what I’ve done in an app I use almost daily.

Option 2) Implement with EF 6 DB first, but with modifications to support INotifyPropertyChange and ObservableCollections. By default, EF 6 creates POCO (plain old CLR objects) that are not by default very observable. However, the creation process can be modified in order to implement these. The KEY to this is to modify the T4 template, which is done by modifying the {yourmodelname}.tt file. I recently did this on my EF4-based application and it’s been working well. Here are the steps to do that:

Locate your {modelname}.tt file, make a back-up of it.

Updating the .tt to add INotifyPropertyChange. See: naskew's answer here: Using INotifyPropertyChanged with Entity Framework 6 DbContext Generator,

Updating the .tt to use ObservableCollections instead of HashSets: See: Kolya Evdokimov's answer here: How can I change an Entity Framework ICollection to be an ObservableCollection?, With one change: in NavigationProperty function of the .tt, change the ICollection to ObservableCollection

After changing the .tt, right click on the .tt file and select Run Custom Tool.
Once this is complete, your created EF classes will implement INotifyPropertyChange, and have ObservableCollections for associations. These should be ready for implementing DataBinding on WPF controls. Changes in one UserControl are reflected elsewhere in your application since the underlying model uses INotifyPropertyChange and ObservableCollections

I'd paste my .tt file here for you but it was too large.

Community
  • 1
  • 1
RunzWitScissors
  • 128
  • 1
  • 8