Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UWP Binding to AutoSuggestBox in MVVM

i am invoking the QuerySubmitted command of the AutoSuggestBox control in UWP. the command binds to ICommand in the view model. the problem is it requires to accept AutoSuggestBoxQuerySubmittedEventArgs which is pure UI and it's not acceptable in MVVM.

my code looks like that:

<AutoSuggestBox Name="SearchAutoSuggestBox"
                PlaceholderText="Search by keywords"
                QueryIcon="Find"
                >
    <interactivity:Interaction.Behaviors>
        <core:EventTriggerBehavior EventName="QuerySubmitted">
            <core:InvokeCommandAction Command="{x:Bind ViewModel.SearchCommand}" />
        </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</AutoSuggestBox>

and my view model looks like that:

public DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs> SearchCommand { get; }

public MainPageViewModel()
{
    SearchCommand = new DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs>(ExecuteMethod);
}

private void ExecuteMethod(AutoSuggestBoxQuerySubmittedEventArgs o)
{
    // CODE HERE
}

ofcours AutoSuggestBoxQuerySubmittedEventArgs is not acceptable in the view model. looking for alternatives... same goes to SuggestionChosen...

like image 1000
kaycee Avatar asked Jan 05 '16 20:01

kaycee


3 Answers

InvokeCommandAction has a parameter named InputConverter which you can use to convert the event args to some other parameter that can be passed to your ViewModel.

First create a IValueConverter class to extract what you need from your event args like this:-

public class AutoSuggestQueryParameterConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, string language)
       {
          // cast value to whatever EventArgs class you are expecting here
          var args = (AutoSuggestBoxQuerySubmittedEventArgs)value;
          // return what you need from the args
          return (string)args.ChosenSuggestion;
       }
}

Then use that converter in your XAML like this:

<Page.Resources>
     <converters:AutoSuggestQueryParameterConverter x:Key="ArgsConverter" />
</Page.Resources>

<AutoSuggestBox Name="SearchAutoSuggestBox"
            PlaceholderText="Search by keywords"
            QueryIcon="Find">
    <interactivity:Interaction.Behaviors>
      <core:EventTriggerBehavior EventName="QuerySubmitted">
        <core:InvokeCommandAction 
              Command="{x:Bind ViewModel.SearchCommand}"
              InputConverter="{StaticResource ArgsConverter}" />
      </core:EventTriggerBehavior>
    </interactivity:Interaction.Behaviors>
</AutoSuggestBox>

Finally in your viewmodel change your command to accept a string as parameter. So you would have the following in your vm:

public DelegateCommand<string> SearchCommand { get; }

public MainPageViewModel()
{
    SearchCommand = new DelegateCommand<string>(ExecuteMethod);
}

private void ExecuteMethod(string o)
{
    // CODE HERE
}
like image 168
Nick Avatar answered Oct 24 '22 07:10

Nick


You can bind the search string (Text property) to a view model property and the events to parameter-less methods. This way the view model wont have to deal with UI objects:

XAML:

<AutoSuggestBox Header="What's your name?"
                TextChanged="{x:Bind ViewModel.FilterUsuals}"
                QuerySubmitted="{x:Bind ViewModel.ProcessQuery}"
                SuggestionChosen="{x:Bind ViewModel.ProcessChoice}"
                ItemsSource="{x:Bind ViewModel.Usuals, Mode=OneWay}"
                Text="{x:Bind ViewModel.SearchText, Mode=TwoWay}"
                QueryIcon="Find" />

Code behind:

public class MainPageViewModel : SomeViewModelBaseClass
{
    /* Boilerplate code and constructor not included */

    private string _SearchText;
    public string SearchText {/* getter and setter INotyfyPropertyChange compliant */ }

    private List<string> _Usuals; // Initialized on constructor
    public string Usuals {/* getter and setter INotyfyPropertyChange compliant */ }


    public void FilterUsuals()
    {
        // the search string is in SearchText Example:
        Usuals = _UsualsStore.Where(u => u.Contains(_SearchText.ToLower())).ToList();
    }

    public void ProcessQuery() { /* TODO - search string is in SearchText */ }

    public void ProcessChoice() { /* TODO - search string is in SearchText */ }
}
like image 25
CFreitas Avatar answered Oct 24 '22 07:10

CFreitas


If you don't mind doing non pure MVVM way.

MainPage.xaml :

<AutoSuggestBox Name="SearchAutoSuggestBox"
        PlaceholderText="Search by keywords"
        QueryIcon="Find" QuerySubmitted="{x:Bind ViewModel.SearchQuerySubmitted}" IsEnabled="{x:Bind ViewModel.CanExecuteSearchCommand, Mode=TwoWay}"
        >
</AutoSuggestBox>

MainPageViewModel.cs :

public class MainPageViewModel : INotifyPropertyChanged
{
    private bool _canExecuteSearchCommand;

    public MainPageViewModel()
    {
        this.CanExecuteSearchCommand = true;
    }

    public bool CanExecuteSearchCommand
    {
        get { return _canExecuteSearchCommand; }
        set
        {
            bool changed = _canExecuteSearchCommand != value;
            _canExecuteSearchCommand = value;

            if(changed)
                this.OnPropertyChanged();
        }
    }

    public void SearchQuerySubmitted(AutoSuggestBox sender, AutoSuggestBoxQuerySubmittedEventArgs args)
    {
        // Just example disabling SearchBox
        this.CanExecuteSearchCommand = false;
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

MainPage.cs :

MainPageViewModel ViewModel = new MainPageViewModel();
like image 1
Ask Too Much Avatar answered Oct 24 '22 07:10

Ask Too Much