title: MVVM WPF - How to update DataGrid bound to ObservableCollection
body: <h1>What I'm trying to do:</h1>
  <p>I have a WPF app, linked to a SQL-server. I am using the MVVM-light package (I do actually have Prism.Core installed, but I'm not sure if I'm using it or not.... new to MVVM).</p>
  <p>There's a <code>DataGrid</code>, bound to an <code>ObservableCollection</code>.
  I have been trying to implement the <code>PropertyChangedEventHandler</code>, but I can't seem to get it to work.</p>
  <p>I have a Delete button bound, and I am able to remove rows, but when I re-open the form, the changes does not carry over.</p>
  <p>I tried to change the binding-mode for the <code>DataGrid</code> from <code>OneWay</code> to <code>TwoWay</code>. With <code>OneWay</code>, the changes does not carry over when I re-open the form. With <code>TwoWay</code>, I get this error message when opening the child form (which contains the <code>DataGrid</code>):</p>
  <blockquote>
  <p>System.InvalidOperationException: 'A TwoWay or OneWayToSource binding cannot work on the read-&gt;only property 'licenseHolders' of type 'Ridel.Hub.ViewModel.LicenseHoldersViewModel'.'</p>
  </blockquote>
  <p>So, If I then add a <code>set;</code> to my <code>public ObservableCollection&lt;LicenseHolders&gt; licenseHolders { get; }</code>,
  the program runs, but the previous problem persists, like it did when there was a <code>OneWay</code> mode configuration on the <code>DataGrid</code>.</p>
  <p>What do I need to do to get this to work without communicating directly with the <code>Sql-server</code>, which would defy the whole point of using this methodology in the first place?</p>
  <h2>ViewModel:</h2>
  <pre><code>public class LicenseHoldersViewModel : INotifyPropertyChanged {
  
      public event PropertyChangedEventHandler PropertyChanged;
  
      public ObservableCollection&lt;LicenseHolders&gt; licenseHolders { get; }
          = new ObservableCollection&lt;LicenseHolders&gt;();
  
      public LicenseHoldersViewModel() {
  
          FillDataGridLicenseHolders();
      }
  
      private void FillDataGridLicenseHolders() {
  
          try {
  
              using (SqlConnection sqlCon = new(ConnectionString.connectionString))
              using (SqlCommand sqlCmd = new(&quot;select * from tblLicenseHolder&quot;, sqlCon))
              using (SqlDataAdapter sqlDaAd = new(sqlCmd))
              using (DataSet ds = new()) {
  
                  sqlCon.Open();
                  sqlDaAd.Fill(ds, &quot;tblLicenseHolder&quot;);
  
                  foreach (DataRow dr in ds.Tables[0].Rows) {
  
                      licenseHolders.Add(new LicenseHolders {
  
                          ID = Convert.ToInt32(dr[0].ToString()),
                          Foretaksnavn = dr[1].ToString(),
                          Foretaksnummer = dr[2].ToString(),
                          Adresse = dr[3].ToString(),
                          Postnummer = (int)dr[4],
                          Poststed = dr[5].ToString(),
                          BIC = dr[6].ToString(),
                          IBAN = dr[7].ToString(),
                          //Profilbilde ???
                          Kontaktperson = dr[8].ToString(),
                          Epost = dr[9].ToString(),
                          Tlf = dr[10].ToString()
                      });
                  }
              }
  
          } catch (Exception ex) {
  
              MessageBox.Show(ex.Message, &quot;Message&quot;, MessageBoxButton.OK, MessageBoxImage.Information);
          }
      }
  
      private RelayCommand&lt;LicenseHolders&gt; _removeLicenseHoldersCommand;
  
      public RelayCommand&lt;LicenseHolders&gt; RemoveLicenseHoldersCommand =&gt; _removeLicenseHoldersCommand
          ??= new RelayCommand&lt;LicenseHolders&gt;(RemoveLicenseHolderExecute, RemoveLicenseHolderCanExecute);
  
      private bool RemoveLicenseHolderCanExecute(LicenseHolders myLicenseHolder) {
  
          // Checking for the removeable licenseholder in the collection
          return licenseHolders.Contains(myLicenseHolder);
      }
  
      private void RemoveLicenseHolderExecute(LicenseHolders myLicenseHolder) {
  
          licenseHolders.Remove(myLicenseHolder);
      }
  
      private void OnPropertyChanged(string myLicenseHolder) {
  
          PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(myLicenseHolder));
      }
  }
  </code></pre>
  <h2>Model</h2>
  <pre><code>public class LicenseHolders {
  
      public int ID { get; set; }
      public string Foretaksnavn { get; set; }
      public string Foretaksnummer { get; set; }
      public string Adresse { get; set; }
      public int Postnummer { get; set; }
      public string Poststed { get; set; }
      public string BIC { get; set; }
      public string IBAN { get; set; }
      public string Kontaktperson { get; set; }
      public string Epost { get; set; }
      public string Tlf { get; set; }
  
  }
  </code></pre>
  <h2>Code-behind</h2>
  <pre><code>public partial class Personell : Window {
  
          LicenseHoldersViewModel licenseHoldersViewModel;
  
          public Personell() {
  
              InitializeComponent();
              btnLogOut.Content = UserInfo.UserName;
  
              licenseHoldersViewModel = new LicenseHoldersViewModel();
              base.DataContext = licenseHoldersViewModel;
          }
  </code></pre>
  <h2>XAML</h2>
  <pre><code>&lt;Window x:Class=&quot;Ridel.Hub.Personell&quot;
          xmlns=&quot;http://schemas.microsoft.com/winfx/2006/xaml/presentation&quot;
          xmlns:x=&quot;http://schemas.microsoft.com/winfx/2006/xaml&quot;
          xmlns:d=&quot;http://schemas.microsoft.com/expression/blend/2008&quot;
          xmlns:mc=&quot;http://schemas.openxmlformats.org/markup-compatibility/2006&quot;
          xmlns:local=&quot;clr-namespace:Ridel.Hub&quot; xmlns:viewmodel=&quot;clr-namespace:Ridel.Hub.ViewModel&quot; d:DataContext=&quot;{d:DesignInstance Type=viewmodel:LicenseHoldersViewModel}&quot;
          mc:Ignorable=&quot;d&quot;
          
      &lt;Canvas Margin=&quot;10,10,10,10&quot;&gt;
      &lt;!-- I click this button when I want to delete a DataGrid row --&gt;
          &lt;Button Style=&quot;{DynamicResource ButtonWithRoundCornersGreen}&quot; FontSize=&quot;22&quot; x:Name=&quot;btnDelete&quot; Content=&quot;Delete license holder&quot; Width=&quot;187&quot; Height=&quot;47&quot; 
                  Background=&quot;#48bb88&quot; Foreground=&quot;White&quot; Canvas.Left=&quot;547&quot; Canvas.Top=&quot;668&quot; IsEnabled=&quot;False&quot; 
                  Command=&quot;{Binding RemoveLicenseHoldersCommand}&quot; CommandParameter=&quot;{Binding SelectedItem, ElementName=dgLicenseHolder}&quot;/&gt;
  
          &lt;DataGrid             
              x:Name=&quot;dgLicenseHolder&quot;
              CanUserAddRows=&quot;False&quot;
              ItemsSource=&quot;{Binding licenseHolders, Mode=TwoWay}&quot;
              Height=&quot;557&quot; 
              Width=&quot;505&quot; 
              ColumnWidth=&quot;*&quot;
              Canvas.Top=&quot;158&quot; 
              FontSize=&quot;20&quot;
              IsReadOnly=&quot;True&quot;
              SelectionMode=&quot;Single&quot;
              AutoGenerateColumns=&quot;False&quot;
              CanUserDeleteRows=&quot;False&quot;          
              SelectionChanged=&quot;dgLicenseHolder_SelectionChanged&quot; Canvas.Left=&quot;31&quot; &gt;
  
              &lt;DataGrid.Columns&gt;
                  &lt;DataGridTextColumn Header=&quot;ID&quot;             Binding=&quot;{Binding Path='ID'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Foretaksnavn&quot;   Binding=&quot;{Binding Path='Foretaksnavn'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Visible&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Foretaksnummer&quot; Binding=&quot;{Binding Path='Foretaksnummer'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Adresse&quot;        Binding=&quot;{Binding Path='Adresse'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Postnummer&quot;     Binding=&quot;{Binding Path='Postnummer'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Poststed&quot;       Binding=&quot;{Binding Path='Poststed'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Visible&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;BIC&quot;            Binding=&quot;{Binding Path='BIC'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;IBAN&quot;           Binding=&quot;{Binding Path='IBAN'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Kontaktperson&quot;  Binding=&quot;{Binding Path='Kontaktperson'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Epost&quot;          Binding=&quot;{Binding Path='Epost'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
                  &lt;DataGridTextColumn Header=&quot;Tlf&quot;            Binding=&quot;{Binding Path='Tlf'}&quot; IsReadOnly=&quot;True&quot; Visibility=&quot;Collapsed&quot;/&gt;
              &lt;/DataGrid.Columns&gt;
              
          &lt;/DataGrid&gt;
      &lt;/Canvas&gt;
  &lt;/Window&gt;
  </code></pre>