views:

278

answers:

2

I have a wpf window which is used to add as well as edit information about an entity. I am using mvvm architecture and ADO.Net entity model.

The screen looks something like this -

  <!-- EmployeeView -->
  <Window .....DataContext={.....}>

      <WpfToolkit:Datagrid x:Name="dgEmployees"
                           CanUserAddRows="false"
                           ItemSource="{Binding Path=Employees}"
                           ................
                           SelectedItem="{Binding SelectedEmployee}"..>
            <!-3 datagrid template column binding -->              

      </WpfToolkit:Datagrid>

       <TextBox Text="{Binding ElementName=dgEmployees, Path=SelectedEmployee.FirstName}"/>

       <TextBox Text="{Binding ElementName=dgEmployees, Path=SelectedEmployee.LastName}"/>


        <Button Content="Clear" Command="{Binding ClearCommand}"/>
        <Button Content="Save" Command={Binding SaveCommand}">

  </Window>

Here the ClearCommand will simply clear the textboxes and save will add or edit a record. I am setting the DataContext property in the xaml itself. I want to keep the CodeBehind empty.

The ViewModel -

 public class EmployeeViewModel : INotifyProperyChanged
 {
      DatabaseEntities _dbEntities; // Ado.Net Entity model

      RelayCommand _saveCommand, _clearCommand;

      public ObservableCollection<Employee> Employees{get;set;}

      public Employee SelectedEmployee{get; set;}

      public EmployeeViewModel()
      {
           _dbEntities=new DatabaseEntities();
            GetAllEmployees();
      }

      private void GetAllEmployees()
      {
          Employees = new ObservableCollection<Employee>();

          var query = from _e in _dbEntities.Employee
                      select _e;

          foreach(Employee _emp in query)
          {
              Employees.Add(_emp);
          }
      }

      public ICommand SaveCommand
      {
          get
          {
             if(_saveCommand == null)
             {
                 _saveCommand = new RelayCommand(){param => SaveEmployee()};
             }
          }
      }


      public ICommand ClearCommand
      {
          get
          {
             if(_clearCommand == null)
             {
                 _clearCommand = new RelayCommand(){param => Clear()};
             }
          }
      }


      private void Save()
      {
           /*************************Edit****************************/
          // if editing Employee info (this part works fine)


          Employee emp = _dbEntities.Employee.FirstorDefault<Employee>( p => p.EmpID == SelectedEmployee.EmpID);
          if(emp != null)
          {
          .................

          _dbEntities.SaveChanges(true);
           /************************************************************/
           }
           else
           {
           /*******************Add New**************************/
         // if adding new employee info (doesn't work)

         Employee emp = Employee.CreateEmployee(0, SelectedEmployee.FirstName, SelectedEmployee.LastName); // here NullReference Exception is thrown because SelectedEmployee is null while adding a new Employee. 

         _dbEntities.AddToEmployee(emp
         _dbEntities.SaveChanges(true);

          GetAllEmployees();
         /************************************************************/

         }

      }


      private void Clear()
      {
          // to clear all the textboxes before adding new employee info.
          SelectedEmployee = null;
          OnPropertyChanged("SelectedEmployee");
      }
 }

I can edit information, but not add new. If I want to add new Employee info, and enter the FirstName lastname in the respective textboxes. These entered values do not bind with SelectedEmployee property as SelectedEmployee is null( we clear the fields to add a new record). How do I access values entered in the textboxes from SelectedEmployee Property?

I know this problem can be solved by Creating a separate EmployeeModel with the IsSelected property .....But is there any other way out??

A: 

If I understand you well the Clear Command will prepare the VM to accept a new Employee, so why don't you initialize a new SelectedEmployee in the Clear method and add it to the Employees collection?

private void Clear() 
 {
      // to clear all the textboxes before adding new employee info.
      SelectedEmployee = new Employee{FirstName="",LastName=""};
      Employees.Add(SelectedEmployee);
      OnPropertyChanged("SelectedEmployee");
  }
Dabblernl
A: 

I would recommend you put the FirstName and LastName into strings on the ViewModel, then you always have access to them in the Save method, whether the SelectedEmployee is null or not.

(In your Save method)

Employee emp = Employee.CreateEmployee(0, FirstName, LastName);

If you want the textboxes to refresh from the user changing the selected item in the datagrid, you'll need to override the setter on SelectedEmployee, something like:

 string _firstName;
 public string FirstName 
 {
  get { return _firstName; }
  set
  {
   if (_firstName != value)
   {
    _firstName = value;
    OnPropertyChanged("FirstName");
   }
  }
 }

 string _lastName;
 public string LastName
 {
  get { return _lastName; }
  set
  {
   if (_lastName != value)
   {
    _lastName = value;
    OnPropertyChanged("LastName");
   }
  }
 }

 Employee _selectedEmployee;
 public Employee SelectedEmployee
 {
  get { return _selectedEmployee; }
  set
  {
   if (_selectedEmployee != value)
   {
    _selectedEmployee = value;
    OnPropertyChanged("SelectedEmployee");
    FirstName = (_selectedEmployee == null) ? string.Empty : _selectedEmployee.FirstName;
    LastName = (_selectedEmployee == null) ? string.Empty : _selectedEmployee.LastName;
   }
  }
 }

then simply update your xaml to look like:

   <TextBox Text="{Binding Path=FirstName}"/>
   <TextBox Text="{Binding Path=LastName}"/>

Hope this helps :)

IanR
Thank you all for your response.
Wpf Newbie