-2

I used two Task.Run. In the first one everything works correctly, but in the second an exception is thrown:

Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD).

I do not understand how to solve it. I would like to understand from the code that the Task.Run returns a TextHighlighter. What is the right solution?

xaml:

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid x:Name="CommandGrid" Margin="25,50,0,50" Width="200" HorizontalAlignment="Left">
        <StackPanel x:Name="CommandStack" Orientation="Vertical">
            <Button x:Name="btnFind" Click="btnFind_Click" Content="Find Words" HorizontalAlignment="Stretch" Height="32"/>
            <TextBox x:Name="txbToFind" HorizontalAlignment="Stretch" Height="32" Margin="0,20,0,0"/>
        </StackPanel>
    </Grid>
    <Grid x:Name="BaseGrid" Margin="250,50,50,50" Background="#FFCBF3A6">
        <ScrollViewer x:Name="BaseScroll">
            <RichTextBlock x:Name="TextOneRich" Margin="20,20,35,20"/>
        </ScrollViewer>
    </Grid>
</Grid>

xaml.cs:

public sealed partial class MainPage : Page
{
    public MainPage()
    {
        this.InitializeComponent();
        Paragraph paragraph = new Paragraph();
        paragraph.Inlines.Add(new Run() { Text = "Paste the text here" });
        TextOneRich.Blocks.Add(paragraph);
    }

    private async void btnFind_Click(object sender, RoutedEventArgs e)
    {
        string tofind = txbToFind.Text.ToLower();
        string completeText = string.Empty;

        for (int a = 0; a <= TextOneRich.Blocks.Count - 1; a++)
        {
            Paragraph paragraphCurrent = TextOneRich.Blocks[a] as Paragraph;
            for (int b = 0; b <= paragraphCurrent.Inlines.Count - 1; b++)
            {
                completeText += (paragraphCurrent.Inlines[b] as Run).Text;
            }
        }

        List<int> indexList = await Task.Run(async () => await DoStuffAsync(completeText, tofind)); // Works well
        TextHighlighter HighlighterAll = await Task.Run(async () => await CreateHighlighter(indexList, tofind.Length)); // Generate exception

        TextOneRich.TextHighlighters.Clear();
        TextOneRich.TextHighlighters.Add(HighlighterAll);
    }

    private async Task<TextHighlighter> CreateHighlighter(List<int> listaindex, int lenght)
    {
        TextHighlighter Higlighter = new TextHighlighter() { Foreground = new SolidColorBrush(Colors.White), Background = new SolidColorBrush(Color.FromArgb(255, 7, 58, 77)) };
        for (int a = 0; a <= listaindex.Count - 1; a++)
        {
            Higlighter.Ranges.Add(new TextRange() { StartIndex = listaindex[a], Length = lenght });
        }
        return await Task.FromResult(Higlighter);
    }

    private async Task<List<int>> DoStuffAsync(string myTxt, string toFind)
    {
        bool thereis = true;
        List<int> indexList = new List<int>();
        string remainingText = string.Empty;
        remainingText = myTxt;
        int progressiveIndex = 0;
        int index = 0;
        while (thereis)
        {
            if (remainingText.ToLower().IndexOf(toFind) != -1)
            {
                indexList.Add(remainingText.ToLower().IndexOf(toFind) + progressiveIndex);
                index = remainingText.ToLower().IndexOf(toFind) + 1;
                progressiveIndex += index;
                remainingText = remainingText.Substring(index, remainingText.Length - index);
            }
            else
            {
                thereis = false;
            }
        }
        return await Task.FromResult(indexList);
    }
}

Text to paste: text.

Exception screenshot: exception.

Thanks for your help.

Parsa Karami
  • 702
  • 1
  • 8
  • 30
Jib58
  • 19
  • 5
  • 2
    ref https://stackoverflow.com/questions/33430543/com-0x8001010e-error-when-invoking-from-a-new-thread – programtreasures Jan 31 '18 at 11:29
  • Your `DoStuffAsync` method doesn't appear to do anything that has to be done on the UI thread. `CreateHighligher` does. – Jon Skeet Jan 31 '18 at 11:29
  • And why is an exception created? – Jib58 Jan 31 '18 at 11:33
  • I correct the code. – Jib58 Jan 31 '18 at 11:49
  • So much is wrong with the code. :( The exception should be reasonably clear: you're executing code in the wrong thread. See marked duplicate for information about that. You _could_ fix the problem by following that advice, but you have a more fundamental problem: the work will just wind up back on the UI thread, blocking it while you do it. The only way around this is to do the work in batches, and allow the UI thread time to refresh periodically. Unfortunately, with no [mcve] here, there's no good way to solve the problem you really have. See marked duplicate for solution to problem you asked – Peter Duniho Jan 31 '18 at 18:12

1 Answers1

0

The general problem with your code is that you are using Tasks for code that performs no kind of asynchronous I/O work. Both CreateHighlighter and DoStuffAsync are said to be Task for absolutely no good reason.
Moreover, since CreateHighlighter is working with UI objects, is worse to make that async since you aren't in the UI context (due to your usage of Task.Run). This is how your code should look like:

public sealed partial class MainPage : Page
{
    ... 
    private async void btnFind_Click(object sender, RoutedEventArgs e)
    {
        ...
        List<int> indexList = await Task.Run(DoStuff(completeText, tofind)); 
        TextHighlighter HighlighterAll = CreateHighlighter(indexList, tofind.Length);
        ...
    }

    private TextHighlighter CreateHighlighter(List<int> listaindex, int lenght)
    {
        ...
        return Higlighter;
    }

    private List<int> DoStuff(string myTxt, string toFind)
    {
        ...
        return indexList;
    }
}
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • 1
    I created Task.Run CreateHighlighter because the cycle in this method blocks the app. – Jib58 Jan 31 '18 at 11:50
  • What I would like to do is to add the range list to the TextHighlighter asynchronously so as not to block the app. – Jib58 Jan 31 '18 at 11:53
  • @Jib58 I am not sure of the correct syntaxis in UWP, but if you want that to be asynchronous you still need to do it aware of the UI thread. Probably with a Dispatcher class – Camilo Terevinto Jan 31 '18 at 11:55
  • Is just what I would like to be able to do ... I tried in every way but without result .. any idea? – Jib58 Jan 31 '18 at 11:58
  • @Jib58 It should be something like [this](https://stackoverflow.com/questions/38149767/uwp-update-ui-from-task) – Camilo Terevinto Jan 31 '18 at 11:59
  • With a short range list it works but, with a longer for example of 40000 indexes freezes .. I would like to make it asyncrono without blocking the app .. – Jib58 Jan 31 '18 at 12:12
  • Is it possible to run the second Tasck.Run (CreateHighlighter) as the first? – Jib58 Jan 31 '18 at 14:24
  • @Jib58 Not really, since as I mentioned, UI objects need to be created in the UI thread. That's why I gave you a link to how to run async actions in the UI context – Camilo Terevinto Jan 31 '18 at 14:34
  • But the TextHighlifhter is not part of the UI and so it should be possible ... no? I do not understand this .. – Jib58 Jan 31 '18 at 14:59