2

我正在尝试在单独的线程中运行 for 循环,以便 UI 应该是响应式的并且进度条是可见的。

问题是我不知道该怎么做:)。在这段代码中,进程在单独的线程中开始,但代码的下一部分同时执行。messageBox 被显示并且结果永远不会被返回(例如列表框的 selected index 属性永远不会被设置)。

即使我使用“taskEx.delay()”,它也不起作用。

            TaskEx.Run(() =>
                {
                    for (int i = 0; i < sResults.Count(); i++)
                    {

                        if (sResults.ElementAt(i).DisplayIndexForSearchListBox.Trim().Contains(ayaStr))
                        {
                            lstGoto.SelectedIndex = i;
                            lstGoto_SelectionChanged(lstReadingSearchResults, null);
                            IsIndexMatched = true;
                            break;
                        }
                    }
                });

        //TaskEx.delay(1000);
        if (IsIndexMatched == true)
            stkPanelGoto.Visibility = Visibility.Collapsed;
        else //the index didn't match
        {
            MessagePrompt.ShowMessage("The test'" + ayaStr + "' does not exist.", "Warning!");
        }

谁能告诉我如何使用带有“for”或“foreach”循环的多线程?

4

3 回答 3

5

你需要使用Task.Wait()

试试这个:

TaskEx.Wait();
if (IsIndexMatched == true)
    stkPanelGoto.Visibility = Visibility.Collapsed;

如果要限制等待时间可以给出Wait()时间参数或TimeSpan,例如:

TaskEx.Wait(10000)

您也可以将其与 CancellationToken 一起使用,
或者将 CancellationToken 和时间限制结合使用

阅读 MSDN 上的所有选项:http:
//msdn.microsoft.com/en-us/library/dd235635.aspx

于 2012-07-01T08:56:13.027 回答
2

TaskEx- 您是否使用 .NET 4.0 的异步目标包?在这种情况下,使用await TaskEx.Run(...)- C# 5.0await将等待任务完成,但会在等待时保持 UI 响应(与.Wait()方法不同)。

此外,您需要将lstGoto.SelectedIndex = i;分配移出后台线程 - 仅允许在主线程上访问 UI 控件。

    int index = await TaskEx.Run(() =>
            {
                // ensure that sResults is a List<T> - call .ToList() if necessary
                for (int i = 0; i < sResults.Count; i++)
                {

                    if (sResults[i].DisplayIndexForSearchListBox.Trim().Contains(ayaStr))
                    {
                        return i;
                    }
                }
                return -1; // nothing found
            });

    //await TaskEx.Delay(1000);
    if (index >= 0)
    {
        stkPanelGoto.Visibility = Visibility.Collapsed;
        lstGoto.SelectedIndex = i;
        lstGoto_SelectionChanged(lstReadingSearchResults, null);
    }
    else //the index didn't match
    {
        MessagePrompt.ShowMessage("The test'" + ayaStr + "' does not exist.", "Warning!");
    }

最后一句警告:不要在循环中重复使用Count()/ ElementAt()- 这些 LINQ 方法最终可能会遍历整个集合来计算它们的结果。如果需要按索引遍历 IEnumerable,将其转换为 List 一次,然后遍历该列表会快得多。

于 2012-07-01T09:12:14.327 回答
2

应用修复后的代码。

int index = -1;
IEnumerable<dictSearchResults> sResults = (IEnumerable<dictSearchResults>)lstGoto.DataContext;
//Makin a list of all the DisplayIndex from the IEnumerable object
var lstGotoResults= sResults.Select(rec => rec.DisplayIndexForSearchListBox.ToString()).ToList();

index = await TaskEx.Run(() =>
{
    return lstGotoResults.IndexOf(ayaIndexStr);
});


if (index >= 0)
{ 
    lstGoto.SelectedIndex = index ;
    lstGoto_SelectionChanged(lstReadingSearchResults, null);
    stkPanelGoto.Visibility = Visibility.Collapsed;
}

将 IEnumerable 转换为 List 后,代码非常高效,我怀疑是否应该使用TaskEx. 没有时间让进度条可见:)

谢谢丹尼尔的提示!

于 2012-07-01T12:27:04.070 回答