简体   繁体   中英

Call method when ObservableProperty changes using CommunityToolkit.Mvvm

I'm implementing auto complete feature in my .NET MAUI app and I'm using CommunityToolkit.Mvvm code generators in my view model to handle observable properties.

I have the following code and I'm trying call GetSuggestions() method when the SearchText changes.

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(GetSuggestions))]
string searchText;

[ObservableProperty]
bool showSuggestions;

ObservableCollection<string> Suggestions { get; } = new();

private async Task GetSuggestions()
{
   if(string.IsNullOrEmpty(SearchText) || SearchText.Length < 3)
      return;

   var data = await _myApiService.GetSuggestions(SearchText.Trim());
   if(data != null && data.Count > 0)
   {
      Suggestions.Clear();
      foreach(var item in data)
         Suggestions.Add(item);

      ShowSuggestions = true;
   }
}

This is giving me the following error:

The target(s) of [NotifyCanExecuteChangedFor] must be an accessible IRelayCommand property, but "GetSuggestions" has no matches in type MyViewModel.

What am I doing wrong here?

I guess there are two problems here.

Why is this error occurring?

That happens because GetSuggestions is not a Command. Try adding the [RelayCommand] attribute to your method.

[RelayCommand]
private async Task GetSuggestions()
{
    if(string.IsNullOrEmpty(SearchText) || SearchText.Length < 3)
       return;

    var data = await _myApiService.GetSuggestions(SearchText.Trim());
    if(data != null && data.Count > 0)
    {
        Suggestions.Clear();
        foreach(var item in data)
        Suggestions.Add(item);

        ShowSuggestions = true;
    }
}

Then link NotifyCanExecuteChangedFor to the autogenerated command.

[ObservableProperty]
[NotifyCanExecuteChangedFor(nameof(GetSuggestionsCommand))]
string searchText;

The second one.

You need to

call GetSuggestions() method when the SearchText changes.

The NotifyCanExecuteChangedFor attribute doesn't do that.

In the autogenerated source code you should find an empty partial method called OnSearchTextPropertyChanged . Try implementing it.

partial void OnSearchTextPropertyChanged(string value)
{
    GetSuggestions();
}

If this is what you're searching for, GetSuggestions doesn't need to be marked with the RelayCommand attribute.

Only meant as more of an amendment of @RMinato's answer.

As my comment say: "While most of this was helpful, I need to do a few things different including using the [RelayCommand] and calling the method inside my OnPropChanged method to be Task.Run(() => this.MyMethodAsync()).Wait(); ".

My code looks like:

[QueryProperty(nameof(Course), nameof(Course))]
public partial class CourseDetailViewModel : BaseViewModel
{
    private readonly CourseService courseService;

    public CourseDetailViewModel(CourseService courseService)
    {
        this.courseService = courseService;
    }

    [ObservableProperty]
    [NotifyCanExecuteChangedFor(nameof(GetCourseDetailCommand))]
    Course course;

    partial void OnCourseChanged(Course value)
    {
        Task.Run(() => this.GetCourseDetailAsync()).Wait();
    }

    [RelayCommand]
    public async Task GetCourseDetailAsync()
    {
        if (GetCourseDetailCommand.IsRunning) return;

        try
        {
            IsBusy = true;

            course = await courseService.GetCourseDetailAsync(course.Id);
        }
        catch (Exception ex)
        {
            Debug.WriteLine($"Failed to get course detail. Error: {ex.Message}");
            await Shell.Current.DisplayAlert("Error!",
                $"Failed to get course detail: {ex.Message}", "OK");
            throw;
        }
        finally
        {
            IsBusy = false;
        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM