0

Tried countless different variations of this but everything blocks the UI.

My XAML View code:

<TextBox x:Name="FilterText"
    materialDesign:HintAssist.Hint="Filter"
    cm:Message.Attach="[Event KeyDown] = [Action FilterAsync($eventArgs)]"/>

My ViewModel code:

public async void FilterAsync(KeyEventArgs keyArgs)
{
    await Task.Run(() => Filter(keyArgs));
}

public void Filter(KeyEventArgs keyArgs)
{
    if (keyArgs.Key != Key.Enter)
    {
        return;
    }

    FilteredTreeItems = new ObservableCollection<TreeNode>(TreeItems
        .Select(x => x.Search(node => node.Name.Contains(FilterText))).ToList());
}

Search is a recursive function that walks through all of the children nodes of TreeNode. I also have a similar problem although the solution might not be the same which I addressed in my previous post. I'm making another post as I did not address that I'm using Caliburn.Micro in the previous one as I didn't think it can be fault of the Caliburn.micro framework. I also included a more trivial example here with all the code.

Mr Squidr
  • 143
  • 1
  • 8
  • Have you had a look at [When correctly use Task.Run and when just async-await](https://stackoverflow.com/questions/18013523/when-correctly-use-task-run-and-when-just-async-await) as that is specifically asking about the Caliburn.Micro framework? – stuartd Sep 07 '20 at 14:20
  • Whenever doing things on a background thread it is a good idea to use pure functions if possible, i.e. take all input as parameters, and return the result without changing anything. Not sure if it will solve the problem in this case, but it would not hurt. – JonasH Sep 07 '20 at 20:44
  • @stuartd I did but I don't see how that post answers my question, it's about best practices and I can't get anything to work at all. – Mr Squidr Sep 07 '20 at 22:39
  • @JonasH if I understand you correctly you mean that I shouldn't change the property FilteredTreeItems directly but I should rather return the result and assigned returned value to FilteredTreeItems? Because I'm using MVVM this would mean I would have to add another method just so I can assign it. I'm quite new to MVVM but I don't see how that would benefit me architecturally. I also don't see how that could possibly solve my issue but maybe I misunderstood you – Mr Squidr Sep 07 '20 at 22:39
  • 1
    @Mr Squidr you would typically just change Filter to return the collection and write `FilteredTreeItems = await Task.Run(...)` . Assuming FilterAsync is called on the main thread. – JonasH Sep 08 '20 at 06:33
  • @JonasH just to make sure I understand, this is a good practice because we only wrap the CPU heavy task around `Task.Run(...)` or because it's a bad practice to modify variables outside of `Task.Run(...)` scope? – Mr Squidr Sep 08 '20 at 06:38
  • 1
    @Mr Squidr In most UI frameworks only the main thread may change the UI. So yea, good practice is to run the CPU heavy stuff on a background thread with a Task.Run, but only update the UI on the main thread, i.e. after awaiting the task. And use Async methods for any IO intensive stuff. – JonasH Sep 08 '20 at 06:43
  • @JonasH this makes a lot of sense. I changed it to reflect this but unfortunately UI is still getting blocked. Not quite sure how to approach fixing this. – Mr Squidr Sep 08 '20 at 07:11

0 Answers0