Home > Net >  MVVM Search Bar in Xamarin.Forms with EventToCommandBehavior(XCT) and MVVMHelpers
MVVM Search Bar in Xamarin.Forms with EventToCommandBehavior(XCT) and MVVMHelpers

Time:03-14

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>
  • Related