Home > Software design >  How to apply search to the list in the MVVM (WPF) without recalling the list values every time?
How to apply search to the list in the MVVM (WPF) without recalling the list values every time?

Time:12-11

First of all I'm new to the MVVM though in case I'm missing the point please feel free to corect me.

I'm working on the WPF application where I'm using the MVVM Community Toolkit. My application architecture looks more like this:

  1. I have simple Model containing some basic properties
public class Package : ObservableObject
    {
        private string id;
        public string Id
        {
            get => id;
            set => SetProperty(ref id, value);
        }

        private string name;
        public string Name
        {
            get => name;
            set => SetProperty(ref name, value);
        }

        private string version;
        public string Version
        {
            get => version;
            set => SetProperty(ref version, value);
        }

        private string summary;
        public string Summary
        {
            get => summary;
            set => SetProperty(ref summary, value);
        }
}
  1. There is ViewModel where there is IList<Package> property and a AsyncRelayCommand which calls the process, get output and update the property.
class MainWindowViewModel : ObservableObject
    {
        public AsyncRelayCommand StartProcessCommand { get; }
        public MainWindowViewModel()
        {
            
            StartProcessCommand = new AsyncRelayCommand(StartProcess, CanStartProcess);
            
        }
        
        private async Task StartProcess()
        {
            
           //Start process, collect the output and set the PackageList property
        }

        private IList<Package> packagesList;

        public IList<Package> PackagesList
        {
            get => packagesList;
            set => SetProperty(ref packagesList, value);
        }
 }
  1. Then there is a View where the binding is done as below:

<ListView ItemsSource="{Binding PackagesList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
               
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}"/>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                        <GridViewColumn Header="Version" DisplayMemberBinding="{Binding Version}" />
                        <GridViewColumn Header="Summary" DisplayMemberBinding="{Binding Summary}"/>
                    </GridView>
                </ListView.View>
            </ListView>

and the button to call the RelayCommand (async).

Here is the question and the problem I'm facing

I would like to apply the Search TextBox to dynamically search the result of the IList<Package>, for this purpose I have create a SearchText in the ViewModel which updates the IList<Package> property on the PropertyChanged event. The problem is that my property is changing and I would like to not recall it every time from the process.

  1. Create a list
  2. Search the list and present it in a View
  3. In case I'm removing my searchText value it's still showing the list from the point 1

What will be best approach to achieve this?

This is so far where I got to but works only once, filter the list but not returning to previous list:



public void SearchItem()
        {
            PackagesList = packagesList.Where(package => package.Id == SearchText).ToList();

        }

private string? searchText;
        public string? SearchText
        {
            get => searchText;
            set
            {
                SetProperty(ref searchText, value);
                SearchItem();
            }
            
        }

CodePudding user response:

Inside the MainWindowViewModel create another property IList<Package> and call it ResultList

    private IList<Package> ResultList { get; set;} // Add Result list
    private IList<Package> packagesList;

    public IList<Package> PackagesList
    {
        get => packagesList;
        set => SetProperty(ref packagesList, value);
    }

Set your ItemsSource binding to the ResultList instead.

        <ListView ItemsSource="{Binding ResultList, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
           
            <ListView.View>
                <GridView>
                    <GridViewColumn Header="Id" DisplayMemberBinding="{Binding Id}"/>
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>
                    <GridViewColumn Header="Version" DisplayMemberBinding="{Binding Version}" />
                    <GridViewColumn Header="Summary" DisplayMemberBinding="{Binding Summary}"/>
                </GridView>
            </ListView.View>
        </ListView>

Anytime you set your PackagesList, you set the ResultList as well. Now when it gets to the search, you do something of this sort

public void SearchItem()
{
    ResultList = packagesList.Where(package => package.Id == SearchText).ToList();
}

CodePudding user response:

According to your claim, you want to show all the data after deleting the text? If so, you can try this

public void SearchItem()
{   
    PackagesList = packagesList.Where(package => package.Id == SearchText || null == SearchText).ToList();
}
  • Related