Entity Framework and Windows Presentation Foundation Walk Through

Entity Framework

The first thing to do is get the Database Model going:

  1. Fire up Visual Studio 2012
  2. Create a new project called EF_WPF_Example, Select Windows, WPF project type.
  3. If the Data Sources side bar (windows) is not visible Press Shift+Alt+D
  4. Click Add New Data Sources and in the wizard...
    1. Click Database, Next
    2. Entity Data Model, Next
    3. Generate from database, Next
    4. Click New Connection...
    5. Give your server name and click on the drop down under "Select or enter a database name"
    6. Select the University Database Example that we have been working on.
    7. Test the connection to make sure that it works, then click OK
    8. Make a special note of the connection string name, Click next
    9. Under tables place check marks next to "advisor", "instructor", "student" and notice the Model Namespace (Mine was UniversityExampleModel), Click Finish.

Your file should now look like this:

EFModel.png

One last thing: Rename the file to be UniversityModel (I just don't like Model1.edmx).


WPF View Part (1)

Now we will build the GUI (You could do this in Blend too, but I'm going to use Visual Studio 2012).

  1. Make sure the toolbox is visible.
  2. Add two Label and two TextBox objects on the screen, one DataGrid and three buttons so that it looks like the following (Don't worry about the Binding yet though!):

XAML_View.png


Creating the View Model (MVVM)

There are two parts to the view model. First you need to create a class that implements ICommand. I'm using a rather standard way of doing this called a DelegateCommand. This paradigm allows you to use the same ICommand object over and over again without having to write custom code into each one. The primary methods are there and we do some house keeping based on those methods. I'll be happy to explain how this works if you don't understand (or you can watch the video).

   1 using System;
   2 using System.Collections.Generic;
   3 using System.Linq;
   4 using System.Text;
   5 using System.Threading.Tasks;
   6 using System.Windows.Input;
   7 
   8 namespace EF_WPF_Example
   9 {
  10     class DelegateCommand : ICommand
  11     {
  12         private readonly Predicate<object> _canExecute;
  13         private readonly Action<object> _execute;
  14         private bool flagExecutable = false;
  15 
  16         public event EventHandler CanExecuteChanged;
  17 
  18         public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
  19         {
  20             _execute = execute;
  21             _canExecute = canExecute;
  22         }
  23 
  24         public bool CanExecute(object parameter)
  25         {
  26             bool flag = _canExecute == null || _canExecute(parameter);
  27             if (flagExecutable != flag)
  28             {
  29                 flagExecutable = !flagExecutable;
  30                 RaiseCanExecuteChanged();
  31             }
  32             return flag;
  33         }
  34 
  35         public void Execute(object parameter)
  36         {
  37             _execute(parameter);
  38         }
  39 
  40         public void RaiseCanExecuteChanged()
  41         {
  42             if (CanExecuteChanged != null)
  43             {
  44                 CanExecuteChanged(this, EventArgs.Empty);
  45             }
  46         }
  47     }
  48 }

The second part is the actual View model itself:

   1 using System.Collections.Generic;
   2 using System.ComponentModel;
   3 using System.Linq;
   4 using EF_WPF_Example.Annotations;
   5 
   6 namespace EF_WPF_Example
   7 {
   8     class MainViewModel : INotifyPropertyChanged
   9     {
  10         private readonly UniversityExampleEntities _context = new UniversityExampleEntities();
  11         private readonly List<student> _students;
  12         private readonly DelegateCommand _prev;
  13         private readonly DelegateCommand _next;
  14         private readonly DelegateCommand _save;
  15 
  16 
  17         private int _index;
  18         private readonly int _maxIndex;
  19 
  20         public string Name
  21         {
  22             get { return _students[_index].name; } 
  23             set
  24             {
  25                 _students[_index].name = value;
  26                 OnPropertyChanged("Name");
  27             }
  28         }
  29 
  30         public string Department
  31         {
  32             get { return _students[_index].dept_name; }
  33             set
  34             {
  35                 _students[_index].dept_name = value;
  36                 OnPropertyChanged("Department");
  37             }
  38         }
  39 
  40         public List<take> Classes
  41         {
  42             get { return _students[_index].takes.ToList(); }
  43         }
  44 
  45         public DelegateCommand Prev
  46         {
  47             get { return _prev; }
  48         }
  49 
  50         public DelegateCommand Next
  51         {
  52             get { return _next; }
  53         }
  54 
  55         public DelegateCommand Save
  56         {
  57             get { return _save; }
  58         }
  59 
  60         public MainViewModel()
  61         {
  62             _students = _context.students.Include("takes").ToList();
  63             _index = 0;
  64             _maxIndex = _students.Count() - 1; 
  65             _next = new DelegateCommand(MoveNext, x=>_index < _maxIndex);
  66             _prev = new DelegateCommand(MovePrev, x=>_index > 0);
  67             _save = new DelegateCommand(x=>_context.SaveChanges(), x=>true);
  68         }
  69 
  70         private void MoveNext(object o)
  71         {
  72                 _index++;
  73                 NotifyAll();
  74                 Prev.CanExecute(null);
  75                 Next.CanExecute(null);
  76         }
  77 
  78         private void MovePrev(object o)
  79         {
  80                 _index--;
  81                 NotifyAll();
  82                 Prev.CanExecute(null);
  83                 Next.CanExecute(null);
  84         }
  85 
  86         private void NotifyAll()
  87         {
  88             if (PropertyChanged != null)
  89             {
  90                 PropertyChanged(this, new PropertyChangedEventArgs("Name"));
  91                 PropertyChanged(this, new PropertyChangedEventArgs("Department"));
  92                 PropertyChanged(this, new PropertyChangedEventArgs("Classes"));
  93                 PropertyChanged(this, new PropertyChangedEventArgs("Next"));
  94                 PropertyChanged(this, new PropertyChangedEventArgs("Prev"));
  95                 PropertyChanged(this, new PropertyChangedEventArgs("Save"));
  96             }
  97         }
  98 
  99         public event PropertyChangedEventHandler PropertyChanged;
 100 
 101         [NotifyPropertyChangedInvocator]
 102         protected virtual void OnPropertyChanged(string property)
 103         {
 104             if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(property));
 105         }
 106     }
 107 }

Now that we have a view model that works (make sure that you have compiled it and that it does compile). We are ready to go back and tie the View to the View Model.


WPF View Part 2

Below is the completed Xaml code. Pay particular attention to the way in which the xmlns, "my" is added to the xaml. The Window.DataContext defines the View Model that this View will attempt to create when you bring up the view. The different Binding attributes map to properties of the View Model identified.

<Window x:Class="EF_WPF_Example.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:my="clr-namespace:EF_WPF_Example"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <my:MainViewModel />
    </Window.DataContext>
    <Grid>
        <Label Content="Name:" HorizontalAlignment="Left" Margin="0,10,0,0" VerticalAlignment="Top"/>
        <Label Content="Department:" HorizontalAlignment="Left" Margin="189,10,0,0" VerticalAlignment="Top"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="49,13,0,0" TextWrapping="Wrap" Text="{Binding Name}" VerticalAlignment="Top" Width="120"/>
        <TextBox HorizontalAlignment="Left" Height="23" Margin="270,13,0,0" TextWrapping="Wrap" Text="{Binding Department}" VerticalAlignment="Top" Width="120"/>
        <Button Content="&lt;" HorizontalAlignment="Left" Margin="408,14,0,0" VerticalAlignment="Top" Width="22" Command="{Binding Prev}"/>
        <Button Content="&gt;" HorizontalAlignment="Left" Margin="439,14,0,0" VerticalAlignment="Top" Width="22" Command="{Binding Next}"/>
        <DataGrid Margin="10,41,0,0" VerticalAlignment="Top" HorizontalAlignment="Left" 
                  AutoGenerateColumns="False"
                  ItemsSource="{Binding Classes}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding year}" Header="Year" />
                <DataGridTextColumn Binding="{Binding semester}" Header="Semester" />
                <DataGridTextColumn Binding="{Binding course_id}" Header="Course ID" />
                <DataGridTextColumn Binding="{Binding sec_id}" Header="Section ID" />
            </DataGrid.Columns>
        </DataGrid>
        <Button Content="Save" HorizontalAlignment="Left" Margin="466,14,0,0" VerticalAlignment="Top" Width="41" Command="{Binding Save}"/>
    </Grid>
</Window>

Note: In the video, I think I left out the part where I added the Save binding for the Save button. Make sure you get that in there.

EF_WPF_Example.zip

DatabaseManagementSystems/EntityFrameworkWpfExample (last edited 2013-02-15 18:58:39 by embsys-tekscope-2)