Click here to Skip to main content
15,867,686 members
Articles / Desktop Programming / WPF
Article

Tutorial for a Basic WPF – MVVM Project Using Entity Framework

Rate me:
Please Sign up or sign in to vote.
4.92/5 (21 votes)
6 Feb 2015CPOL7 min read 133.6K   9.2K   53   15
I decided to create my own sample project which connects to a named server (anSQL 2008 R2 server on my local machine – will also work on SQL Server 2012Express

Introduction

I have been searching for a basic WPF – MVVM sample project that uses Entity Framework (EF). I found a few projects that combine EF with WCF, and I even found one WPF – MVVM project that used EF directly, but connected to LocalDB and was not basic. When I tried modifying the connection string to a named SQL Server, the project error'd out. After not having any luck finding the kind of basic sample WPF-MVVM project using Entity Framework, I decided to create my own sample project which connects to a named server (an SQL 2008 R2 server on my local machine – will also work on SQL Server 2012 Express). The target audience for this article will ideally have a background in SQL Server programming with TSQL, C# programming, and Visual Studio 2010 (or higher), and .NET Framework 4.0 (or higher).

This sample project is a three-tier project with a Data layer, Business layer, and Presentation layer and consists of the following – two comboboxes, one textbox (in MainWindow.xaml), one ADO.NET Entity Model which contains two tables (Author and Book), and one ViewModel – MainWindowViewModel.cs. This sample was created in Visual Studio 2012 on a Windows 7 workstation, but it can also be created in VS2010.

On project startup, MainWindowViewModel will populate the Author table entity which is the datasource for the first combobox (call it combo1 for shorthand). Upon selecting an Author item from combo1, the second combobox (call it combo2) gets populated with the related rows from the Book table entity, and on selecting a book item from combo2, the content of the Description field for that book will be displayed in the textbox.

First I create two data tables in a database (any database) on a named SQL Server, which this SQL Server happens to reside on my Win7 workstation – SQL Server 2008 R2 (this project will also work with SQL Server 2012 Express). The tables are Author (the Master table) and Book (the Detail table). These two tables are related with a PK-FK constraint.

Here is the SQL code for creating the tables – which will be the Model part of the project.

SQL
create table Author (AuthorId int primary key, AuthorName nvarchar(50))
 
create table Book (BookId int primary key, AuthorId int, Title nvarchar(50), Description nvarchar(200), Price money)
 
alter table Book add constraint FK_Book_Author foreign key (AuthorId) references Author (AuthorId)
 
insert into Author values (1, 'Gambardella, Matthew')
insert into Author values (2, 'Ralls, Kim')
insert into Author values (3, 'Corets, Eva')
 
insert into Book values (1, 1, 'XML Developers Guide', 'An in-depth look at creating applications with XML.', 4.95)
 
insert into Book values (2, 1, 'Foods of the world.', 'Simply a book about food.',  5.95)
 
insert into Book values (3, 1, 'Cars', 'A book about cars.',  8.95)
 
insert into Book values (4, 2, 'Scarecrows', 'This be could horror or agriculture.', 4.15)
 
insert into Book values (5, 3, 'Book of blue', 'First in a series of books about colors',  6.30)
 
insert into Book values (6, 3, 'EF', 'Some tips and trics on Entity Frameworks',  3.45)

Next, I create a new (standard) WPF project from Visual Studio. I named my project Wpf_EF_Mvvm_sample (for anyone who would like to copy the code directly – the project can be named anything – just changed the namespaces in the code). From here I first add an ADO.NET Entity Model (will work with either EF5 or EF6, I tried both of them). This entity model will serve as the Model for the Model-View-ViewModel pattern. I name the .edmx "AuthorBook". I use the wizard to "Generate from Database" and select the respective server that contains the database where I created the two tables. I name the Entity Context "AuthorBookEntities". Click next and select the two tables, Author and Book. Then I change the model name (below in the same dialog window where the tables were selected) to AuthorBookModel and click OK. The Entity Model is now generated. This is the Data layer. This entity model will use DBContext.

Next I add a MainWindowViewModel.cs class to the project. I add this directly to the root folder of the project (same folder as MainWindow.xaml. The idea is to keep this basic.

In MainWindowViewModel I add a using System.ComponentModel directive for the INotifyPropertyChanged interface that we will need to implement so we can use properties to perform the operations. I also add a using System.Runtime.Compilerservices directive for the [CallerMemberName] tag which is used the the NotifyPropertyChanged method of the INotifyPropertyChanged implementation. This is a very nice feature because it eliminates the need to include the property names on the calls to NotifyPropertyChanged() in the MainWindowViewModel properties (formerly NotifyPropertyChanged("somePropertyName");).

The only source code for the project will be contained in MainWindowViewModel.cs. This is the Business tier (or Business layer). Here is the source code.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
using System.Runtime.CompilerServices;
 
namespace Wpf_EF_Mvvm_sample
{
    class MainWindowViewModel : INotifyPropertyChanged
    {
        AuthorBookEntities ctx = new AuthorBookEntities();
 
        public MainWindowViewModel()
        {
            FillAuthors();
        }
 
        private void FillAuthors()
        {
            var q = (from a in ctx.Authors
                     select a).ToList();
            this.Authors = q;
        }
 
        private List<Author> _authors;
        public List<Author> Authors
        {
            get
            {
                return _authors;
            }
            set
            {
                _authors = value;
                NotifyPropertyChanged();
            }
        }
 
        private Author _selectedAuthor;
        public Author SelectedAuthor
        {
            get
            {
                return _selectedAuthor;
            }
            set
            {
                _selectedAuthor = value;
                NotifyPropertyChanged();
                FillBook();
            }
        }
 
        private void FillBook()
        {
            Author author = this.SelectedAuthor;
 
            var q = (from book in ctx.Books
                     orderby book.Title
                     where book.AuthorId == author.AuthorId
                     select book).ToList();
 
            this.Books = q;
        }
 
        private List<Book> _books;
        public List<Book> Books
        {
            get
            {
                return _books;
            }
            set
            {
                _books = value;
                NotifyPropertyChanged();
            }
        }
 
        private Book _selectedBook;
        public Book SelectedBook
        {
            get
            {
                return _selectedBook;
            }
            set
            {
                _selectedBook = value;
                NotifyPropertyChanged();
            }
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

One other nice feature of VS2012 (of the many nice features) – you can place the mouse cursor in any of the using statements at the top of the MainWindowViewModel class file and right-click. Select "Organize Usings" 2nd option from the top of the dropdown, then select "Remove unused usings". This helps to clean up clutter.

In the MainWindowViewModel class I first create a context object

C#
AuthorBookEntities ctx = new AuthorBookEntities();

Then in the constructor I load up the first entity/list (Authors) with the FillAuthors() method. Note the LINQ here – it needs to be a list because a DBSet cannot be consumed directly by a control, and this is the data source for a List property – Authors – which the ItemSource property of combo1 will be bound to in the XAML. The SelectedItem property of combo1 (in the XAML) will be bound to the SelectedAuthor property in MainWindowViewModel. When this property gets invoked, the FillBook method will be called, and the related books for the selected author will populate the Books list property which the ItemSource property for to which combo2 will be bound.

Now combo1 and comb2 are populated. The real cool part is when an item is selected from the SelectedItem property of comobo2 which is bound to the SelectedBook property. The SelectedBook property will contain only one row from the Books list. The Text property of the textbox will be bound to the SelectedBook.Description property, so when an item is selected from combo2 the content of the Description field from the selected Book row will automatically appear in the textbox. Note: this could introduce a slight dependency on the field names of the Book table using this technique. One workaround for this situation would be to create a method for retrieving the Description value of the selected Book object, and then create a property for the textbox to bind to that would be passed the Description value.

The MainWindowViewModel is the Business layer.

The third tier of this project, the Presentation layer, will be MainWindow.xaml, which is the view. MainWindow.xaml will contain all the XAML that will bind to the properties in MainWindowViewModel. But before we hook up the XAML, we need to compile what we have so far so that the project assembly is created and thus create a DataContext to be consumed by MainWindow.xaml.

Note that the project can be compiled with no presentation layer. This is an example of "separation of concerns" which is the core concept of the MVVM pattern. In WinForms you would attach a bunch of code to the events of the controls on the form. If you happen to delete/remove a control from the form – the project would not compile. This is an example of the tightly coupled paradigm of WinForms programming. The MVVM pattern resolves this issue by separating the code from the UI and using Binding and commands to interact between the UI and the code (the Business layer).

After compiling the project, we have an assembly that the MainWindow (the view) can bind to. First I add a reference to the location where MainWindowViewModel resides (which is the root folder). We add this line to the MainWindow.xaml header section

XML
xmlns:vm="clr-namespace:Wpf_EF_Mvvm_sample"

Then we add the data context

XML
<Window.DataContext>
    <vm:MainWindowViewModel />
</Window.DataContext>

This could also be done in the code behind (MainWindow.xaml.cs). I’m just being a purist here keeping the code behind MainWindow.xaml.cs clear of any code that wasn’t there by default.

Here is the XAML for the Presentation layer which is the View (the 3rd tier of this three tier project).

<Window x:Class="Wpf_EF_Mvvm_sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:Wpf_EF_Mvvm_sample"
        Title="MainWindow" Height="350" Width="525">
   
    <Window.DataContext>
        <vm:MainWindowViewModel />
    </Window.DataContext>
   
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="180" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="25" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
 
        <ComboBox DisplayMemberPath="AuthorName" ItemsSource="{Binding Authors}"
                      Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="1" Name="combo1" SelectedItem="{Binding SelectedAuthor}" />
 
        <ComboBox DisplayMemberPath="Title" ItemsSource="{Binding Books}"
                      Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="1" Name="combo2" SelectedItem="{Binding SelectedBook}" />
        <TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Name="tbDesc" Text="{Binding SelectedBook.Description}"/>
    </Grid>
</Window>

Conclusion

I have presented a basic three tier project that contains a Data layer, Business layer, and Presentation layer, the Model, the ViewModel, and the View. The Model is composed of an ADO.NET Entity Model, the ViewModel is composed of the MainWindowViewModel class, and the View is composed of the MainWindow.xaml. Hopefully, this sample project will provide some enlightenment for those seeking an easy to follow/understand WPF-MVVM project using Entity Framework.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
PraiseSuper tutorial Pin
Member 140089679-Oct-18 6:30
Member 140089679-Oct-18 6:30 
PraiseJust what I was looking for! Pin
DPrimetime11-Jan-18 8:23
DPrimetime11-Jan-18 8:23 
QuestionError on this.Authors = q; Pin
Member 111505778-Jan-18 20:32
Member 111505778-Jan-18 20:32 
QuestionNo Connection String error in the MainWindow.xaml data context Pin
Les Williams11-Jul-16 3:41
Les Williams11-Jul-16 3:41 
AnswerRe: No Connection String error in the MainWindow.xaml data context Pin
Anders Eriksson16-Nov-16 5:03
Anders Eriksson16-Nov-16 5:03 
QuestionI am starting with mvvm can you add to this proyect "Icommand" class example Pin
Richard Aguirre2-Apr-16 15:24
Richard Aguirre2-Apr-16 15:24 
PraiseVery good tutorial explanation Pin
Richard Aguirre2-Apr-16 15:03
Richard Aguirre2-Apr-16 15:03 
QuestionStoring computed fields in MVVM Pin
Alexey Popov23-Dec-15 13:53
Alexey Popov23-Dec-15 13:53 
AnswerRe: Storing computed fields in MVVM Pin
Botizan_Ionut10-Feb-16 4:08
Botizan_Ionut10-Feb-16 4:08 
QuestionComsider the following things Pin
nullptr_exception4-Apr-15 5:19
nullptr_exception4-Apr-15 5:19 
AnswerRe: Comsider the following things Pin
Richard Protzel4-Apr-15 13:28
Richard Protzel4-Apr-15 13:28 
QuestionFile is missing Pin
taichay24-Feb-15 0:59
taichay24-Feb-15 0:59 
AnswerRe: File is missing Pin
Richard Protzel24-Feb-15 8:39
Richard Protzel24-Feb-15 8:39 
Greetings, I just clicked on the download link, and it worked for me. The zip file downloaded correctly. I posted all the source code. There is only a MainWindowViewModel.cs class and a MainWindow.xaml file. Create at new WPF project and copy/paste all the source code. The only thing you have to do is to add the Entity yourself (of course, that is done for you in the .zip project download). To add the Entity, just right-click on the project (not the solution) in the solution explorer, go to Add, go to Data, select Ado.Net Entity Model. Name it AuthorBook.edmx. In the wizard, name the connection string AuthorBookEntities. Then in the last page of the wizard, at the bottom name the model AuthorBookModel. That's it.
QuestionToList() Pin
Frank W. Wu11-Feb-15 6:53
Frank W. Wu11-Feb-15 6:53 
AnswerRe: ToList() Pin
Richard Protzel11-Feb-15 9:58
Richard Protzel11-Feb-15 9:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.