C#aync等待-桂冻结时失去焦点



我最近决定研究一下C#5的新异步/等待特性。出于演示目的,我编程了一个Windows窗体应用程序,允许用户获取一个整数数组,并使用他们选择的排序例程对其进行排序。在这个程序中,我提供了五个test.dat文件,每个文件都包含未排序的数据,从32000个整数开始,每个后续文件的大小都会翻倍。该程序将文件中的数据读取到一个int数组中,以便进行排序

我遇到的问题是GUI冻结并且变得完全没有响应。但是,只有将GUI本身放在后台时,它才会冻结。也就是说,我看不见它,因为我可能正忙于浏览互联网等。它可能不会立即冻结。有时我可能会让它重新聚焦,它仍然有效,但最终会失败。如果我让程序始终处于焦点状态,GUI将保持完全响应。我可以在屏幕上拖动它。我可以最小化和最大化它。在结果表显示经过的排序时间之前,一个字幕式的进度条会产生动画,我可以继续点击按钮等。

现在我要补充一点,我不认为这是排序算法本身的问题。我的理由是,当GUI处于焦点时,它可以很好地工作。我还有一整套单元测试来验证每个算法是否正常工作。运行时间似乎是一个问题,因为Heap或Quick sort等更快的算法可以处理非常大的数据集,而不会导致冻结。最后,我尝试在等待Task的表单级别和任务本身内部捕获异常,但似乎没有抛出异常。

在过去的两天里,我只研究了async/await,我决不是一个专家,但我最初的想法是,当重新聚焦时,它可能与GUI重新绘制有关。有人能帮忙吗?以下是代码的帮助部分:-

示例SelectionSort例程:-

public SelectionSort(IStopwatch stopwatch) : base(stopwatch){}
    public override async Task<int[]> SortAsync(int[] data, CancellationToken cancelToken)
    {
        OnStarted();           
        Stopwatch.Start();
        await Task.Run(() =>
            {
                int i, j;
                int min, temp;
                for (i = 0; i < data.Length - 1; i++)
                {
                    if (cancelToken.IsCancellationRequested)
                        return;
                    min = i;
                    for (j = i + 1; j < data.Length; j++)
                    {
                        if (data[j] < data[min])
                            min = j;
                    }
                    temp = data[i];
                    data[i] = data[min];
                    data[min] = temp;
                }
            }, cancelToken);
        Stopwatch.Stop();
        OnCompleted(new SortCompleteEventArgs(Stopwatch.ElapsedMilliseconds, data.Length, cancelToken.IsCancellationRequested));
        return data;
    }

处理每个分拣例程的分拣机上下文(策略模式):-

public class SorterContext
{
    private readonly SortRoutine _sortRoutine;
    public SorterContext(SortRoutine sortRoutine)
    {
        _sortRoutine = sortRoutine;
    }
    public async Task<int[]> Sort(int[] dataToSort, CancellationToken cancellationToken)
    {
        if(dataToSort == null) 
            throw new ArgumentNullException("dataToSort");
        if(dataToSort.Length == 1) 
            throw new ArgumentOutOfRangeException("dataToSort");
        int[] result = await _sortRoutine.SortAsync(dataToSort, cancellationToken);
        return result;
    }

来自Windows窗体单击事件处理程序的调用:-

private async void StartSorting_Click(object sender, EventArgs e)
    {
        if (_lBoxSelectedFiles.Items.Count == 0)
        {
            MessageBox.Show("Select data to sort");
            return;
        }
        _btnCancelSort.Enabled = true;
        if (_comboBxAlgorithm.SelectedValue.Equals("SelectSort"))
        {
            var selectSort = new SelectSort(new SortStopwatch());
            selectSort.Completed += DisplaySortResults;
            _sorter = new SorterContext(selectSort);
            StartProgressBar();
             await _sorter.Sort(_dataToSort, _cancelTokenSrcWrapper.Token);   
        }

异步代码似乎没有任何问题。当排序后引发OnComplete事件时,主窗体中的处理程序会实例化一个新的结果窗体并显示它。当窗体失去焦点时,这会失败。我正在调查为什么会出现这种情况,以及这是否是一个深思熟虑的框架设计决定。无论如何,我只是从处理程序中调用了方法Activate()。这使应用程序成为焦点,然后我实例化了新表单,它运行良好。至少对我来说是这样。例如:-

private void DisplaySortResults(object sender, SortCompleteEventArgs e)
    {
        Activate();
        _btnCancelSort.Enabled = false;
        _progressBar.Style = ProgressBarStyle.Continuous;
        var sortResults = new SortResults();
        sortResults.BuildResults(e);
        sortResults.SetCompletedValues(e);
        sortResults.ShowDialog();
    }

最新更新