WPF MVVM EF Simple Example

2019-04-11 21:52发布

问题:

I was hoping someone could help me get this simple WPF MVVM example off the ground as I am struggling to plumb the data into the view model.

I have an SQL Table Temperatures where each record has a time stamp and then a numerical value eg.

LogTime--------------Temperature
01/01/2013 00:00 --60
01/01/2013 00:05 --61.1
01/01/2013 00:10 --61.2

My WPF View would have a start datetime and end datetime picker and a gridview allow the user to select records from a date range and then display them in the grid

My Model is entity framework so where I am struggling is what would I need for the view model and where would the linq query go to pass the user entered start and end datetime. I am evetually going to chart the data and there is a definite requirment (scichart) to use an Observable Collection for the data. But I just wanted to get a very simplisitic data example to see how the database data is obtained in the ViewModel as an Observable Collection for binding to the view. I am also using Telerik WPF controls for my GridView and I know they may do things differently.

As you can tell I am a complete beginner and have struggled to find a simple example anywhere (loads of complex ones) else so any help is greatly appreciated.

回答1:

This is actually quite a large subject. However, to keep things simple, and exclude design patterns and MVVM Frameworks for now...

You would need to create;

A WPF XAML View having:

<Window x:Class="MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="728" Width="772">
    <Grid>
        <DataGrid AutoGenerateColumns="True" ItemsSource="{Binding MyDataGridDataSource}" HorizontalAlignment="Center" Margin="0,88,0,0" VerticalAlignment="Top" Height="286" Width="584"/>
        <Grid Margin="0,403,0,0" VerticalAlignment="Top" HorizontalAlignment="Center" >
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Label Content="Start Date:" HorizontalAlignment="Left" Margin="10,8,0,0" VerticalAlignment="Top"/>
            <DatePicker SelectedDate="{Binding StartDate}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Grid.Column="1"/>
            <Label Content="End Date:" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Grid.Column="2"/>
            <DatePicker SelectedDate="{Binding EndDate}" HorizontalAlignment="Left" Margin="10,10,0,0" VerticalAlignment="Top" Grid.Column="3"/>
        </Grid>

    </Grid>
</Window>

A VieModel Class called something like clsMyTemperatureViewModel:

Imports System.Collections.ObjectModel
Imports System.ComponentModel

''' <summary>
''' Only for Simulating the EF Context!
''' </summary>
''' <remarks></remarks>
Public Class TableTemperatures

    Public Property LogTime As Date
    Public Property Temperature As Double

End Class


Public Class clsMyTemperatureViewModel : Implements INotifyPropertyChanged

    Private _ListOfTemperatures As ObservableCollection(Of TableTemperatures)

    Private _MyDataGridDataSource As ObservableCollection(Of TableTemperatures)
    Public Property MyDataGridDataSource As ObservableCollection(Of TableTemperatures)
        Get
            Return _MyDataGridDataSource
        End Get
        Set(value As ObservableCollection(Of TableTemperatures))
            _MyDataGridDataSource = value
            OnPropertyChanged("MyDataGridDataSource")
        End Set
    End Property

    Private _StartDate As Date
    Public Property StartDate As Date
        Get
            Return _StartDate
        End Get
        Set(value As Date)
            If _StartDate <> value Then
                _StartDate = value
                OnPropertyChanged("StartDate")
                GetResults()
            End If
        End Set
    End Property

    Private _EndDate As Date
    Public Property EndDate As Date
        Get
            Return _EndDate
        End Get
        Set(value As Date)
            If _EndDate <> value Then
                _EndDate = value
                OnPropertyChanged("EndDate")
                GetResults()
            End If
        End Set
    End Property

    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    Public Sub OnPropertyChanged(ByVal PropertyChangeName As String)

        RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(PropertyChangeName))
    End Sub

    Public Sub GetResults()

        Dim query = From TemperatureList In _ListOfTemperatures
                    Where TemperatureList.LogTime >= StartDate
                    Where TemperatureList.LogTime <= EndDate
                    Select TemperatureList

        MyDataGridDataSource = New ObservableCollection(Of TableTemperatures)(query)

    End Sub

    Public Sub New()

        '
        ' Only for Simulating the EF Context!
        '
        _ListOfTemperatures = New ObservableCollection(Of TableTemperatures)
        _ListOfTemperatures.Add(New TableTemperatures With {.LogTime = New Date(2012, 9, 1), .Temperature = 14})
        _ListOfTemperatures.Add(New TableTemperatures With {.LogTime = New Date(2012, 10, 2), .Temperature = 15})
        _ListOfTemperatures.Add(New TableTemperatures With {.LogTime = New Date(2012, 11, 3), .Temperature = 16})
        _ListOfTemperatures.Add(New TableTemperatures With {.LogTime = New Date(2012, 12, 4), .Temperature = 17})
        _ListOfTemperatures.Add(New TableTemperatures With {.LogTime = New Date(2013, 1, 5), .Temperature = 18})

        StartDate = New Date(2011, 1, 1)
        EndDate = New Date(2014, 1, 1)

        GetResults()

    End Sub
