Search code examples
c#wpftimerwpfdatagrid

Update Datagrid when ItemsSource changes


I have gone through many forums to find a solution for my problem, but I didn't find the appropriate solution.

I have a Datagrid that is bound to a Datasource (MS SQL Server 2008) following the MVVM pattern. I have bound the ItemsSource to an ObservableCollection and implemented the INotifyPropertyChanged interface.

My database changes the table values in a certain time constraint. Now, I would like to reflect this Datasource change in my UI ( i.e I would like to see my UI's ItemsSource getting updated). When I thought about this, I understood that I should implement a Timer concept (like polling) so that my query gets run in a loop every 15 sec.

Here is my ViewModel Class, kindly guide me where should I implement the Timer Class??

namespace MVVM_DemoAppl.ViewModels
{
public class MainViewModel : INotifyPropertyChanged
{
 // Properties for the DispatcherTimer
  private bool disposed;
  private DispatcherTimer timer = new DispatcherTimer();
  // declaring instance of a class and Observable collection
  Model _myModel = new Model();
  private ObservableCollection<SystemStatus> _systemStatusData= new ObservableCollection<SystemStatus>();
  public ObservableCollection<SystemStatus> SystemStatusData
  {
    get { return _systemStatusData; }
    set
      {
        _systemStatusData= value;
      OnPropertyChanged("SystemStatusData");
      }
  }

public MainViewModel()
 {
   initializeload();
   timer.Tick += new EventHandler(timer_Tick);
   timer.Interval = new TimeSpan(0, 0, 15);
   timer.Start();
 }

 ~MainViewModel()
   {
       Dispose(false);
   }

  protected virtual void Dispose(bool disposing)
   {
       if (!disposed)
       {
           if (disposing)
           {
               timer.Stop();
               timer.Tick -= new EventHandler(timer_Tick);
           }
           disposed = true;
       }
   }

   private void timer_Tick(object sender, EventArgs e)
   {
       try
       {
           EventLogData.Clear();
           initializeload();
       }
       catch (Exception ex)
       {
           timer.Stop();
           Console.WriteLine(ex.Message);

       }
   }
private void initializeload()
{
   DataTable table = _myModel.getData();

 for (int i = 0; i < table.Rows.Count; ++i)
   SystemStatusData.Add(new SystemStatus
   {
Systems= table.Rows[i][0].ToString(),
Date =Convert.ToDateTime(table.Rows[i][1]),
Types = table.Rows[i][2].ToString(),
Messages = table.Rows[i][3].ToString(),
Critical = Convert.ToBoolean(table.Rows[i][1]),
    });
}

  public event PropertyChangedEventHandler PropertyChanged;

 private void OnPropertyChanged(string propertyname)
   {
     var handler = PropertyChanged;
     if (handler != null)
     handler(this, new PropertyChangedEventArgs(propertyname));
  }
 }

public class Model
 {
  string con = ConfigurationManager.AppSettings["ConnectionStrings"];
   public DataTable getData()
{
  DataTable ndt = new DataTable();
  SqlConnection sqlcon = new SqlConnection(con);
  sqlcon.Open();
  SqlDataAdapter da = new SqlDataAdapter("select top 5 System,Date,Typ,Message,Critical     from test_DB.dbo.SystemStatus",con);
  da.Fill(ndt);
  return ndt;
  }
 }
}

Solution

  • You could use a DispatcherTimer. Make your ViewModel disposable and kill the timer on dispose. In the constructor, configure the timer, hook a handler to the Tick event, and then start it:

    public MainViewModel()
    {
        initializeload();
        timer.Tick += new EventHandler(timer_Tick);
        timer.Interval = new TimeSpan(0, 0, 15);
        timer.Start();
    }
    ~MainViewModel()
    {
        Dispose(false);
    }
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                timer.Stop();
                timer.Tick -= new EventHandler(timer_Tick);
            }
            disposed = true;
        }
    }
    
    private void timer_Tick(object sender, EventArgs e)
    {
        try 
        {
            SystemStatusData.Clear();
            initializeload();
        } 
        catch (...) 
        {
            // Problem best to stop the timer if there is an error...
            timer.Stop();
        }
    }
    
    private bool disposed;
    private DispatcherTimer timer = new DispatcherTimer();