Reputation: 1309
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...
Upvotes: 7
Views: 7902
Reputation: 11
UWP Binding Command/Delegate
to AutoSuggestBox
in MVVM
For UWP Mobile Application
Make a DelegateCommand class
public class DelegateCommand<T> : ICommand
{
private readonly Action<T> executeAction;
Func<object, bool> canExecute;
public event EventHandler CanExecuteChanged;
public DelegateCommand(Action<T> executeAction)
: this(executeAction, null)
{
//var a = ((Page)(((Func<object, bool>)(executeAction.Target)).Target)).Name;
//((ViewModel.VMBranchSelection)(executeAction.Target)).;
}
public DelegateCommand(Action<T> executeAction, Func<object, bool> canExecute)
{
this.executeAction = executeAction;
this.canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return canExecute == null ? true : canExecute(parameter);
}
public void Execute(object parameter)
{
executeAction((T)parameter);
}
public void RaiseCanExecuteChanged()
{
EventHandler handler = this.CanExecuteChanged;
if (handler != null)
{
handler(this, new EventArgs());
}
}
}
In View Model
public ICommand SuggessionSelectCity_QuerySubmitted
{
get { return new DelegateCommand<AutoSuggestBoxQuerySubmittedEventArgs>(this.SuggessionSelectCityQuerySubmitted); }
}
private void SuggessionSelectCityQuerySubmitted(AutoSuggestBoxQuerySubmittedEventArgs obj)
{
if (obj.ChosenSuggestion != null)
{
AutosuggestionTextBoxName.Text = ((ModelName) (obj.ChosenSuggestion)).Model's Property name;
//or
AutosuggestionTextBoxName.Text =(obj.ChosenSuggestion).property name
}
else
{
}
}
In XAML Code
<AutoSuggestBox Grid.Column="1" x:Name="SuggessionSelectCity"
PlaceholderText="Search by keywords" QueryIcon="Find"
ItemsSource="{Binding PApplicantCityList}"
HorizontalAlignment="Center" VerticalAlignment="Center" DisplayMemberPath="Description" Width="250" Height="45">
<Interactivity:Interaction.Behaviors>
<Core:EventTriggerBehavior EventName="TextChanged">
<Core:EventTriggerBehavior.Actions>
<Core:InvokeCommandAction Command="{Binding SuggessionSelectCityTextChange}"/>
</Core:EventTriggerBehavior.Actions>
</Core:EventTriggerBehavior>
<Core:EventTriggerBehavior EventName="QuerySubmitted">
<Core:EventTriggerBehavior.Actions>
<Core:InvokeCommandAction Command="{Binding SuggessionSelectCity_QuerySubmitted}"/>
</Core:EventTriggerBehavior.Actions>
</Core:EventTriggerBehavior>
<Core:EventTriggerBehavior EventName="SuggestionChosen">
<Core:EventTriggerBehavior.Actions>
<Core:InvokeCommandAction Command="{Binding SuggessionSelectCitySuggestionChosen}"/>
</Core:EventTriggerBehavior.Actions>
</Core:EventTriggerBehavior>
</Interactivity:Interaction.Behaviors>
</AutoSuggestBox>
</Grid>
Create a list in View Model for Autosuggestion TextBox Itemssource
private ObservableCollection<ResultMasterModel> ApplicantCityList;
public ObservableCollection<ResultMasterModel> PApplicantCityList
{
get { return ApplicantCityList; }
set { this.SetProperty(ref this.ApplicantCityList, value); }
}
add some hard code value in above list
Create a Model In Model Folder
public class ResultMasterModel
{
public string Code { get; set; }
public string Description { get; set; }
}
Upvotes: 0
Reputation: 790
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
}
Upvotes: 11
Reputation: 1775
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 */ }
}
Upvotes: 5
Reputation: 637
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();
Upvotes: 1