Trouble with persisting data from MVVM to Entity Framework using WPF binding

Xipooo

New member
Joined
Jan 30, 2014
Messages
3
Programming Experience
1-3
Here is my VM class:


VB.NET:
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Collections.Specialized


Public Class MainWindowVM
    Implements INotifyPropertyChanged
    Implements INotifyCollectionChanged


    Dim dbcontext As New FootballPoolEntities
    Private _Users As ObservableCollection(Of User)
    Private _Settings As ObservableCollection(Of ScheduleSetting)
    Public Property Users As ObservableCollection(Of User)
        Get
            Return _Users
        End Get
        Set(value As ObservableCollection(Of User))
            _Users = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Users"))
        End Set
    End Property
    Public Property Settings As ObservableCollection(Of ScheduleSetting)
        Get
            Return _Settings
        End Get
        Set(value As ObservableCollection(Of ScheduleSetting))
            _Settings = value
            RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("Settings"))
        End Set
    End Property


    Public Sub New()
        _Users = New ObservableCollection(Of User)(dbcontext.Users.ToList)
        _Settings = New ObservableCollection(Of ScheduleSetting)(dbcontext.ScheduleSettings.ToList)
        AddHandler Users.CollectionChanged, AddressOf OnUsersCollectionChanged
        AddHandler Settings.CollectionChanged, AddressOf OnSettingsCollectionChanged
    End Sub


    Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) Implements INotifyPropertyChanged.PropertyChanged
    Public Event CollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs) Implements INotifyCollectionChanged.CollectionChanged


    Private Sub OnUsersCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
        If e.Action = NotifyCollectionChangedAction.Add Then
            For Each item In e.NewItems
                dbcontext.Users.Add(item)
            Next
        End If
        If e.Action = NotifyCollectionChangedAction.Remove Then
            For Each item In e.OldItems
                dbcontext.Users.Remove(item)
            Next
        End If
    End Sub


    Private Sub OnSettingsCollectionChanged(sender As Object, e As NotifyCollectionChangedEventArgs)
        If e.Action = NotifyCollectionChangedAction.Add Then
            For Each item In e.NewItems
                dbcontext.ScheduleSettings.Add(item)
            Next
        End If
        If e.Action = NotifyCollectionChangedAction.Remove Then
            For Each item In e.OldItems
                dbcontext.ScheduleSettings.Remove(item)
            Next
        End If
    End Sub


    Public Sub SaveChanges()
        dbcontext.SaveChanges()
    End Sub
    Public Sub NewWeek()
        Dim newWeek As New ScheduleSetting
        Settings.Add(newWeek)
    End Sub


    Public Function WeekList(SelectedYear As Int32) As ObservableCollection(Of ScheduleSetting)
        If SelectedYear = 0 Then
            Return Nothing
            Exit Function
        End If
        Return New ObservableCollection(Of ScheduleSetting)(Settings.Where(Function(c) c.Year = SelectedYear).ToList)
    End Function


    Public Function YearList() As List(Of Int32)
        Return dbcontext.ScheduleSettings _
            .Select(Function(x) x.Year) _
            .Distinct.ToList()
    End Function
End Class


