0

Following:

Converting Action method call to async Action method call

and

The 'await' operator can only be used within an async lambda expression

I've come up with the following code:

CommandHandler.cs:

public class CommandHandler : ICommand
{
    private Func<Task> _action;
    private Func<bool> _canExecute;

    /// <summary>
    /// Creates instance of the command handler
    /// </summary>
    /// <param name="action">Action to be executed by the command</param>
    /// <param name="canExecute">A bolean property to containing current permissions to execute the command</param>
    public CommandHandler(Func<Task> action, Func<bool> canExecute)
    {
        _action = action;
        _canExecute = canExecute;
    }

    /// <summary>
    /// Wires CanExecuteChanged event 
    /// </summary>
    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    /// <summary>
    /// Forcess checking if execute is allowed
    /// </summary>
    /// <param name="parameter"></param>
    /// <returns></returns>
    public bool CanExecute(object parameter)
    {
        return _canExecute.Invoke();
    }

    public void Execute(object parameter)
    {
        _action(); // IS THIS REALLY ASYNC? VS DOESN'T COMPLAIN 
    }
}

AppliedJobsViewModel.cs:

class AppliedJobsViewModel
{
    private TexParser texParser;
    private ObservableCollection<AppliedJob> appliedJobsCollection;

    public AppliedJobsViewModel() {
        // TODO:
        // -- do nothing here 
    }

    public ObservableCollection<AppliedJob> AppliedJobsCollection
    {
        get
        {
            if (appliedJobsCollection == null)
            {
                appliedJobsCollection = new ObservableCollection<AppliedJob>();
            }

            return appliedJobsCollection;
        }
        set
        {
            if (value != null)
            {
                appliedJobsCollection = value;
            }
        }
    }

    private ICommand _openTexClick;
    public ICommand OpenTexClick
    {
        get
        {
            return _openTexClick ?? (_openTexClick = new CommandHandler(() => ReadAndParseTexFile(), () => CanExecute));
        }
    }
    public bool CanExecute
    {
        get
        {
            // check if executing is allowed, i.e., validate, check if a process is running, etc. 
            return true;
        }
    }

    public async Task ReadAndParseTexFile()
    {
        if (texParser == null)
        {
            texParser = new TexParser();
        }
        // Read file asynchronously here
        await Task.Run(() => ReadFileAndUpdateUI()); // LARGE SYNC CHUNK OF CODE
    }

    private void ReadFileAndUpdateUI()
    {
        texParser.ReadTexFile();
        string[][] appliedJobsArray = texParser.getCleanTable();
        // Update collection here
        List<AppliedJob> appliedJobsList = createAppliedJobsListFromTable(appliedJobsArray);
        appliedJobsCollection = new ObservableCollection<AppliedJob>(appliedJobsList);
    }

    private List<AppliedJob> createAppliedJobsListFromTable(string[][] table)
    {
        List<AppliedJob> jobsList = new List<AppliedJob>();

        for (int i = 0; i < table.Length; i++)
        {
            jobsList.Add(new AppliedJob(table[i]));
        }

        return jobsList;
    }

    public ObservableCollection<AppliedJob> AppliedJobs {
        get;
        set;
    }
}

Is the code "entirely"(from the start of the Func action) async? If yes, is it "fully" MVVM? If not, why?

Sebi
  • 4,262
  • 13
  • 60
  • 116
  • 1
    .net dynamically chooses if it runs sync or async. based on your code, if you pass ReadAndParseTexFile, it's going to run async, since you await `ReadFileAndUpdateUI` – Patrick Beynio Oct 06 '20 at 11:02
  • Ok. So it's, all in all, entirely async. ReadFileAndUpdateUI calls ReadStreamAsync at some point but this shouldn't really matter. Can an async method call at some point only sync methods? – Sebi Oct 06 '20 at 11:09
  • 1
    _"So it's, all in all, entirely async"_ depends on your definition of "async". I'd call it "fake" async because it seems to be CPU-Bound. So all this does is shove synchronously executed code to a different (pool-)thread while using async/await syntax. – Fildor Oct 06 '20 at 11:36
  • Essentially, that's what I wanted; don't freeze the UI while reading large files. – Sebi Oct 06 '20 at 11:42
  • 1
    Otoh this is a desktop app. Making the file read itself properly asynchronous would be much more significant on a web server. – Andy Oct 06 '20 at 11:49
  • I tried using sync and it's laggy (on a decent machine) when opening large files (thousands of entries). – Sebi Oct 06 '20 at 12:01
  • 1
    The `CommandHandler` isn't awaitiable, i.e. calling `Execute` fires and forgets a `Task`. And the task itself creates another task that will run `ReadFileAndUpdateUI()` on a background thread... – mm8 Oct 06 '20 at 12:33
  • Yes, but don't Tasks need something not async as an entry point? – Sebi Oct 06 '20 at 12:38

0 Answers0