Я немного в замешательстве от сложившейся ситуации. Если я вызываю метод SleepBeforeInvoke
, приложение приостанавливается на строку _task.Wait();
. Но если я назову метод SleepAfterInvoke
, приложение работает нормально, и управление достигнет catch
. Вызов метода BeginInvoke
также прекрасен.Отмена заданий отменяет UI
Может ли кто-нибудь объяснить с максимальными подробностями, в чем разница между этими тремя методами использования? Почему приложение приостановлено, если я использую метод SleepBeforeInvoke
, и почему это не так, если я использую методы SleepAfterInvoke
и BeginInvoke
? Благодарю.
Win 7, .Net 4.0
XAML:
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
Name="_textBlock"
Text="MainWindow"></TextBlock>
<Button Grid.Row="1"
Click="ButtonBase_OnClick"></Button>
</Grid>
.cs:
public partial class MainWindow : Window
{
private readonly CancellationTokenSource _cts = new CancellationTokenSource();
private Task _task;
/// <summary>
/// Application wiil be suspended on string _task.Wait();
/// </summary>
private void SleepBeforeInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(500);
Application.Current.Dispatcher.Invoke(new Action(() => { }));
}
}
/// <summary>
/// Works fine, control will reach the catch
/// </summary>
private void SleepAfterInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Application.Current.Dispatcher.Invoke(new Action(() => { }));
Thread.Sleep(500);
}
}
/// <summary>
/// Works fine, control will reach the catch
/// </summary>
private void BeginInvoke()
{
for (Int32 count = 0; count < 50; count++)
{
if (_cts.Token.IsCancellationRequested)
_cts.Token.ThrowIfCancellationRequested();
Thread.Sleep(500);
Application.Current.Dispatcher.BeginInvoke(new Action(() => { }));
}
}
public MainWindow()
{
InitializeComponent();
_task = Task.Factory.StartNew(SleepBeforeInvoke, _cts.Token, TaskCreationOptions.None, TaskScheduler.Default);
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
try
{
_cts.Cancel();
_task.Wait();
}
catch (AggregateException)
{
}
Debug.WriteLine("Task has been cancelled");
}
}
Задача async должна заменить вашу потребность в потоке. Если вы не знаете, что делаете, придерживайтесь Single Threaded Async. Также прочитайте блог Стивена Клири в асинхронном режиме. – Aron
@Aron, .net 4.0 :(no async-wait – monstr
Я бы предложил использовать Rx.Net в этом случае. Или обновить ... серьезно ... его стоит обновить ... хотя бы потому, что нарушена 'Task'. net 4.0, НЕ ИСПОЛЬЗУЙТЕ ЭТО. 'Task.ContinueWith' # $% * добавляет ваш' SynchronizationContext.Current' и в основном разбивает как WinForms, так и WPF. – Aron