I come from VB6 where everything is single threaded, so I've never written a lick of multi-threaded code before. I just added a wait cursor to one of our GUI's by stumbling through the docs, but I'm unsure I've done it the best way. Did I?Control is a Winform view and the code below is located in the presenter class. Full file can be found on GitHub.     private void RefreshToDoList(object sender, EventArgs e)    {        try        {            Cursor.Current = Cursors.WaitCursor;            var getItems = new Task<IOrderedEnumerable<ToDoItem>>(() => GetItems());            getItems.Start();            Control.TodoItems = getItems.Result;        }        finally        {            Cursor.Current = Cursors.Default;        }    }private IOrderedEnumerable<ToDoItem> GetItems(){    var items = new ConcurrentBag<ToDoItem>();    var projects = VBE.VBProjects.Cast<VBProject>();    Parallel.ForEach(projects,        project =>        {            var modules = _parser.Parse(project);            foreach (var module in modules)            {                var markers = module.Comments.AsParallel().SelectMany(GetToDoMarkers);                foreach (var marker in markers)                {                    items.Add(marker);                }            }        });    var sortedItems = items.OrderBy(item => item.ProjectName)                            .ThenBy(item => item.ModuleName)                            .ThenByDescending(item => item.Priority)                            .ThenBy(item => item.LineNumber);    return sortedItems;}
Displaying a wait cursor while we're waiting
c#;multithreading;gui
You shouldn't use Task.Run or Task.Factory.StartNew unless you specifically want to put your work on a new thread, which Parallel.ForEach already does. Also the order by is not executed in your async block by the task, it is executed as it is assigned. This is probably not what you want so you should do a .ToArray at the end of the order by sequence.private async Task<IOrderedEnumerable<ToDoItem>> GetItems(){    await Task.Yield(); //returns the Task here so the UI can process    var items = new ConcurrentBag<ToDoItem>();    var projects = VBE.VBProjects.Cast<VBProject>();    Parallel.ForEach(projects, project =>    {        var modules = _parser.Parse(project);        foreach (var module in modules)        {            var markers = module.Comments.AsParallel().SelectMany(GetToDoMarkers);            foreach (var marker in markers)            {                items.Add(marker);            }        }    });    var sortedItems = items.OrderBy(item => item.ProjectName)                        .ThenBy(item => item.ModuleName)                        .ThenByDescending(item => item.Priority)                        .ThenBy(item => item.LineNumber).ToArray();    return sortedItems;}Then in your Refresh:private async void RefreshToDoList(object sender, EventArgs e){    try    {        Cursor.Current = Cursors.WaitCursor;        Control.ToDoItems = await GetItems();    }    finally    {        Cursor.Current = Cursors.Default;    }}