I am trying to MVVM a search bar in Xamarin. I am using MVVMHelpers and EventToCommandBehavior from Xamarin Community Toolkit. I want to turn the TextChanged event to a command.
In my viewmodel file I have some commands to work with the list and an ObservableRangeCollection in which I store "Category" type data. The model only contains Id and Name fields (keeping it simple until I get the hang of it).
I want to be able to search by the Name field of the Category class and display the frames that contains the value from the search bar with no code behind.
I have no idea what to write in the viewmodel file. I saw some tutorials about handling TextChange event in code behind and I tried mvvm-ing it but I had no success.
HomeViewModel.cs
namespace A.point.me.ViewModels
{
public class HomeViewModel : BaseViewModel
{
public ObservableRangeCollection<Category> Categories { get; set; }
public AsyncCommand RefreshCommand { get; }
public Command DelayLoadMoreCommand { get; }
public Command ClearCommand { get; }
public Command LoadMoreCommand { get; }
public Command SearchCommand { get; }
public HomeViewModel()
{
Title = "Home";
Categories = new ObservableRangeCollection<Category>();
LoadMore();
RefreshCommand = new AsyncCommand(Refresh);
ClearCommand = new Command(Clear);
LoadMoreCommand = new Command(LoadMore);
DelayLoadMoreCommand = new Command(DelayLoadMore);
SearchCommand = new Command(Search);
}
void Search()
{
}
void LoadMore()
{
if (Categories.Count >= 20)
return;
Categories.Add(new Category { Name = "Beauty" });
Categories.Add(new Category { Name = "Tattoo" });
Categories.Add(new Category { Name = "Hairstyle" });
Categories.Add(new Category { Name = "Dentist" });
Categories.Add(new Category { Name = "Tech" });
Categories.Add(new Category { Name = "Auto" });
}
void Clear()
{
Categories.Clear();
}
...
Homepage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="A.point.me.Views.HomePage"
xmlns:vm="clr-namespace:A.point.me.ViewModels"
xmlns:model="clr-namespace:A.point.me.Models"
xmlns:cells="clr-namespace:A.point.me.Cells"
xmlns:xct="http://xamarin.com/schemas/2020/toolkit"
x:DataType="vm:HomeViewModel"
xmlns:fontAwesome="clr-namespace:FontAwesome"
x:Name="HPage"
Title="{Binding Title}"
BackgroundColor="{AppThemeBinding Dark={StaticResource WindowBackgroundColorDark}, Light={StaticResource WindowBackgroundColor}}">
<ContentPage.BindingContext>
<vm:HomeViewModel />
</ContentPage.BindingContext>
<StackLayout>
<SearchBar x:Name="srcBar">
<SearchBar.Behaviors>
<xct:EventToCommandBehavior EventName="TextChanged" Command="CommandSearch" CommandParameter="{Binding Text, Source={x:Reference srcBar}}"/>
</SearchBar.Behaviors>
</SearchBar>
<RefreshView
Command="{Binding RefreshCommand}"
IsRefreshing="{Binding IsBusy, Mode=OneWay}"
RefreshColor="Red">
<CollectionView
ItemsSource="{Binding Categories}"
ItemsLayout="VerticalGrid, 2"
BackgroundColor="Transparent"
ItemSizingStrategy="MeasureAllItems"
RemainingItemsThreshold="1"
RemainingItemsThresholdReachedCommand="{Binding DelayLoadMoreCommand}">
<CollectionView.EmptyView>
<StackLayout>
<Label HorizontalOptions="Center" VerticalOptions="CenterAndExpand" Text="No categories yet" Style="{StaticResource LabelLarge}"/>
</StackLayout>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate>
<cells:CategoryCard/>
</DataTemplate>
</CollectionView.ItemTemplate>
<CollectionView.Header>
<StackLayout Orientation="Horizontal">
<Label HorizontalOptions="CenterAndExpand" Text="CATEGORIES" Style="{StaticResource LabelHeader}"/>
</StackLayout>
</CollectionView.Header>
<CollectionView.Footer>
<StackLayout Orientation="Horizontal">
<Button Text="Clear" Command="{Binding ClearCommand}" HorizontalOptions="CenterAndExpand"/>
</StackLayout>
</CollectionView.Footer>
</CollectionView>
</RefreshView>
</StackLayout>
</ContentPage>
This is where I bind the Name field of the Category class
CategoryCard.xaml
<?xml version="1.0" encoding="UTF-8" ?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="A.point.me.Cells.CategoryCard"
xmlns:models="clr-namespace:A.point.me.Models"
x:DataType="models:Category"
Padding="10">
<Frame Style="{StaticResource CategoryCard}">
<Label VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand" Text="{Binding Name}" Style="{StaticResource LabelMedium}"/>
</Frame>
</Grid>
CodePudding user response:
In your xaml change CommandSearch to SearchCommand
<SearchBar x:Name="srcBar">
<SearchBar.Behaviors>
<xct:EventToCommandBehavior EventName="TextChanged" Command="SearchCommand" CommandParameter="{Binding Text, Source={x:Reference srcBar}}"/>
</SearchBar.Behaviors>
</SearchBar>
then in the VM
public HomeViewModel()
{
SearchCommand = new Command<object>(Search);
}
void Search(object obj)
{
var text = (string)obj;
}
CodePudding user response:
Have you tried the Binding extension? Check the code below:
<StackLayout>
<SearchBar x:Name="srcBar">
<SearchBar.Behaviors>
<xct:EventToCommandBehavior EventName="TextChanged" Command="{Binding CommandSearch}" CommandParameter="{Binding Text, Source={x:Reference srcBar}}"/>
</SearchBar.Behaviors>
</SearchBar>