Kamenskyh
Kamenskyh

Reputation: 495

How to use search bar with ObservableCollection and List in MVVM

Please help.I have a listview where I write data from the VM.I have a list of car brands and I want to use the search bar to display only what matches the text in the search bar. For example I have a list

BAC

BAE

BAIC

Bailey

Bajaj

Baker

Electric

Baldwin-Motion

Ballot

When I write for example Bai or bai I want that my list show me

BAIC

Bailey

Please help me

XAML CODE

<Frame CornerRadius="15" HasShadow="True" BorderColor="LightGray" Margin="10,10,10,0" Padding="5">
                    <controls:CustomSearchBar x:Name="searchBar"   TextColor="Gray" 
                 />
                </Frame>
     <StackLayout>
                    <ListView x:Name="Company"   SelectionMode="None" ItemsSource="{Binding Cars}">
                        <ListView.ItemTemplate>
                            <DataTemplate>
                                <ViewCell>
                                <Grid >
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="100" />

                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="Auto" />
                                    </Grid.ColumnDefinitions>
                                    <StackLayout Spacing="0">
                                            <BoxView  
            HeightRequest="1" 
            BackgroundColor="LightGray" 
            HorizontalOptions="FillAndExpand" VerticalOptions="Start" />
                                            <controls:ExtendedButton2   HeightRequest="45" Padding="5,10,0,10"
                             WidthRequest="300"   Margin="0"  HorizontalTextAlignment="Start"
                         BackgroundColor="{Binding CustButtonColor}" Text="{Binding Name}" TextColor="Gray" FontSize="18" 
                                           Command="{ Binding BindingContext.ChangeMark, 
                                            Source={x:Reference Name=Company} }"  CommandParameter="{Binding .}"/>
                                          
                                        </StackLayout>
                                    </Grid>
                                </ViewCell>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>

VM CODE

public class CarAddCompany : INotifyPropertyChanged
    {
        public  ObservableCollection<Car> Cars { get;  }
        public ICommand ChangeMark { protected set; get; }
        public MainCar mainCar { get; set; }
        INavigation Navigation { get; set; }

        public Command navigateCommand { get; set; }

        public Command navigateCommandBACK { get; set; }
        public async Task GotoPage2()
        {
            if (mainCar.MarkCar != null) await Navigation.PushModalAsync(new Car_add_model(mainCar));
        }
        public async Task GotoPage1()
        {
            //mainCar.MarkCar ="";
            //   await Navigation.PushModalAsync(new Car_add());
            await Navigation.PopModalAsync();
        }
        public CarAddCompany(INavigation navigation,MainCar carC)
        {
            mainCar = carC;

            this.Navigation = navigation;
            this.navigateCommand = new Command(async () => await GotoPage2());
            navigateCommandBACK = new Command(async () => await GotoPage1());
            Cars = new ObservableCollection<Car>();
            Cars.Add(new Car() { Name = "BAC", CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "BAE", CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "BAIC",  CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Bailey",  CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Bajaj",  CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Baker", CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Electric", CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Baldwin-Motion",CustButtonColor = Color.White });
            Cars.Add(new Car() { Name = "Ballot",  CustButtonColor = Color.White });

                      
            ChangeMark = new Command<Car>((key) =>
            {

                
                foreach (var item in Cars)
                {

                    item.CustButtonColor = Color.White;
                }
                    
                    var car = key as Car;
                    car.CustButtonColor = Color.FromHex("#D1DAED");
                    mainCar.MarkCar = car.Name;

                
            });
        }
        public event PropertyChangedEventHandler PropertyChanged;
        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }

enter image description here

enter image description here

Upvotes: 2

Views: 2155

Answers (1)

Shubham Tyagi
Shubham Tyagi

Reputation: 838

Change ListView itemsource from cars to new observable collection say SearchedCars

private ObservableCollection<Car> searchedCars = new ObservableCollection<Car>();

public  ObservableCollection<Car> SearchedCars { get => searchedCars; set { searchedCars = value;OnPropertyChanged("SearchedCars");}  }

<ListView x:Name="Company"   SelectionMode="None" ItemsSource="{Binding SearchedCars}">

After that use Corcav.Behavior nuget to get searchbar textChanged event to your ViewModel https://github.com/corradocavalli/Corcav.Behaviors

...
xmlns:corcav="clr-namespace:Corcav.Behaviors;assembly=Corcav.Behaviors"
...

<SearchBar>
         <corcav:Interaction.Behaviors>
                 <corcav:BehaviorCollection>
                        <corcav:EventToCommand EventName="TextChanged" Command="{Binding Path=SearchBarTextChangedCommand}" PassEventArgument="True"/>
                 </corcav:BehaviorCollection>
          </corcav:Interaction.Behaviors>
</SearchBar>

Add and initialize command and finally apply the filter

public ICommand SearchBarTextChangedCommand { get; set; }
...
SearchBarTextChangedCommand = new Command<object>(OnSearchBarTextChanged);
...
private void OnSearchBarTextChanged(object obj)
        {
            if(obj is TextChangedEventArgs args)
            {
                string filter = args.NewTextValue;
                SearchedCars = Cars.Where(x => x.Name.ToLower().Contains(filter.Trim().ToLower())).ToList();
            }
        }

Upvotes: 1

Related Questions