2
votes

Good Day everyone. I'm trying to create a SearchBar that do the searching on a ListView. The records on the ListView are retrieved from a Database in Visual Studio.

I have tried some codes but wasn't able to make it work. And I'm just a newbie here in Xamarin.Forms. Hope you guys can help me.

These are some of the codes I've tried:

CustomerList.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="XamarinFormsDemo.Views.ClientListPage"
         xmlns:ViewModels="clr-namespace:XamarinFormsDemo.ViewModels;assembly=XamarinFormsDemo"
         xmlns:controls="clr-namespace:ImageCircle.Forms.Plugin.Abstractions;assembly=ImageCircle.Forms.Plugin.Abstractions"
         BackgroundImage="bg3.jpg"
         Title="Client List">


  <ContentPage.BindingContext>
    <ViewModels:CustomerVM/>
  </ContentPage.BindingContext>
  <StackLayout Orientation="Vertical">


    <SearchBar x:Name="searchcustomer"
            Placeholder="Search"
           Text="{Binding SearchedText, Mode=TwoWay}"
           SearchCommand="{Binding SearchCommand}"/>

   <ListView ItemsSource="{Binding CustomerList}"
          HasUnevenRows="True">
      <ListView.ItemTemplate>
        <DataTemplate>
          <ViewCell>
            <Grid Padding="10" RowSpacing="10" ColumnSpacing="5">
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
              </Grid.RowDefinitions>
              <Grid.ColumnDefinitions>
                <ColumnDefinition Width="Auto"/>
                <ColumnDefinition Width="*"/>
              </Grid.ColumnDefinitions>

              <controls:CircleImage Source="icon.png"
                 HeightRequest="66"
                 HorizontalOptions="CenterAndExpand"
                 Aspect="AspectFill"
                 WidthRequest="66"
                 Grid.RowSpan="2"
               />


          <Label Grid.Column="1"
                 Text="{Binding CUSTOMER_NAME}"
                 TextColor="#24e97d"
                 FontSize="24"/>



          <Label Grid.Column="1"
                  Grid.Row="1"
                   Text="{Binding CUSTOMER_CODE}"
                   TextColor="White"
                   FontSize="18"
                   Opacity="0.6"/>


          <Label Grid.Column="1"
              Grid.Row="2"
              Text="{Binding CUSTOMER_CONTACT}"
               TextColor="White"
               FontSize="18"
               Opacity="0.6"/>



            </Grid>
          </ViewCell>
        </DataTemplate>
      </ListView.ItemTemplate>

    </ListView>


    <StackLayout Orientation="Vertical"
         Padding="30,10,30,10"
         HeightRequest="20"
         BackgroundColor="#24e97d"
         VerticalOptions="Center"
         Opacity="0.5">
      <Label Text="© Copyright 2016   SMESOFT.COM.PH   All Rights Reserved "
         HorizontalTextAlignment="Center"
         VerticalOptions="Center"
         HorizontalOptions="Center" />
    </StackLayout>
  </StackLayout>
</ContentPage>

CustomerViewModel.cs

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinFormsDemo.Models;
using XamarinFormsDemo.Services;

namespace XamarinFormsDemo.ViewModels
{
    public class CustomerVM : INotifyPropertyChanged
    {


        private void SearchCommandExecute()
        {
            var tempRecords = _customerList.Where(c => c.CUSTOMER_NAME.Contains(SearchedText));
            CustomerList = new List<Customer>(tempRecords);
        }
        public ICommand SearchCommand { get; set; }




        private string _searchedText; 
        public string SearchedText
        {
            get { return _searchedText; }
            set { _searchedText = value; OnPropertyChanged(); }
        }


        private List<Customer> _customerList;

        public List<Customer> CustomerList
        {
            get
            {
                return _customerList;
            }
            set
            {
                _customerList = value;
                OnPropertyChanged();
            }
        }



        public CustomerVM()
        {
            InitializeDataAsync();
        }

        private async Task InitializeDataAsync()
        {
            var customerServices = new CustomerServices();

            CustomerList = await customerServices.GetCustomerAsync();
            SearchCommand = new Command(() => Debug.WriteLine("Command executed"));
        }


        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }

    }
}

If you need to see more codes, just please let me know. Thanks a lot.

1
What exactly doesn't work? - Gerald Versluis
@GeraldVersluis The searching doesn't work Sir. The records of the Customers are being displayed on a ListView. The SearchBar itself isn't functioning. - Jaycee Evangelista
Change you List<Customer> to a ObservableList<Customer> and don't assign a new instance, but clear the list and add the items one by one. Also have a look at my blog post about the SearchBar here - Gerald Versluis
@GeraldVersluis Thanks Sir. What do you mean by "don't assign a new instance, but clear the list and add the items one by one"? - Jaycee Evangelista
In your SearchCommandExecute don't do this: CustomerList = new List<Customer>(tempRecords); but do CustomerList.Clear(); foreach(var t in tempRecords) CustomerList.Add(t); - Gerald Versluis

1 Answers

6
votes

First: Change

 private List<Customer> _customerList;

    public List<Customer> CustomerList
    {
        get
        {
            return _customerList;
        }
        set
        {
            _customerList = value;
            OnPropertyChanged();
        }
    }

for

private ObservableList <Customer> _customerList;

    public ObservableList <Customer> CustomerList
    {
        get
        {
            return _customerList;
        }
        set
        {
            _customerList = value;
            OnPropertyChanged();
        }
    }

And change this

private void SearchCommandExecute()
    {
        var tempRecords = _customerList.Where(c => c.CUSTOMER_NAME.Contains(SearchedText));
        CustomerList = new List<Customer>(tempRecords);
    }

to

private void SearchCommandExecute()
    {
        var tempRecords = _customerList.Where(c => c.CUSTOMER_NAME.Contains(SearchedText));
        CustomerList.Clear();
        foreach (var item in tempRecords)
        {
             CustomerList.Add(item);
        }
    }

Basically you need to use an observable list to notify the view about the changes and avoid create a new instance every time.