WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And VB.NET
Good day guys!
Here's the VB.NET version of this article WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET which is a CRUD (Create,Update and Delete) application using the DataGrid control, ADO.NET Entity Framework 6.x and Model–View–Viewmodel(MVVM) architectural pattern. The project structure and the logic were derived from that article except that this application incorporates Visual Basic.NET/VB.NET as the programming language.
2. Create a WPF Project and add four folders called DataAccess, Model, View and ViewModel. The project structure may resemble with the screenshot provided below.
2. For the connectionstring name, I called it as StudentEntities.
3. Next is to add a StudentRecord class that has properties corresponding to the table columns and an ObservableCollection property used as itemsource for the DataGrid. This class inherits the ViewModelBase class added in the ViewModel folder which will mentioned on Coding The ViewModel Classes section so that there's a mechanism in handling property changes and notifications from the controls through data binding.
4. Add a repository class within the DataAccess Folder that performs the CRUD operations towards the Students table in the database.
2. Next is to add a RelayCommand class that implements the ICommand interface. Commands are used for handling events in WPF with regards to the MVVM Architectural Pattern. The sole purpose of a command is to relay or distribute its functionality to other objects by invoking delegates. The default return value for a CanExecute method is true.
3. Last is to create a ViewModel class that performs the command binding of the buttons which then calls specific methods that handles the CRUD operations and updating of property values. An example is the DeleteCommand bound to the Delete button inside the DataGrid control. When the delete button is clicked, the delete command then executes the DeleteStudent() method and deletes the information from the database. That method fetches all records from the database and populates the Observable object which is the ItemSource of the DataGrid.
2. Next is to add several controls like textboxes for accepting input, buttons to trigger events and the DataGrid control to show the entire updated information from the database. These controls have been glued to the ViewModel class through the Binding property. The input controls are grouped in a GroupBox panel, while the Save and Reset buttons are inside the StackPanel container. The DataGrid is also inside the StackPanel container and each of these containers are arranged horizontally inside a StackPanel parent container.
Since most of the examples out there are written in C#.NET, I hope this article will serve as reference for the VB.NET/Visual Basic.NET developers out there.
Output Source Code
Cheers!
Here's the VB.NET version of this article WPF CRUD Application Using DataGrid, MVVM Pattern, Entity Framework, And C#.NET which is a CRUD (Create,Update and Delete) application using the DataGrid control, ADO.NET Entity Framework 6.x and Model–View–Viewmodel(MVVM) architectural pattern. The project structure and the logic were derived from that article except that this application incorporates Visual Basic.NET/VB.NET as the programming language.
I. Project Setup
1. Create a table in your database called Students using the script from this post WPF CRUD With DataGrid, Entity Framework And C#.NET.2. Create a WPF Project and add four folders called DataAccess, Model, View and ViewModel. The project structure may resemble with the screenshot provided below.
II. Coding The Model and Repository Class
1. Inside the Model folder, add an ADO.NET Entity Data Model object that connects to the Students table in your database. On my part, I named it StudentModel.2. For the connectionstring name, I called it as StudentEntities.
3. Next is to add a StudentRecord class that has properties corresponding to the table columns and an ObservableCollection property used as itemsource for the DataGrid. This class inherits the ViewModelBase class added in the ViewModel folder which will mentioned on Coding The ViewModel Classes section so that there's a mechanism in handling property changes and notifications from the controls through data binding.
Imports System.Collections.ObjectModel Imports System.Collections.Specialized Public Class StudentRecord Inherits ViewModelBase Private _id As Integer Public Property Id As Integer Get Return _id End Get Set(ByVal value As Integer) _id = value OnPropertyChanged("Id") End Set End Property Private _name As String Public Property Name As String Get Return _name End Get Set(ByVal value As String) _name = value OnPropertyChanged("Name") End Set End Property Private _age As Integer Public Property Age As Integer Get Return _age End Get Set(ByVal value As Integer) _age = value OnPropertyChanged("Age") End Set End Property Private _address As String Public Property Address As String Get Return _address End Get Set(ByVal value As String) _address = value OnPropertyChanged("Address") End Set End Property Private _contact As String Public Property Contact As String Get Return _contact End Get Set(ByVal value As String) _contact = value OnPropertyChanged("Contact") End Set End Property Private _studentRecords As ObservableCollection(Of StudentRecord) Public Property StudentRecords As ObservableCollection(Of StudentRecord) Get Return _studentRecords End Get Set(ByVal value As ObservableCollection(Of StudentRecord)) _studentRecords = value OnPropertyChanged("StudentRecords") End Set End Property Private Sub StudentModels_CollectionChanged(ByVal sender As Object, ByVal e As NotifyCollectionChangedEventArgs) OnPropertyChanged("StudentRecords") End Sub End Class
Public Class StudentRepository Private studentContext As StudentEntities = Nothing Public Sub New() studentContext = New StudentEntities() End Sub Public Function GetStudent(ByVal id As Integer) As Student Return studentContext.Students.Find(id) End Function Public Function GetAll() As List(Of Student) Return studentContext.Students.ToList() End Function Public Sub AddStudent(ByVal student As Student) If student IsNot Nothing Then studentContext.Students.Add(student) studentContext.SaveChanges() End If End Sub Public Sub UpdateStudent(ByVal student As Student) Dim studentFind = Me.GetStudent(student.ID) If studentFind IsNot Nothing Then studentFind.Name = student.Name studentFind.Contact = student.Contact studentFind.Age = student.Age studentFind.Address = student.Address studentContext.SaveChanges() End If End Sub Public Sub RemoveStudent(ByVal id As Integer) Dim studObj = studentContext.Students.Find(id) If studObj IsNot Nothing Then studentContext.Students.Remove(studObj) studentContext.SaveChanges() End If End Sub End Class
III. Coding The ViewModel Classes
1. Add a ViewModelBase class that implements the INofifyPropertyChanged interface. This interface basically informs binding clients that a property value has been updated. This class is inherited by the StudentRecord model of which it's properties are used in data binding and needed some sort of notification when a property's value has been changed.Imports System.ComponentModel Public Class ViewModelBase : Implements INotifyPropertyChanged Public Event PropertyChanged As PropertyChangedEventHandler _ Implements INotifyPropertyChanged.PropertyChanged Protected Sub OnPropertyChanged(ByVal propertyName As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) End Sub End Class
Imports System.Windows.Input Public Class RelayCommand : Implements ICommand Private ReadOnly _execute As Action(Of Object) Private ReadOnly _canExecute As Predicate(Of Object) Public Sub New(ByVal execute As Action(Of Object)) End Sub Public Sub New(ByVal execute As Action(Of Object), ByVal canExecute As Predicate(Of Object)) If execute Is Nothing Then Throw New ArgumentNullException("execute") _execute = execute _canExecute = canExecute End Sub Public Function CanExecute(ByVal parameter As Object) As Boolean Implements ICommand.CanExecute Return (_canExecute Is Nothing) OrElse _canExecute(parameter) End Function Public Custom Event CanExecuteChanged As EventHandler Implements ICommand.CanExecuteChanged AddHandler(ByVal value As EventHandler) AddHandler CommandManager.RequerySuggested, value End AddHandler RemoveHandler(ByVal value As EventHandler) AddHandler CommandManager.RequerySuggested, value End RemoveHandler RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs) CommandManager.InvalidateRequerySuggested() End RaiseEvent End Event Public Sub Execute(ByVal parameter As Object) Implements ICommand.Execute _execute(parameter) End Sub End Class
Imports System.Collections.ObjectModel Public Class StudentViewModel Private _saveCommand As ICommand Private _resetCommand As ICommand Private _editCommand As ICommand Private _deleteCommand As ICommand Private _repository As StudentRepository Private _studentEntity As Student = Nothing Public Property StudentRecord As StudentRecord Public Property StudentEntities As StudentEntities Public ReadOnly Property ResetCommand As ICommand Get If _resetCommand Is Nothing Then _resetCommand = New RelayCommand(AddressOf ResetData, Nothing) End If Return _resetCommand End Get End Property Public ReadOnly Property SaveCommand As ICommand Get If _saveCommand Is Nothing Then _saveCommand = New RelayCommand(AddressOf SaveData, Nothing) End If Return _saveCommand End Get End Property Public ReadOnly Property EditCommand As ICommand Get If _editCommand Is Nothing Then _editCommand = New RelayCommand(AddressOf EditData, Nothing) End If Return _editCommand End Get End Property Public ReadOnly Property DeleteCommand As ICommand Get If _deleteCommand Is Nothing Then _deleteCommand = New RelayCommand(AddressOf DeleteStudent, Nothing) End If Return _deleteCommand End Get End Property Public Sub New() _studentEntity = New Student() _repository = New StudentRepository() StudentRecord = New StudentRecord() GetAll() End Sub Public Sub ResetData() StudentRecord.Name = String.Empty StudentRecord.Id = 0 StudentRecord.Address = String.Empty StudentRecord.Contact = String.Empty StudentRecord.Age = 0 End Sub Public Sub DeleteStudent(ByVal id As Integer) If MessageBox.Show("Confirm delete of this record?", "Student", MessageBoxButton.YesNo) = MessageBoxResult.Yes Then Try _repository.RemoveStudent(id) MessageBox.Show("Record successfully deleted.") Catch ex As Exception MessageBox.Show("Error occured while saving. " & ex.InnerException.Message) Finally GetAll() End Try End If End Sub Public Sub SaveData() If StudentRecord IsNot Nothing Then _studentEntity.Name = StudentRecord.Name _studentEntity.Age = StudentRecord.Age _studentEntity.Address = StudentRecord.Address _studentEntity.Contact = StudentRecord.Contact Try If StudentRecord.Id <= 0 Then _repository.AddStudent(_studentEntity) MessageBox.Show("New record successfully saved.") Else _studentEntity.ID = StudentRecord.Id _repository.UpdateStudent(_studentEntity) MessageBox.Show("Record successfully updated.") End If Catch ex As Exception MessageBox.Show("Error occured while saving. " & ex.InnerException.Message) Finally GetAll() ResetData() End Try End If End Sub Public Sub EditData(ByVal id As Integer) Dim model = _repository.GetStudent(id) StudentRecord.Id = model.ID StudentRecord.Name = model.Name StudentRecord.Age = CInt(model.Age) StudentRecord.Address = model.Address StudentRecord.Contact = model.Contact End Sub Public Sub GetAll() StudentRecord.StudentRecords = New ObservableCollection(Of StudentRecord)() Dim records As New List(Of Student) records = _repository.GetAll() For Each record As Student In records Dim item As New StudentRecord item.ID = record.ID item.Name = record.Name item.Address = record.Address item.Age = Convert.ToInt32(record.Age) item.Contact = record.Contact StudentRecord.StudentRecords.Add(item) Next End Sub End Class
IV. Databinding and View
1. Move the MainWindow page into the View folder of the project. In the constructor method , set the class DataContext with the StudentViewModel class. You may opt to set the DataContext through XAML.Class MainWindow Public Sub New() ' This call is required by the designer. InitializeComponent() ' Add any initialization after the InitializeComponent() call. Me.DataContext = New StudentViewModel() End Sub End Class
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:MVVMDemoVB" mc:Ignorable="d" Title="Basic Create Update Delete With MVVM In VB.NET" Height="500" Width="600"> <StackPanel Orientation="Vertical"> <GroupBox Header="Student Form" Margin="10"> <Grid Height="150"> <Grid.RowDefinitions> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> <RowDefinition Height="1*"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <Label Content="Name" HorizontalAlignment="Left" VerticalContentAlignment="Center" Grid.Column="0" Grid.Row="0"/> <TextBox Grid.Row="0" Grid.Column="1" x:Name="TextBoxName" Height="27" Text="{Binding Path=StudentRecord.Name, Mode=TwoWay}" Margin="5" Width="300" HorizontalAlignment="Left"/> <Label Content="Age" HorizontalAlignment="Left" VerticalContentAlignment="Center" Grid.Row="1" Grid.Column="0"/> <TextBox Grid.Row="1" Grid.Column="1" x:Name="TextBoxAge" Height="27" Text="{Binding Path=StudentRecord.Age, Mode=TwoWay}" Margin="5" Width="70" HorizontalAlignment="Left"/> <TextBlock Grid.Row="1" Grid.Column="1" x:Name="TextBlockId" Visibility="Hidden" Text="{Binding Path=StudentRecord.Id, Mode=TwoWay}"/> <Label Content="Address" HorizontalAlignment="Left" VerticalContentAlignment="Center" Grid.Row="2" Grid.Column="0" /> <TextBox Grid.Row="2" Grid.Column="1" x:Name="TextBoxAddress" Height="27" Text="{Binding Path=StudentRecord.Address, Mode=TwoWay}" Margin="5" Width="300" HorizontalAlignment="Left"/> <Label Content="Contact" HorizontalAlignment="Left" VerticalContentAlignment="Center" Grid.Row="3" Grid.Column="0" /> <TextBox Grid.Row="3" Grid.Column="1" x:Name="TextBoxContact" Height="27" Text="{Binding Path=StudentRecord.Contact, Mode=TwoWay}" Margin="5" Width="300" HorizontalAlignment="Left"/> </Grid> </GroupBox> <StackPanel Height="40" Orientation="Horizontal" HorizontalAlignment="Right"> <Button x:Name="ButtonSave" Content="Save" Height="30" Width="80" Command="{Binding SaveCommand}"/> <Button x:Name="ButtonCancel" Content="Cancel" Height="30" Width="80" Command="{Binding ResetCommand}" Margin="5,0,10,0"/> </StackPanel> <StackPanel Height="210"> <DataGrid x:Name="DataGridStudents" AutoGenerateColumns="False" ItemsSource="{Binding StudentRecord.StudentRecords}" CanUserAddRows="False" Height="200" Margin="10"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Path=Id}" Visibility="Hidden"/> <DataGridTextColumn Header="Name" Binding="{Binding Path=Name}" Width="100" IsReadOnly="True"/> <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}" Width="50" IsReadOnly="True"/> <DataGridTextColumn Header="Address" Binding="{Binding Path=Address}" Width="180" IsReadOnly="True"/> <DataGridTextColumn Header="Contact" Binding="{Binding Path=Contact}" Width="125" IsReadOnly="True"/> <DataGridTemplateColumn Width="50"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="Select" x:Name="ButtonEdit" CommandParameter="{Binding Path=Id}" Command="{Binding Path=DataContext.EditCommand,RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> <DataGridTemplateColumn Width="50"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <Button Content="Delete" x:Name="ButtonDelete" CommandParameter="{Binding Path=Id}" Command="{Binding Path=DataContext.DeleteCommand, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}"/> </DataTemplate> </DataGridTemplateColumn.CellTemplate> </DataGridTemplateColumn> </DataGrid.Columns> </DataGrid> </StackPanel> </StackPanel> </Window>
Output Source Code
Finally, I have the spare time to create a code sample for this blog post. You may now download the project written in Visual Studio 2022 at my Github Page.
Cheers!
Comments
Post a Comment