End Class

Here I've mocked up a small class to replicate your EF Context. You would however need to reference your EF Context rather than my _ListOfTemperatures collection. This would be something like;

    Public Sub GetResults()

        Dim query = From TemperatureList In MyEFContext.TemperatureList
                    Where TemperatureList.LogTime >= StartDate
                    Where TemperatureList.LogTime <= EndDate
                    Select TemperatureList

        MyDataGridDataSource = New ObservableCollection(Of TableTemperatures)(query)

    End Sub

The ViewModel basically exposes the relevant Public Properties to the View. One important thing to notice, is that you must implement the INotifyPropertyChanged interface, and Raise the PropertyChanged event for the view to update when the Properties have changed within the ViewModel.

You then need to add the following to your code behind New Sub;

Me.DataContext = New clsMyTemperatureViewModel

This will set the DataContext of your View to the new ViewModel.

As I mentioned previously, this example doesn't attempt to involve any MVVM Frameworks, nor use any proper Design Patterns.

You should really be using the Repository Pattern for your data. It's within this Repository that you would place your Linq to Entities code, returning only an ObservableCollection to your ViewModel.

You would create a Solution having;

  • A Project which would house your EF Context
  • A Project for Database Repositories
  • A Project for your Main Application which in turn would have Folders setup for your Views, View Models, Classes, Behaviours etc.

However, I hope this get's you going!



回答2:

Create a view-model and have it look something like this:

public class YourViewModel: INotifyPropertyChanged
{

private ObservableCollection<YourModel> _yourModels;
public ObservableCollection<YourModel> YourModels
    {
    get { return _yourModels; }
    set
    {
    _yourModels= value;
    RaisePropertyChanged(() => this.YourModels);
    }
    }

private DateTime _startTime;
public DateTime StartTime
    {
    get { return _startTime; }
    set
    {
    if (value == _startTime) return;
    _startTime= value;
    RaisePropertyChanged(() => this.StartTime);
    }
    }

private DateTime _endTime;
public DateTime SendTime
    {
    get { return _endTime; }
    set
    {
    if (value == _endTime) return;
    _endTime= value;
    RaisePropertyChanged(() => this.SendTime);
    }
    }

public YourViewModel()
{
YourModels = new ObservableCollection<YourModel>();

//
// You'll need to load your data into the ObservableCollection
//

}
}

Now in your view, you'll need to bind to the properties and collection. Something like this:

<DatePicker x:Name="startDate" SelectedDate="{Binding Path=StartDate}"></DatePicker>
<DatePicker x:Name="endDate" SelectedDate="{Binding Path=EndDate}"></DatePicker>

<ListView ItemsSource="{Binding Path=YourModels}">
     <ListView.View>
         <GridView>
         <GridViewColumn Header="YourProperty" DisplayMemberBinding="{Binding        Path=YourProperty}" />
         </GridView>
     </ListView.View>
</ListView>

I haven't tested this, but it should give you a push in the right direction.



标签: wpf mvvm