0

I am learning some WPF and have written this little program that reads an Excel file for data and updates the UI on save. Only after the first save does my ResetTimer() function work. But the GetDisplayData() does load the data and the program will update data on save. Only they timer does not start until that first save..

But I want the timer to start right away in case there is not a save event on the Excel file at load.

What can I do to get it to work, seems like whenever I try and place it in window_loaded or other places I tried, my program loops or does not load the data.

Thank you for your help.

using System;
using System.Data;
using System.IO;
using System.Windows;
using System.Windows.Threading;

namespace WPFReadExcel
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
      private const string ExcelPath = @"C:\";
      private const string ExcelPathFile = @"C:\DataSource.xlsx";
      DataTable _dashBoardData = new DataTable();

      public MainWindow()
      {
        InitializeComponent();
      }

      protected void Window_Loaded(object sender, RoutedEventArgs e)
      {
        GetDisplayData();
        StartFileSystemWatcher();
      }

      public void GetDisplayData()
      {
        var excelData = new ExcelData();
        _dashBoardData = excelData.ReadExcelFile("Live", ExcelPathFile);

         Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
         {
           ExcelDataGrid.ItemsSource = _dashBoardData.AsDataView();
           RefreshDateTime.Content = "Refresh at: " + 
                                      DateTime.Now.ToShortTimeString();
          }
          ));
      }

      private void ResetDisplayData()
      {
        if (_dashBoardData != null) _dashBoardData.Dispose();
        GetDisplayData();
        ResetTimer();

      }

      private void ResetTimer()
      {
        while (true)
        {
          System.Threading.Thread.Sleep(20000);
          ResetDisplayData();
        }
      }

      private void StartFileSystemWatcher()
      {
        if (string.IsNullOrWhiteSpace(ExcelPath))
           return;

        FileSystemWatcher watcher = new FileSystemWatcher();

        // set directory to watch
        watcher.Path = ExcelPath;

       // set what to watch for
       watcher.NotifyFilter = NotifyFilters.LastWrite;

       // set event handlers
       watcher.Changed += new FileSystemEventHandler(watcher_Changed);

       // start watching
       watcher.EnableRaisingEvents = true;
      }

      private void watcher_Changed(object sender, FileSystemEventArgs e)
      {
        ResetDisplayData();
      }

      private void Label_Loaded(object sender, RoutedEventArgs e)
      {
        RefreshDateTime.Content = "Refresh at: " + DateTime.Now.ToShortTimeString();
      }
  }

}

Walt Ritscher
  • 6,977
  • 1
  • 28
  • 35
JoJo
  • 4,643
  • 9
  • 42
  • 65
  • 1
    I'm not so good at WPF, but why don't you use real timer for your purpose instead of Thread.Sleep()? See this on how to use DispatcherTimer: http://stackoverflow.com/a/11560151/2571926. Second thing - what happens on program load? GetDisplayData() doesn't display what you need? It's not clear from description. – Ilya Luzyanin Jul 18 '14 at 13:41
  • @IlyaLuzyanin ty I will take a look. I updated my description. Data Loads fine on start, but timer does not start till the first Excel sheet save after that it is perfect. – JoJo Jul 18 '14 at 13:46
  • 1
    What *timer*??? You don't have one! – Sheridan Jul 18 '14 at 13:47
  • @IlyaLuzyanin Thank you again. I added a DispatcherTimer and it works perfectly. If you answer it I will mark it as the answer. ty – JoJo Jul 18 '14 at 13:53
  • That's ok, Sheridan already posted a good answer! Cheers! – Ilya Luzyanin Jul 18 '14 at 13:57

1 Answers1

2

The Window.Loaded event is the correct place to do what you want:

protected void Window_Loaded(object sender, RoutedEventArgs e)
{
    ResetTimer();
    GetDisplayData();
    StartFileSystemWatcher();
}

However, it appears that you aren't using a Timer anywhere, so your question and your method name are inappropriate. In WPF, we use the DispatcherTimer Class. First, you'd need to initialise it and then start it:

private DispatcherTimer timer = new DispatcherTimer();

...

private void ResetTimer()
{
    timer.Interval = TimeSpan.FromSeconds(20);
    timer.Tick += Timer_Tick;
    timer.Start();
}

private void Timer_Tick(object sender, EventArgs e)
{
    ResetDisplayData();
}

For your information, you really couldn't write much worse code than this, as it will block your UI and make your application non responsive:

while (true)
{
    System.Threading.Thread.Sleep(20000);
    ResetDisplayData();
}
Sheridan
  • 68,826
  • 24
  • 143
  • 183