在SessionWith中,当任务本身工作得太快时,Wpf UI bahaviour的陌生感

时间:2015-02-13 08:58:49

标签: c# wpf task

模拟错误的代码。

XAML:

                                                                              

    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0"
                Grid.Column="0"
                Margin="5,5,5,0"
                FontSize="14"
                HorizontalAlignment="Right"
                Text="User:">
    </TextBlock>
    <TextBox  Grid.Row="0"
                Grid.Column="1"
                Margin="5,5,5,0"
                Name="_txtLogin" 
                Text="{Binding Login}"/>
    <Button Grid.Row="1"
            Grid.Column="1" 
            Content="Ok"
            Width="100" 
            VerticalAlignment="Center" 
            HorizontalAlignment="Center" 
            Click="AutentificateClick" 
            Padding="0,2,0,2" 
            IsDefault="True" 
            Name="_btnOk" 
            />
</Grid>

代码:

private Boolean _isFirstTime = true;

public Window2()
{
    InitializeComponent();
    DataContext = this;
}

private void AutentificateClick(Object sender, RoutedEventArgs e)
{
    _btnOk.IsEnabled = false;
    Cursor = Cursors.Wait;

    Task<Boolean>.Factory.StartNew(InitConnection).ContinueWith(t =>
    {
        if (!t.Result)
            return;

        // Emulate some work after connection's been established
        Thread.SpinWait(1000000000); (2)

        _btnOk.IsEnabled = true;
        Cursor = Cursors.Arrow;

    }, TaskScheduler.FromCurrentSynchronizationContext());
}

private Boolean InitConnection()
{
    Thread.SpinWait(10000000); (1)
    return true;

    if (_isFirstTime)
    {
        // Emulate some work to establish connection
        Thread.SpinWait(10000000); (1)
        _isFirstTime = false;
    }

    return true;
}

上面的代码工作正常。要在InitConnection方法:

中模拟错误评论plz这些字符串
Thread.SpinWait(10000000); (1)
return true;

并多次点击确定按钮。现在您可以看到Cursor始终正常,它会发生变化。但按钮的IsEnabled属性并不经常发挥作用。按钮按住Enabled

是否还有一个WPF错误还是有任何合理的解释?

.Net 4.0,Win 7

1 个答案:

答案 0 :(得分:2)

使用TaskScheduler.FromCurrentSynchronizationContext()将告诉您的任务在UI线程上执行。

当您调用Thread.SpinWait(1000000000)时;用户界面将变得无法响应(如果您尝试执行任何操作,您会注意到这一点,例如拖动窗口等),因此无法保证禁用该按钮。

所以最初,我建议你删除TaskScheduler.FromCurrentSynchronizationContext(),但这样做意味着你不能在任务结束时重新启用按钮,因为你将不再在UI线程上。如果您按如下方式重新编写AutentificateClick方法,我认为您会发现它可以执行您想要的操作,并且UI将在任务执行时保持响应。

private void AutentificateClick(Object sender, RoutedEventArgs e)
{
    _btnOk.IsEnabled = false;
    Cursor = Cursors.Wait;         

    Task<Boolean>.Factory.StartNew(InitConnection).ContinueWith(t =>
    {        
         if (!t.Result)
             return;

         // Emulate some work after connection's been established
         Thread.SpinWait(1000000000);

         this.Dispatcher.Invoke((Action)(() =>
         {
             _btnOk.IsEnabled = true;
             Cursor = Cursors.Arrow;
         }));                                
    });        
}