2015-09-28 5 views
0

Я не могу понять это ... Я следил за несколькими различными инструкциями, которые я нашел повсюду, но я не могу понять, как не заморозить поток пользовательского интерфейса при выполнении нескольких задач.Как не замораживать поток пользовательского интерфейса?

Я запускаю это, когда окно загружается. В корне окна в MainWindow.xaml у меня есть:

<i:Interaction.Triggers> 
    <i:EventTrigger EventName="ContentRendered"> 
     <i:InvokeCommandAction Command="{Binding WindowLoaded}" /> 
    </i:EventTrigger> 
</i:Interaction.Triggers> 

Это вызывает следующее:

private void WindowLoadedEx(object p) 
{ 
    DBMan(); 
    LoadValues(); 
    //Boot = false; 
    //MainMenuVisibility = true; 
} 

DBMan() является negligable, проблема не здесь - это в LoadValues ​​() , Я расколол и сильно изменил это, пытаясь найти разные вещи, ничего не работая.

private void LoadValues() 
{ 
    //ThreadStart AddHeroesRef = new ThreadStart(HeroesDBAddHeroes); 
    //Thread AddHeroesThread = new Thread(AddHeroesRef); 
    //AddHeroesThread.Start(); 
    ////HeroesDBAddHeroes(); 
    //ThreadStart AddCommentsRef = new ThreadStart(HeroesDBAddComments); 
    //Thread AddCommentsThread = new Thread(AddCommentsRef); 
    //AddCommentsThread.Start(); 
    ////HeroesDBAddComments(); 
    ThreadStart LoadValuesRef = new ThreadStart(LoadValuesThreaded); 
    Thread LoadValuesThread = new Thread(LoadValuesRef); 
    LoadValuesThread.Start(); 
    //HeroesDBAssignComments(); 
    //SetDBIDs(); 
} 

private async void LoadValuesThreaded() 
{ 
    ThreadStart AddHeroesRef = new ThreadStart(HeroesDBAddHeroes); 
    Thread AddHeroesThread = new Thread(AddHeroesRef); 
    AddHeroesThread.Start(); 
    //HeroesDBAddHeroes(); 
    ThreadStart AddCommentsRef = new ThreadStart(HeroesDBAddComments); 
    Thread AddCommentsThread = new Thread(AddCommentsRef); 
    AddCommentsThread.Start(); 
    //HeroesDBAddComments(); 

    while (AddHeroesThread.IsAlive || AddCommentsThread.IsAlive) 
    { 
     Thread.Sleep(1); 
    } 
    HeroesDBAssignComments(); 
    SetDBIDs(); 

    Boot = false; 
    MainMenuVisibility = true; 
} 

(Как вы можете видеть, ive попытался изменить разные вещи и не мог заставить что-либо работать).

В общем, и HeroesDBAddHeroes(), и HeroesDBAddComments() необходимо запускать вместе, у них нет конфликтов друг с другом и т. Д. В будущем у меня будут другие методы для запуска, в то же время в отдельных потоках.

Однако, я должен дождаться, когда все это будет завершено, прежде чем продолжить и разрешить запуск HeroesDBAssignComments(). Если все выше уже не будет полным, оно не будет работать. Затем мне нужно изменить логические значения Boot и MainMenuVisibility после завершения работы с HeroesDBAssignComments.

+0

Вы пытались вызвать метод 'Dispatcher.Invoke (...)'? –

+2

Нельзя использовать Thread.Sleep() для ожидания. Вместо этого используйте [WaitHandle] [1]. [1]: http://stackoverflow.com/questions/2538065/what-is-the-basic-concept-behind-waithandle – Hristo

+0

Где я могу это сделать? – pingu2k4

ответ

0

Нельзя использовать Thread.Sleep() для ожидания. Вместо этого используйте WaitHandle.

Основным способом использования WaitHandle является вызов WaitOne() в том месте, где вы могли бы ожидать, а затем выполнить работу над другим потоком, а затем вызвать Set() на waithandle.

Я обычно использую EventWaitHandle

+0

Это все равно собирается заблокировать поток пользовательского интерфейса, замораживая приложение. – Servy

1

Поскольку вы не указали версию .net я просто предлагаю 4.0 способ борьбы с этим:

void BlockingMethod() { 
    Task.Factory.StartNew(() => { 
     // blocking work here, db loading for example 
    }) 
    .ContinueWith(result => { 
     // update control here with the result of result.Result 
     }, 
     TaskScheduler.FromCurrentSynchronizationContext() 
    }); 
} 

Вы, возможно, придется исправить синтаксис маленький.

Что это значит?

В основном при вызове BlockingMethod он запускает асинхронную задачу. Этот метод будет вызываться пользовательским интерфейсом в вашем случае, поэтому ваш пользовательский интерфейс замерзает.

Поскольку мы асинхронны, код, который мы передали для выполнения, будет работать, когда метод уже оставлен, так как его работа рассматривается картой.

После выполнения тяжелой загрузки будет выполнен код в «ContinueWith». Мы передаем TaskScheduler.FromCurrentSynchronizationContext(), потому что мы должны быть уверены, что этот код выполняется только в том контексте, из которого первоначально был вызван метод (контекст ui sync), иначе вы получите исключение, поскольку wpf не разрешает это.

1

Использование асинхронного шаблона на основе задач (TAP) делает такие проблемы очень простыми.

Ваш метод верхнего уровня WindowLoadedEx может быть объявлен как async void, так как это в основном прославленный обработчик событий.Затем вы можете использовать async/await с захваченным контекстом синхронизации WPF опубликовать изменения пользовательского интерфейса на правильной нити, то есть:

private async void WindowLoadedEx(object p) 
{ 
    DBMan(); 
    await LoadValuesAsync(); 
    Boot = false; 
    MainMenuVisibility = true; 
} 

private async Task LoadValuesAsync() 
{ 
    var addHeroesTask = HeroesDBAddHeroesAsync(); 
    var addCommentsTask = HeroesDBAddCommentsAsync(); 

    // We cannot assign comments or IDs until these have been added 
    await Task.WhenAll(addHeroesTask, addCommentsTask).ConfigureAwait(false); 

    // TODO Should these both also be asynchronous? 
    HeroesDBAssignComments(); 
    SetDBIDs(); 
} 

Примечание Я использовал HeroesDBAddHeroesAsync и HeroesDBAddCommentsAsync, как я считаю, что эти действительно асинхронные операции с базами данных.

Читайте об использовании async/wait here.

Смежные вопросы