Click here to Skip to main content
15,903,856 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Good evening, I have been trying to study MVVM and CodeFirst, however I have come across a snag. I cannot seem to get my head round saving to SQL.

My example code is below, but basically I want to save a Name and an Address to my SQL database.

Please note, I already added 3 names and addresses to the table that is generated by EF. I am then populating a listview from my ViewModel. The problem is saving what the user puts in the textboxes, to the sql table.

My first guess was using command parameter, but that only allows one parameter string, and I need two.


If anyone can help me achieve this, I would really appreciate it, thanks.

View:
C#
<Window x:Class="WPFICommandMVVM.View.Person"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Person" Height="300" Width="300">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="100"></ColumnDefinition>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="auto"></RowDefinition>
                <RowDefinition Height="auto"></RowDefinition>
            </Grid.RowDefinitions>
            <Label x:Name="lblName" Content="Name" Grid.Row="0" Grid.Column="0"
                   VerticalAlignment="Top"></Label>
            <TextBox x:Name="txtName" Grid.Row="0" Grid.Column="1" VerticalAlignment="Top"
                     Text="{Binding ElementName=lvPerson, Path=SelectedItem.Name}"></TextBox>
            <Label x:Name="lblAddress" Content="Address" Grid.Row="1" Grid.Column="0"
                   VerticalAlignment="Top"></Label>
            <TextBox x:Name="txtAddress" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top"
                     Text="{Binding ElementName=lvPerson, Path=SelectedItem.Address}"></TextBox>
            <Button x:Name="btnUpdate" Width="100" Height="20" VerticalAlignment="Bottom" HorizontalAlignment="Center" Grid.Row="1"
                    Content="Update" Command="{Binding Path=UpdateCommand}" CommandParameter="{Binding
                    ElementName=lvPerson, Path=SelectedItem.Address}" Margin="0,0,0,-60.8"/>
            <ListView x:Name="lvPerson" Grid.Row="1" ItemsSource="{Binding Persons}" Grid.ColumnSpan="2" Margin="0,35.4,99.6,-35.8">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"></GridViewColumn>
                        <GridViewColumn Header="Address" Width="200" DisplayMemberBinding="{Binding Address}"></GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Grid>
</Window>


Model:
C#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace WPFICommandMVVM.Model
{
    public class Person : INotifyPropertyChanged
    {
        private int id;
        private string name;
        private string address;


        public event PropertyChangedEventHandler PropertyChanged;
        public void OnPropertyChanged(string propertyName)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        public int Id
        {
            get
            {
                return id;
            }
            set
            {
                id = value;
                OnPropertyChanged("Id");
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
            set
            {
                name = value;
                OnPropertyChanged("Name");
            }
        }

        public string Address
        {
            get
            {
                return address;
            }
            set
            {
                address = value;
                OnPropertyChanged("Address");
            }
        }
    }
}


ViewModel:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;
using WPFICommandMVVM.Model;
using WPFICommandMVVM.DataAccess;
using System.Collections.ObjectModel;

namespace WPFICommandMVVM.ViewModel
{
    public class PersonViewModel
    {
        public IList<Person> _personList;
        public IList<Person> PersonList;
        ObservableCollection<Person> obVinyl = new ObservableCollection<Person>();
        public PersonViewModel()
        {
            using (var db = new PersonContext())
            {

                // Display all vinyl from the database

                var query = from b in db.People

                            orderby b.Id

                            select b;


                foreach (var item in query)
                {
                    obVinyl.Add(item);
                    PersonList = obVinyl;
                }
                db.SaveChanges();
            }
            _personList = PersonList;
        }

        public IList<Person> Persons
        {
            get { return _personList; }
            set { _personList = value;}
        }
        private ICommand mUpdater;
        public ICommand UpdateCommand
        {
            get
            {
                if (mUpdater == null)
                    mUpdater = new Updater();
                return mUpdater;
            }
            set
            {
                mUpdater = value;
            }
        }
    }
    class Updater : ICommand
    {
        #region ICommand Members
        public bool CanExecute(object parameter)
        {
            return true;
        }
        public event EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object paramenter)
        {
            //InsertPerson method is called here.
            InsertPerson();
            
        }
        #endregion

        private static void InsertPerson()
        {
            var person = new Person
            {

            };

            using (var context = new PersonContext())
            {
                context.People.Add(person);
                context.SaveChanges();
            }
        }
    }
}


DataAccess:
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using WPFICommandMVVM.Model;

namespace WPFICommandMVVM.DataAccess
{
    public class PersonContext : DbContext
    {
       public DbSet<Person> People { get; set; }
    }
}


App.xaml (Where I set the datacontext):
C#
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using WPFICommandMVVM.ViewModel;

namespace WPFICommandMVVM
{
    /// <summary>
    /// Interaction logic for App.xaml
    /// </summary>
    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            View.Person person = new View.Person();
            PersonViewModel personViewModel = new PersonViewModel();
            person.DataContext = personViewModel;
            person.Show();
        }
    }
}




Thanks again for any help.


P.s If I am going about this wrongly, please provide examples to correct me.
Posted
Updated 16-Dec-13 0:34am
v2

1 solution

A few things. Make a few changes. I don't see a need for 2 PersonLists and with the Persons Property the _personList should be private. I also saw no need to have
PersonList = obVinyl;
in the for loop either. Also what is the db.SaveChanges doing? It seems odd to have this in the constructor.

public class PersonViewModel
    {
        private IList<Person> _personList;
        ObservableCollection<Person> obVinyl = new ObservableCollection<Person>();
        public PersonViewModel()
        {
            using (var db = new PersonContext())
            {
 
                // Display all vinyl from the database

                var query = from b in db.People
 
                            orderby b.Id
 
                            select b;
 

                foreach (var item in query)
                {
                    obVinyl.Add(item);
                }
               // What is this supposed to be doing in here?
                db.SaveChanges();
            }
            _personList = obVinyl;
        }
 
        public IList<Person> Persons
        {
            get { return _personList; }
            set { _personList = value;}
        }
        private ICommand mUpdater;
        public ICommand UpdateCommand
        {
            get
            {
                if (mUpdater == null)
                    mUpdater = new Updater();
                return mUpdater;
            }
            set
            {
                mUpdater = value;
            }
        }
    }


You can add another property to the Person object say hasChanged and when the user changes anything set it to true. If the users add a new Person (new list view item) then set the Id to 0 or -1.

Then when you save, you look for all the items in your Persons list that have 0 and insert them into the database and the ones with hasChanged = true you will update.

I haven't used datasets much but if there is a Person.Add there should be a Person.Update, or at the least you could replace the dataset copy with your copy.

Sorry, After all this I don't think I quite got to an answer you were looking for...
 
Share this answer
 
Comments
TeacherDean 16-Dec-13 17:42pm    
the db.SaveChanges() is a mistake, thanks for pointing it out.

Your method makes sense, but I feel it should be easier to save a new person to sql. After all, if I was doing this without MVVM, I could just do name = txtName.Text;
bowlturner 17-Dec-13 11:58am    
true, but if you have a large object with many properties and extra validation etc. this becomes a staging area, and it makes it easier for the user to change their mind before updating the db.
TeacherDean 18-Dec-13 1:06am    
Could you give me an example of your method, please?
bowlturner 18-Dec-13 9:00am    
Try using this as an example

http://www.codeproject.com/Articles/26288/Simplifying-the-WPF-TreeView-by-Using-the-ViewMode

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900