Matthis Kohli Matthis Kohli - 1 year ago 66
C# Question

How do I fill a ListView from a data base using the MVVM pattern?

How do I fill a ListView from a data base using the MVVM pattern? I prefer the EntityFramework but currently I am doing this with a SQLAdapter so I would already be happy with a working solution.

I have a class libary which I call Models. This libary contains a class called ProjectCompletedModel.vb

Public Class ProjectCompletedModel

' Read this article if the Auto-Implemented Properties do not match your needs:

''' <summary>
''' Get or set the project number.
''' </summary>
''' <value>Set the BE-N°</value>
''' <returns>Get the BE-N°</returns>
''' <remarks></remarks>
Public Property ProjectNumber As String

''' <summary>
''' Get or set the project name.
''' </summary>
''' <value>Set the project name</value>
''' <returns>Get the project name</returns>
''' <remarks></remarks>
Public Property ProjectName As String

''' <summary>
''' Get or set the customer name.
''' </summary>
''' <value>Set the customer name</value>
''' <returns>Get the customer name</returns>
''' <remarks></remarks>
Public Property CustomerName As String
End Class

Next I have a class libary ViewModels. It contains the class ProjectCompletedViewModel.vb

Imports System.Collections.ObjectModel

Public Class ProjectCompletedViewModel

Private projCompleted As New Models.ProjectCompletedModel

Public Property Projects As ObservableCollection(Of Models.ProjectCompletedModel)

Public Property ProjectNumber As String
Return Me.projCompleted.ProjectNumber
End Get
Set(value As String)
Me.projCompleted.ProjectNumber = value
End Set
End Property

Public Property ProjectName As String
Return Me.projCompleted.ProjectName
End Get
Set(value As String)
Me.projCompleted.ProjectName = value
End Set
End Property

Public Property CustomerName As String
Return Me.projCompleted.CustomerName
End Get
Set(value As String)
Me.projCompleted.CustomerName = value
End Set
End Property
End Class

The code for my view is the folowing:

<UserControl x:Class="ProjectCompletedView"
d:designheight="400" d:designwidth="400" Background="#D7E4F2" d:DesignWidth="918" d:DesignHeight="478"

<vm:ProjectCompletedViewModel x:Key="projComplObj"/>


<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
<RowDefinition Height="1*"/>
<RowDefinition Height="3*"/>

<ListView x:Name="lvProjects" Grid.ColumnSpan="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="0,52,0,0" Grid.RowSpan="2">

<!-- Define the column names -->
<GridViewColumn Header="ProjectNumber" Width="100" DisplayMemberBinding="{Binding ProjectNumber}"/>
<GridViewColumn Header="ProjectName" Width="100" DisplayMemberBinding="{Binding ProjectName}"/>
<GridViewColumn Header="Customer" Width="100" DisplayMemberBinding="{Binding CustomerName}"/>

It leads to following design by adding some hard coded values in the constructor of the .xaml.vb file.

Me.lvProjects.Items.Add(New ViewModels.ProjectCompletedViewModel() With {.ProjectNumber = "0123456",
.ProjectName = "Alpha",
.CustomerName = "AlphaCustomer"})


The goal is to group customers or any column that's why I want to work with a ListView. Never mind about the grouping I already have the code for that my first issue is loading the ListView from the DataBase with MVVM.

My application has a reference to ViewModels. ViewModels has a reference to Models.

Looks like this:


I am able to fill the ListView with CodeBehind by generating a DataTable and assigning the DataTable.DefaultView to the ListView.ItemSource. By using the "DisplayMemberBinding={Binding TableName}" option I can display my data very fast and easy. But I want to keep it reusable and maintainable. => MVVM.

Answer Source

You got a good start for MVVM. One thing that you should understand is the concept of DataContext and DataBinding for WPF.

For reusability, I commonly use DataBinding of the View (you could bind your ViewModel to controls, but I prefer to use a ViewModel for the view containing ViewModels for controls…)

In the code behind of the view, I use the DataContext to give a context for my view. The ViewModel contains the ObservableCollections that will be bound.

// C#
base.DataContext = ViewModel;
// VB.Net
Me.DataContext = ViewModel;

I guess that you already have a binding since you have


Following this View-ViewModel binding, I can give a Binding to my ListView!

<ListView ItemsSource="{Binding MyJokers}"
    [...] />

MyJokers is actually the name of my Property in my ViewModel (note that the property must be setted Public)

public ObservableCollection<JokerViewModel> MyJokers
    get { return _myCollection; }
    private set { _myCollection = value; }

You can then bind your ListViewItems on the public properties of this ViewModel (since the ListView will contains the sub-ViewModel children). You can customize your ListViewItems with ItemTemplate if the need exists.

With this binding, you can actually modify your ListView and ViewModel easily.