4

I tried to run a task for a WPF UI Code Behind . but it doesn't work and noting happend when I use Task.Factory but it works when I use the code without Task.Factory

public MainWindow()
{
    InitializeComponent();

    GetNews();
}

private void GetNews()
{
    Task.Factory.StartNew(() =>
    {
        FeedReader reader = new FeedReader();
        var news = reader.RetrieveFeed("http://www.bbc.com/feed/");
        foreach (var item in news)
        {
            textBlock.Text = item.Title;
        }
    });
}

How can I use async/await or anything that prevent block main thread?

4
  • Please update your question and explain what you mean when you say "it doesn't work". Does the code not run at all (verified with a debugger breakpoint)? Does it run but have no visible effect? Are exceptions being thrown? Is the application crashing? Also, what is the "textBlock" variable actually referencing? Commented Mar 26, 2017 at 8:34
  • @Xavier I edited my question. textBlock is a control in my xaml UI Commented Mar 26, 2017 at 8:39
  • But, you are setting in a loop the same control... so at the end its text will be the title of the last item. Commented Mar 26, 2017 at 8:48
  • @OfirWinegarten it's not important, I know Commented Mar 26, 2017 at 10:35

2 Answers 2

11

Nothing happens because an exception is thrown as you are trying to modify UI element outside of UI thread. You should either use textBlock.Dispatcher.Invoke method or make FeedReader asynchronous and use async/await in your method, which is preferable.

So the prefered solution would be (provided RetrieveFeed is async method):

private async void GetNews()
{
    FeedReader reader = new FeedReader();
    var news = await reader.RetrieveFeed("http://www.bbc.com/feed/");
    foreach (var item in news)
    {
        textBlock.Text = item.Title;
    }
}

Alternatively you could wrap feed retrieval in a task, which will work with your current implementation:

private async void GetNews()
{
    FeedReader reader = new FeedReader();
    var news = await Task.Run(() => reader.RetrieveFeed("http://www.bbc.com/feed/"));
    foreach (var item in news)
    {
        textBlock.Text = item.Title;
    }
}

This approach will work because await will capture SynchronizationContext of UI thread and will set value to the textbox in UI thread.

And the caveat here is that exceptions thrown in async void method are never observed and are lost. So you should wrap the code inside GetNews method in try/catch block and at least log the exception so you are aware of it.

Sign up to request clarification or add additional context in comments.

7 Comments

You don't show how to call an async method from the constructor.
@HenkHolterman, nothing changes there, the method is async void.
for first solution an error occurs: 'IEnumerable<FeedItem>' does not contain a definition for 'GetAwaiter' and no extension method 'GetAwaiter' accepting a first argument of type 'IEnumerable<FeedItem>' could be found
@Mike yes, that's correct. I have added a note that the method should be changed to become asynchronous.
Async void methods do not swallow exceptions; they raise them on the SynchronizationContext that was active at the beginning of the method.
|
2

You can use the async version to retrieve the feed

SyndicationFeed feed = await client.RetrieveFeedAsync(uri).AsTask(ct);
DisplayResults(feed);

Check the example from msdn.

It calls the Windows Runtime method, RetrieveFeedAsync, and applies a .NET Framework extension method, AsTask, to the returned IAsyncOperation instance. AsTask represents the instance as a Task, so that you can await it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.