Task.Run blocks the main thread (frozen interface)

I am trying to make an asynchronous call to load data into my grid. The problem is that the operation blocks the user interface (it works in the main thread) - and I do not know why. I am trying to do this to get data in the background ... Here is the code:

Binding the ViewModel class to the DataContext of the main window:

<Window.DataContext>
    <vm:MainWindowViewModel WindowTitle="MVVM" BtnLoadText="LOAD DATA"/>
</Window.DataContext>

DataGrid with column binding to the collection property (PeopleList) in the ViewModel class:

    <DataGrid AutoGenerateColumns="False" IsReadOnly="True" ItemsSource="{Binding Path=PeopleList, Mode=TwoWay}" Margin="5">
        <DataGrid.Columns>
            <DataGridTextColumn Header="First name" Binding="{Binding Path=FirstName}"/>
            <DataGridTextColumn Header="Last name" Binding="{Binding Path=LastName}"/>
            <DataGridTextColumn Header="Age" Binding="{Binding Path=Age}"/>
        </DataGrid.Columns>
    </DataGrid>
    <Button x:Name="btn_LoadData" Margin="5" Grid.Row="1" Content="{Binding Path=BtnLoadText}" Click="btn_LoadData_Click"/>

The code behind MainWindow is to trigger an asynchronous button click event:

public partial class MainWindow : Window
{
    private MainWindowViewModel mainWindowViewModel;
    public MainWindow()
    {
        InitializeComponent();
        mainWindowViewModel = (MainWindowViewModel)DataContext;
    }

    private async void btn_LoadData_Click(object sender, RoutedEventArgs e)
    {
        await mainWindowViewModel.LoadData();
    }
}

ViewModel class responsible for MainWindow:

class MainWindowViewModel
{
    public string WindowTitle { get; set; }
    public string BtnLoadText { get; set; }

    public ObservableCollection<Person> PeopleList { get; set; }

    private Database database = new Database();

    public MainWindowViewModel()
    {
        PeopleList = new ObservableCollection<Person>();
    }

    public async Task LoadData()
    {
        PeopleList.Clear();

        var result = await database.GetPeopleListLongOperationAsync();

        PeopleList.Add(result.First());
    }
}

As you can see, I make an asynchronous call using the LoadData method, which gets the data from the database and adds it to the ObservableCollection, which updates the DataGrid (binding to the DataGrid)

, "" :

public class Database
{
    public IEnumerable<Person> GetPeopleListLongOperation()
    {
        // forcing "long" data load
        Thread.Sleep(5000);
        yield return new Person() { FirstName = "Name", LastName = "LastName", Age = new Random().Next(18, 40) };
    }

    public Task<IEnumerable<Person>> GetPeopleListLongOperationAsync()
    {
        return Task.Run<IEnumerable<Person>>(() =>
        {
            return GetPeopleListLongOperation();
        });
    }
}

Task.Run . , .

? , ...

IEnumerable to List . - , ?

    public Task<List<Person>> GetPeopleListLongOperationAsync()
    {
        return Task.Run<List<Person>>(() =>
        {
            return GetPeopleListLongOperation().ToList();
        });
    }
+4
1

:

public IEnumerable<Person> GetPeopleListLongOperation()
{
    // forcing "long" data load
    Thread.Sleep(5000);
    yield return new Person();
}

GetPeopleListLongOperation(), , 5 . , , ; Thread.Sleep(5000) .

, , , ToList , . result.First() .

+5

Source: https://habr.com/ru/post/1673762/


All Articles