'Binding Task<List<T>> to DataGrid WPF C#
My problem is that I'm trying to make a Task<List> binding to a DataGrid in my WPF application, but I don't understand what the problem is and what I'm doing wrong. I have 3 models
DisciplineGroupTeacher:
public class DisciplineGroupTeacher
{
[JsonPropertyName("iddiscipline-group-teacher")]
public int IdDisciplineGroupTeacher { get; set; }
[JsonPropertyName("idteacher")]
public int? IdTeacher { get; set; }
[JsonPropertyName("iddiscipline")]
public int IdDiscipline { get; set; }
[JsonPropertyName("idgroup")]
public int IdGroup { get; set; }
public async Task<Teacher> Teacher() => await DataWorker.GetTeacher(IdTeacher);
public async Task<Group> Group() => await DataWorker.GetGroup(IdGroup);
public async Task<Discipline> Discipline() => await DataWorker.GetDiscipline(IdDiscipline);
}
Teacher:
public class Teacher
{
[JsonPropertyName("idteacher")]
public int IdTeacher { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
}
Group:
public class Group
{
[JsonPropertyName("idgroup")]
public int IdGroup { get; set; }
[JsonPropertyName("group_name")]
public string Name { get; set; }
[JsonPropertyName("iddepartment")]
public int IdDepartment { get; set; }
}
Discipline:
public class Discipline
{
[JsonPropertyName("iddiscipline")]
public int IdDiscipline { get; set; }
[JsonPropertyName("discipline_name")]
public string Name { get; set; }
}
In Data Worker, I have methods get from the API:
public class DataWorker
{
public static async Task<Teacher> GetTeacher(int? id)
{
var client = new HttpClient();
var streamTask = client.GetStreamAsync($"myurl...");
var data = await JsonSerializer.DeserializeAsync<Teacher>(await streamTask);
return data;
}
public static async Task<Discipline> GetDiscipline(int id)
{
var client = new HttpClient();
var streamTask = client.GetStreamAsync($"myurl...");
var data = await JsonSerializer.DeserializeAsync<Discipline>(await streamTask);
return data;
}
public static async Task<Group> GetGroup(int id)
{
var client = new HttpClient();
var streamTask = client.GetStreamAsync($"myurl...");
var data = await JsonSerializer.DeserializeAsync<Group>(await streamTask);
return data;
}
}
At a certain event, I get a BindingList in which I get a List and I make a binding to the DataGrid
BindingList<DisciplineGroupTeacher> dgts= new BindingList<DisciplineGroupTeacher>(await DataWorker.GetDisciplineGroupTeachers());
MyDataGrid.ItemsSource = dgts;
In XAML I do Binding
<DataGrid x:Name="MyDatGrid" AutoGenerateColumns="False" CanUserAddRows="False" ColumnWidth="*" IsReadOnly="True" FontSize="13">
<DataGrid.Columns>
<materialDesign:DataGridTextColumn Header="Discipline" Binding="{Binding Discipline.Name}"/>
<materialDesign:DataGridTextColumn Header="Group" Binding="{Binding Group.Name}"/>
<materialDesign:DataGridTextColumn Header="Teacher" Binding="{Binding Teacher.Name}"/>
</DataGrid.Columns>
</DataGrid>
But when I start, the fields I need do not appear in the datagrid. What am I doing wrong? I met async await recently. Before that, the application worked with a local database, but now i need to get data from the API.
Solution 1:[1]
It's hard to answer because the DataContext is unclear, but in general:
You want to bind to ObservableCollection<T> properties on ViewModels.
If this list is generated asynchronously, a VM would make a call to an async function on the model that would eventually restore the list. After awaiting this call, you would populate the ViewModel collection (which would raise events every time the collection has changed) or create a new one and raise property changed event manually.
No need to use blocking waits on async operations, and if it's done from the UI thread it will usually lead to deadlocks.
I also noticed that your methods on DisciplineGroupTeacher are deserializing data every time they're called, which is probably not what you want.
Solution 2:[2]
The issue is that you are trying to bind to a property that doesn't exist. For example, consider your first binding for Discipline.Name. There is no Discipline property on your DisciplineGroupTeacher, right? Although there is a Discipline() method, (await Discipline()).Name (which should have the name value) is not the same as Discipline.Name (which does not exist).
Now that we know the problem, how do we fix it. You should:
add a property for each element onto your class (e.g. add Discipline, Teacher, and Group)
get the value of each one in your data loading function
If you cannot run Discipline.Name synchronously from your code to get a valid value that has already been retrieved from your data source, then neither can your UI.
If any of this doesn't make sense, just let me know. I'm happy to expand on it to make sure you can move forward.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | asaf92 |
| Solution 2 | John Glenn |
