0

I'm trying to make a WPF application that keeps track of each student's absenteeism. I'm display the data onto a DataGridView using binding. Currently, I was able to get the Datagrid to display each week range (Monday-Sunday) for however long a date range the user wishes to see.

The issue I'm currently stuck on is when the user clicks on a specific week range row. The application will trigger the datagrid selection changed event, where I call an async-await method that does a lot of calculations in the background and outputs a datatable to give back to the Main UI thread, however, the application would jump out of the Task run method and tries to "get" the datatable first before it is filled by the task. The application would then continue getting the data for the datatable, and never updates the datatable for the datagrid row detail because the "get" was already called earlier...

Side note: I'm using async-await to also update a progress bar at the same time...

Below is my code, can anyone help me set this up properly?

Code within MainUI.xaml.cs:

private void dg_SelectionChange(object sender, SelectionChangedEventArgs e)
{
    ShowAbsentStudents();
}

private async void ShowAbsentStudents()
{
    var task = await GetRecords();
   //Update the viewmodel to get a property change
    _ = new DataBinding.ViewModelGrid(task);
}

private async Task<DataTable> GetRecords()
{
    string className = this.ComBox_ClassSelction.Text;
    DataRowView selectedRow = (DataRowView)dg.SelectedItems[0];
    DateTime startDate = DateTime.Parse(SelectedRow[0].ToString());
    DateTime endDate = DateTime.Parse(SelectionRow[1].ToString());

    var progress = new Progress<int>(value => {MainProgressBar.Value = value;});
    var absentStudentsTable = await Task.Run(() => DataProcessor.FindAbsentStudents(className, startDate, endDate, progress, this));

    return absentStudentsTable;
}

And within my ViewModelGrid.cs

public class ViewModelGrid : INotifyPropertyChanged
{
    private static DataView _rowDetailsGrid;

    public DataView rowDetailsGrid
    {
        get { return _rowDetailsGrid; }
        set
        {
            _rowDetailsGrid = value;
            OnPropertyChanged("rowDetailsGrid");
        }
    }
}

And lastly the DataProcessor.cs

internal static DataTable FindAbsentStudents(List<string> Class, MainUi mainUI, etc....)
{
    int counter = 0;
    int numberOfStudents = Class.Count;

    mainUI.Dispacther.Invoke(DispatcherPriority.Normal, new Action(delegate ()
    {
        //Show the progress bar on the main UI.
        mainUI.ShowProgressBar(numberOfStudents);
    }));

    foreach ( string student in Class )
    {
        counter += 1;

        //Put absent students in a table
  
        //Update the progress bar
        if(counter <= numberOfStudents)
        {
            progress?.Report(counter)
        }
    }

    return Datatable;
}
  • My *Spidey Senses* tells me your assumption is incorrect. There is no jumping out of an awaited `Task.Run` to return a value before the *promise* is filled. How are you proving this to your self, have you done some basic debugging, or perhaps `Debug.WriteLines` to illuminate the process flow ? – TheGeneral Feb 13 '21 at 00:38
  • 1
    The code above has a number of peculiarities (i.e. **bugs**), but fundamental to your described issue is that you have made your `async` method `void` and don't wait on it. There's no code above that makes any attempt to postpone any real work until the `Task` has completed. The closest you come is instantiating a new instance of `ViewModelGrid`, but since you immediately throw that instance away without doing anything with it, that line of code might as well not even exist. See duplicates for the info you need regarding the hazards of `async void`. – Peter Duniho Feb 13 '21 at 01:08
  • @00110001 I apologize for the lack of clarity within the code. I tried my best to get my point across without copying the whole solution over. I did went through and debugged it, that's how I noticed it was jumping out of the task into the view model to "get" the "_rowDetailsGrid" before the task was even completed... – OrionsBelt Feb 13 '21 at 01:32
  • You may want to await the method: ShowAbsentStudents(); – rufw91 Feb 13 '21 at 14:58

0 Answers0