1

I have a DataGrid on my main page that is full of Employees. Each Employee has an "in" status - this is modified based on whether the Employee is currently in the building or not.

I need to consistently update this DataGrid as people will be entering or leaving the building throughout the day. This means I will be sending MySQL queries somewhere between every 1-5 seconds until the user clicks on a button to navigate to another page.

I have tried the most simple and obvious solution, a While loop however this freezes and locks the UI. How can I create a loop that runs and queries MySQL without locking the UI?

EDIT: Attempted Answer

        public void PeriodicCall()
        {
            var employeeDS = new EmployeeDataService();
            int i = 1;
            Timer timer = new Timer(
                state => {
                    Employees = employeeDS.HandleEmployeeSelect();
                    FilteredView = CollectionViewSource.GetDefaultView(Employees);
                    Application.Current.Dispatcher.BeginInvoke(new Action(() => {
                        dataGrid.ItemsSource = FilteredView;
                        testLabel.Content = "Who's Who " + i;
                        i++;
                    }));
                },
                null, //no object as Callback parameter
                TimeSpan.FromSeconds(0), //start in x millisec
                TimeSpan.FromSeconds(1)); //time between call
        }
CBreeze
  • 2,925
  • 4
  • 38
  • 93
  • Well, the easiest way to do this is the [BackgroundWorker](http://stackoverflow.com/questions/5483565/how-to-use-wpf-background-worker) – 91378246 Feb 08 '16 at 12:02

2 Answers2

2

You should use a timer to periodically retrieve data from your DB and update data in your datagrid using the Dispatcher.BeginInvoke function.

Timer timer = new Timer(
    state => {
        //Callback function
        Object yourData = GetDataFromDB();
        Application.Current.Dispatcher.BeginInvoke(new Action(()=> {
            YourUIProperty = yourData;
        }));
    },
    null, //no object as Callback parameter
    TimeSpan.FromSeconds(1), //start in x millisec
    TimeSpan.FromSeconds(5) //time between call
);
nkoniishvt
  • 2,442
  • 1
  • 14
  • 29
  • I've used this approach but with a counter on `int i = 1`, the counter never goes above 1. Should the `Timer` not be running the method within `Dispatcher.BeginInvoke` every second from this example? I've added my code to my question. – CBreeze Feb 08 '16 at 14:47
  • This example will execute GetDataFromDB & invoke the dispatcher every 5s after a first wait of 1s – nkoniishvt Feb 08 '16 at 15:11
  • `invoke the dispatcher every 5s` - so if I understand correctly this won't execute `GetDataFromDB()` again after the first execution? That doesn't make much sense to what I want to do as I need to update the Data ever y 5s – CBreeze Feb 08 '16 at 15:29
  • This will retrieve data every 5 sec and update the ui property every 5 sec. Everything in the callback function will be executed every 5 sec – nkoniishvt Feb 08 '16 at 15:36
2

You can use a Backgroundworker, hook to its .completed and there render (using

BackgroundWoker worker = new BackgroundWorker();
worker.DoWork += functioToDo
worker.Completed += functionWhere you update the UI
worker.runAsynchronous(); //actually starts the thread

In the function that updates the UI don't forget to use the dispatcher to access the UI thread:

dispatcher.invoke((Action) delegate { here your code})

to access the UI thread for elsewhere.

Other cooler approach is to take care of the propertyChanged and bind the changes to the UI. But this is a bit more complex and I don't know the details by head.

You can use a timer to start the whole thing every few seconds.

A third approach would be to have a trigger when you update the data base. We would need more details to know how to attach there. But from there you can also call some updates in the UI and then you don't need to use CPU to check every seconds (you know, work by interruption instead of by polling).

javirs
  • 1,049
  • 26
  • 52
  • a timer can call the worker, for sure. But I'd anyhow go for the interruption approach rather than make calls every few seconds. – javirs Feb 08 '16 at 12:09
  • 1
    If a Timer calls the worker you would use two thread to retrieve data instead of one – nkoniishvt Feb 08 '16 at 12:12
  • forget about the threads, focus on having the DB trigger you an event when the values change. This is the real way to go. – javirs Feb 08 '16 at 12:13