Блокировка основного потока при первом переходе на страницу - PullRequest
0 голосов
/ 06 марта 2020

Проблема

При запуске приложения открывается пустая страница Home. Я go на вкладке Vendors, и она зависает на несколько секунд (я вижу, что пользовательский интерфейс заморожен). После этого отображается страница Vendors. Элементы содержат данные из базы данных.

Можно подумать, что блокировка была вызвана загрузкой данных из базы данных. Но это происходит в async/await методах.

Если после одного из загруженных из Vendors вернуться к Home и обратно к Vendors - заморозка отсутствует. Страница открывается практически мгновенно. В этом случае также происходит механизм загрузки данных (Loaded event)

. Оказывается, что остановка происходит только с чистого запуска при первом посещении страницы Vendros. В чем может быть проблема?

GIF

enter image description here

Код

Просмотр

<i:Interaction.Behaviors>
    <ic:EventTriggerBehavior EventName="Loaded">
        <ic:InvokeCommandAction Command="{x:Bind ViewModel.PageLoadedCommand}" />
    </ic:EventTriggerBehavior>
</i:Interaction.Behaviors>

VendorsViewModel

public ICommand PageLoadedCommand {get;}
private async void OnPageLoaded(RoutedEventArgs args)
{
    await VendorsService.InitializeAsync();

    BankItems = VendorsService.BankItems;
    AuthorityItems = VendorsService.AuthorityItems;
    VendorItems = VendorsService.VendorItems;
}

public ObservableCollection<VendorModel> VendorItems {get; set;}
public ObservableCollection<TwoLinesModel> BankItems {get; set;}
public ObservableCollection<TwoLinesModel> AuthorityItems{get; set;}

VendorService

private TwoLinesService<BankEntity> BankService { get; } = new TwoLinesService<BankEntity>();
private TwoLinesService<AuthorityEntity> AuthorityService { get; } = new TwoLinesService<AuthorityEntity>();

public ObservableCollection<VendorModel> VendorItems { get; private set; }
public ObservableCollection<TwoLinesModel> BankItems { get; private set; }
public ObservableCollection<TwoLinesModel> AuthorityItems { get; private set; }

public async Task InitializeAsync()
{
    await BankService.InitializeAsync();
    await AuthorityService.InitializeAsync();

    VendorItems = new ObservableCollection<VendorModel>
    {
        new VendorModel { Name = "Name 1", Surname = "Surname 1", Patronymic = "MiddleName 1", IssueDate = new DateTime(2020, 2, 9) },
        new VendorModel { Name = "Name 2", Surname = "Surname 2", Patronymic = "MiddleName 2", IssueDate = new DateTime(2019, 3, 7) }
    };
    BankItems = BankService.Items;
    AuthorityItems = AuthorityService.Items;

    await Task.CompletedTask;
}

TwoLinesService

public class TwoLinesService<TEntity> 
    where TEntity : TwoLinesEntity, new()
{
    private IDataServiceFactory<TEntity> DataServiceFactory { get; } = new DataServiceFactory<TEntity>();
    public ObservableCollection<TwoLinesModel> Items { get; } = new ObservableCollection<TwoLinesModel>();

    public async Task InitializeAsync()
    {
        using var dataService = DataServiceFactory.Create();

        foreach (var entity in await dataService.SelectAll())
        {
            Items.Add(CreateModel(entity));
        }

        await Task.CompletedTask;
    }

    public TwoLinesModel CreateModel(TEntity source)
    {
        return new TwoLinesModel
        {
            ID = source.ID,
            Title = source.Title,
            Text = source.Text,
            CreatedOn = source.CreatedOn,
            LastModifiedOn = source.LastModifiedOn
        };
    }
}

DataServiceFactory

public class DataServiceFactory<T> : IDataServiceFactory<T> where T : DomainEntity
{
    public IDataService<T> Create()
    {
        return Configuraiton.Current.DataProvider switch
        {
            DataProviderType.SQLite => new SQLiteService<T>(Configuraiton.Current.SQLiteConnectionString),
            _ => throw new NotImplementedException()
        };
    }
}

SelectAll ()

public partial class GenericDataService<T> : IDataService<T> where T : DomainEntity
{
    private readonly DbContext _dbContext;
    public GenericDataService(DbContext dbContext) => _dbContext = dbContext;

    public async Task<IList<T>> SelectAll()
    {
        return await _dbContext.Set<T>().ToListAsync();
    }
}

Ответы [ 2 ]

1 голос
/ 07 марта 2020

Это может быть распространенной ошибкой в ​​асинхронном программировании в UWP. Использование async / await / Task не эквивалентно запуску кода в фоновом потоке. Если вы хотите выполнить какое-то трудоемкое задание в фоновом потоке, вам нужно обернуть его в Task.Run (). В противном случае UI-поток будет заблокирован.

Попробуйте использовать Task.Run в SelectAll () в любом случае.

public Task<IList<T>> SelectAll()
{
    return Task.Run(async ()=> { return await _dbContext.Set<T>().ToListAsync(); });
}
0 голосов
/ 07 марта 2020

Описание

Мне удалось найти узкое место. Программа находится на ранней стадии разработки. Во время запуска программа не вызывает методы, связанные с базой данных. С помощью Debug Output я обнаружил, что при первом вызове DataServiceFactory.Create() загружаются новые компоненты. Сразу после этого остановка пользовательского интерфейса заканчивается.

"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Threading.Tasks.Extensions.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Linq.Expressions.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Resources.ResourceManager.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Diagnostics.Tracing.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.ComponentModel.TypeConverter.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "Anonymously Hosted DynamicMethods Assembly". 
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Data.Common.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.ComponentModel.Primitives.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Transactions.Local.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.ComponentModel.Annotations.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Threading.Timer.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Threading.Thread.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Text.RegularExpressions.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Buffers.dll".
"ProgramName.exe" (CoreCLR: CoreCLR_UWP_Domain). Loaded "C:\Program Files\WindowsApps\Microsoft.NET.CoreFramework.Debug.2.2_2.2.27909.0_x64__8wekyb3d8bbwe\System.Memory.dll".

Решение

Основным решением является загрузка данных при запуске. На этом этапе загружать нечего.

Я нахожу два временных решения.

  • Назовите создание фабрики в App.xaml.cs. Это загружает большинство компонентов.
var dataServiceFactory = new DataServiceFactory<VendorEntity>();
var dataService = dataServiceFactory.Create();
  • Или инициировать запуск в обработчике событий OnPageLoaded(), используя Task.Run()
private async void OnPageLoaded(RoutedEventArgs args)
{
    await Task.Run(() => VendorsService.InitializeAsync());
    ...
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...