Here is my XAML:
VB.NET:
<Window
    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:FootballPool" mc:Ignorable="d" x:Class="MainWindow"
    xmlns:system="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525" Margin="5">
    <Window.Resources>
        <local:MainWindowVM x:Key="ViewModel" />
        <ObjectDataProvider x:Key="YearList"
                            ObjectType="{x:Type local:MainWindowVM}"
                            MethodName="YearList" />
        <ObjectDataProvider x:Key="WeekList"
                            ObjectType="{x:Type local:MainWindowVM}"
                            MethodName="WeekList">
            <ObjectDataProvider.MethodParameters>
                <system:Int32>0</system:Int32>
            </ObjectDataProvider.MethodParameters>
        </ObjectDataProvider>
    </Window.Resources>
    <Grid>
        <TabControl Margin="0,0,0,37">
            <TabItem Header="Standings">
                <Grid Background="#FFE5E5E5"/>
            </TabItem>
            <TabItem Header="Users">
                <Grid Background="#FFE5E5E5">
                    <DataGrid
                        x:Name="dgUsers"
                        DataContext="{Binding Source={StaticResource ViewModel}}"
                        ItemsSource="{Binding Users, Mode=TwoWay}" AutoGenerateColumns="False"
                        IsSynchronizedWithCurrentItem="True"
                        >
                        <DataGrid.Columns>
                            <DataGridTextColumn Binding="{Binding FirstName}" ClipboardContentBinding="{x:Null}" Header="First Name"/>
                            <DataGridTextColumn Binding="{Binding LastName}" ClipboardContentBinding="{x:Null}" Header="Last Name"/>
                            <DataGridTextColumn Binding="{Binding Email}" ClipboardContentBinding="{x:Null}" Header="Email"/>
                            <DataGridTextColumn Binding="{Binding Password}" ClipboardContentBinding="{x:Null}" Header="Password"/>
                        </DataGrid.Columns>


                    </DataGrid>
                </Grid>
            </TabItem>
            <TabItem Header="Weekly Settings">
                <Grid Background="#FFE5E5E5">
                    <Grid x:Name="Grid1" HorizontalAlignment="Left" VerticalAlignment="Top" Background="#FFC8C8C8" Margin="238,27,0,0" DataContext="{Binding SelectedItem, ElementName=listBox}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                            <RowDefinition Height="Auto"/>
                        </Grid.RowDefinitions>
                        <Label Content="Year:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="0" VerticalAlignment="Center"/>
                        <TextBox x:Name="Year" Grid.Column="1" HorizontalAlignment="Left" Height="24" Margin="3" Grid.Row="0" Text="{Binding Year, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
                        <Label Content="Week Number:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="1" VerticalAlignment="Center"/>
                        <TextBox x:Name="WeekNumberTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="1" Grid.Row="1" Text="{Binding WeekNumber, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>
                        <Label Content="Begin Date:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="2" VerticalAlignment="Center"/>
                        <DatePicker x:Name="BeginDateDatePicker" Grid.Column="1" HorizontalAlignment="Left" Margin="3" Grid.Row="2" SelectedDate="{Binding BeginDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center"/>
                        <Label Content="End Date:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="3" VerticalAlignment="Center"/>
                        <DatePicker x:Name="EndDateDatePicker" Grid.Column="1" HorizontalAlignment="Left" Margin="3" Grid.Row="3" SelectedDate="{Binding EndDate, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center"/>
                        <Label Content="Cost:" Grid.Column="0" HorizontalAlignment="Left" Margin="3" Grid.Row="4" VerticalAlignment="Center"/>
                        <TextBox x:Name="CostTextBox" Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="3" Grid.Row="4" Text="{Binding Cost, Mode=TwoWay, NotifyOnValidationError=true, ValidatesOnExceptions=true}" VerticalAlignment="Center" Width="120"/>


                    </Grid>
                    <Button x:Name="btnNewWeek" Content="New Week" HorizontalAlignment="Left" Height="23" Margin="384,192,0,0" VerticalAlignment="Top" Width="75"/>
                    <ComboBox x:Name="cboYear"
                              HorizontalAlignment="Left" Margin="94,14,0,0" 
                              VerticalAlignment="Top" Width="56"  
                              IsSynchronizedWithCurrentItem="True" 
                              ItemsSource="{Binding Mode=OneWay, Source={StaticResource YearList}}">
                        <ComboBox.SelectedItem>
                            <Binding Source="{StaticResource WeekList}"
                                     Path="MethodParameters[0]"
                                     BindsDirectlyToSource="True"
                                     UpdateSourceTrigger="PropertyChanged" />
                        </ComboBox.SelectedItem>
                    </ComboBox>
                    <ListBox x:Name="listBox" HorizontalAlignment="Left" Height="136" Margin="95,51,0,0" VerticalAlignment="Top" Width="55" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Source={StaticResource WeekList}}" DisplayMemberPath="WeekNumber" />
                    <Label Content="Year:" HorizontalAlignment="Left" Margin="27,10,0,0" VerticalAlignment="Top"/>
                    <Label Content="Week:" HorizontalAlignment="Left" Margin="27,51,0,0" VerticalAlignment="Top"/>
                </Grid>
            </TabItem>
        </TabControl>
        <Button Content="Save" HorizontalAlignment="Right" Height="27" Margin="0,0,5,5" VerticalAlignment="Bottom" Width="80" Click="Button_Click"/>
    </Grid>
</Window>




The users datagrid works perfectly fine. I'm having trouble with a master-detail setup on my "Weekly Settings" tab.


My ObjectDataProvider for the listbox gets an ObservableCollection of Settings Objects through the "WeekList" method of my VM. I set the datacontext of my detail grid to the SelectedItem of that listbox. But when I try to save any changes made to the details, they don't persist back to the Entity Framework when I perform a "SaveChanges".


I could really use some help here.
 
Hmmm... is the question not phrased correctly or are there not enough people familiar with WPF binding to help me?
 
Well I was able to receive the answer from elsewhere but thank you to anyone who was trying.
The solution was that I needed to drop the ObjectDataContext's and instead use more properties.
I created a SelectedYear property as an integer and a WeekList property as an observablecollection of schedulesetting. The Selected year property was bound as the selecteditem of my combobox, and the weeklist had it's getter use the selected week property in a lambda expression to return a filtered list of weeks.
I had to also change it so the datacontexts were set on both the combobox and listbox to the VM. In hindsight, that part should have been obvious.
 
Back
Top