Cascading combobox

Hello,

I am trying to create a cascading combobox where the selection of the first combobox provides a filtered but searchable list in the second combobox.

The first combobox lists JobName and the second combobox lists JobTaskName. The job tasks need to be filtered by the JobNo selected in the job list. Ideally the user would then be able to search the filtered list without tasks from other jobs being shown.

I have tried filtering using the example here under custom filtering

Filtering in .NET MAUI ComboBox control | Syncfusion

But this errors with the sfCombobox not containing a definition for the ItemsSourceList.

source.ItemsSourceList.OfType 

Some code snippets of what I have so far is shown below. 

Do you have a downloadable example? Any assistance would be most appreciated.

Regards

Ross


Cascading Combobox


Job

private ObservableCollection<Job> jobs;

public ObservableCollection<Job> Jobs

{

    get { return jobs; }

    set { jobs = value; OnPropertyChanged(nameof(Jobs)); }

}

      


    Jobs = new ObservableCollection<Job>

    {

     new Job() { JobNo = "373", JobName = "373 - Whitford Quarry Final Faces" },

     new Job() { JobNo = "380", JobName = "380 - Pokeno Miscellaneous 2017" },

     new Job() { JobNo = "400", JobName = "400 - HLC Mangere West Stage 1" },

     new Job() { JobNo = "440", JobName = "440 - Paerata Rise Stage 8 Civil" },

     new Job() { JobNo = "441", JobName = "441 - Phoenix Property 20 Swanson Road" }

    }




Job Task

public ObservableCollection<JobTask> jobTasks;

public ObservableCollection<JobTask> JobTasks

{

    get { return jobTasks; }

    set { jobTasks = value; OnPropertyChanged(nameof(JobTasks)); }

}



    JobTasks = new ObservableCollection<JobTask>

    {

                new JobTask() { JobNo = "373", JobTaskNo = "010", JobTaskName = "010 - Preliminary & General" },

                new JobTask() { JobNo = "373", JobTaskNo = "015", JobTaskName = "015 - Traffic Management" },

                new JobTask() { JobNo = "373", JobTaskNo = "020", JobTaskName = "020 - Clearing & Demolition" },

new JobTask() { JobNo = "373", JobTaskNo = "030", JobTaskName = "030 - Sediment & Erosion Control" },

new JobTask() { JobNo = "373", JobTaskNo = "040", JobTaskName = "040 - Earthworks" },

new JobTask() { JobNo = "373", JobTaskNo = "045", JobTaskName = "045 - Geotech" },

new JobTask() { JobNo = "373", JobTaskNo = "050", JobTaskName = "050 - Drainage" },

new JobTask() { JobNo = "373", JobTaskNo = "060", JobTaskName = "060 - Roading" },

new JobTask() { JobNo = "373", JobTaskNo = "070", JobTaskName = "070 - Services" },

new JobTask() { JobNo = "373", JobTaskNo = "080", JobTaskName = "080 - Concrete" },

new JobTask() { JobNo = "373", JobTaskNo = "090", JobTaskName = "090 - Structures" },

new JobTask() { JobNo = "373", JobTaskNo = "100", JobTaskName = "100 - Variations" },

new JobTask() { JobNo = "373", JobTaskNo = "105", JobTaskName = "105 - Labour" },

new JobTask() { JobNo = "373", JobTaskNo = "110", JobTaskName = "110 - Plant" },

new JobTask() { JobNo = "373", JobTaskNo = "120", JobTaskName = "120 - Unproductive Work" },

new JobTask() { JobNo = "373", JobTaskNo = "140", JobTaskName = "140 - Remedial Work" },

new JobTask() { JobNo = "373", JobTaskNo = "WET", JobTaskName = "WET - Wet Weather" },

new JobTask() { JobNo = "380", JobTaskNo = "010", JobTaskName = "010 - Preliminary & General" },

new JobTask() { JobNo = "380", JobTaskNo = "015", JobTaskName = "015 - Traffic Management" },

new JobTask() { JobNo = "380", JobTaskNo = "020", JobTaskName = "020 - Clearing & Demolition" },

new JobTask() { JobNo = "380", JobTaskNo = "030", JobTaskName = "030 - Sediment & Erosion Control" },

new JobTask() { JobNo = "380", JobTaskNo = "040", JobTaskName = "040 - Earthworks" },

new JobTask() { JobNo = "380", JobTaskNo = "045", JobTaskName = "045 - Geotech" },

new JobTask() { JobNo = "380", JobTaskNo = "050", JobTaskName = "050 - Drainage" },

new JobTask() { JobNo = "380", JobTaskNo = "060", JobTaskName = "060 - Roading" },

new JobTask() { JobNo = "380", JobTaskNo = "070", JobTaskName = "070 - Services" },

new JobTask() { JobNo = "380", JobTaskNo = "080", JobTaskName = "080 - Concrete" },

new JobTask() { JobNo = "380", JobTaskNo = "090", JobTaskName = "090 - Structures" },

new JobTask() { JobNo = "380", JobTaskNo = "100", JobTaskName = "100 - Variations" },

new JobTask() { JobNo = "380", JobTaskNo = "105", JobTaskName = "105 - Labour" },

new JobTask() { JobNo = "380", JobTaskNo = "110", JobTaskName = "110 - Plant" },

new JobTask() { JobNo = "380", JobTaskNo = "120", JobTaskName = "120 - Unproductive Work" },

new JobTask() { JobNo = "380", JobTaskNo = "140", JobTaskName = "140 - Remedial Work" },

new JobTask() { JobNo = "380", JobTaskNo = "150", JobTaskName = "150 - Retentions" },

new JobTask() { JobNo = "380", JobTaskNo = "900", JobTaskName = "900 - Wet Weather" },

new JobTask() { JobNo = "400", JobTaskNo = "010", JobTaskName = "010 - Preliminary & General" },

new JobTask() { JobNo = "400", JobTaskNo = "015", JobTaskName = "015 - Traffic Management" },

new JobTask() { JobNo = "400", JobTaskNo = "020", JobTaskName = "020 - Clearing & Demolition" },

new JobTask() { JobNo = "400", JobTaskNo = "030", JobTaskName = "030 - Sediment & Erosion Control" },

new JobTask() { JobNo = "400", JobTaskNo = "040", JobTaskName = "040 - Earthworks" },

new JobTask() { JobNo = "400", JobTaskNo = "045", JobTaskName = "045 - Geotech" },

new JobTask() { JobNo = "400", JobTaskNo = "050", JobTaskName = "050 - Drainage" },

new JobTask() { JobNo = "400", JobTaskNo = "060", JobTaskName = "060 - Roading" },

new JobTask() { JobNo = "400", JobTaskNo = "070", JobTaskName = "070 - Services" },

new JobTask() { JobNo = "400", JobTaskNo = "080", JobTaskName = "080 - Streetscape Works" },

new JobTask() { JobNo = "400", JobTaskNo = "090", JobTaskName = "090 - Structures" },

new JobTask() { JobNo = "400", JobTaskNo = "100", JobTaskName = "100 - Variations" },

new JobTask() { JobNo = "400", JobTaskNo = "105", JobTaskName = "105 - Labour" },

new JobTask() { JobNo = "400", JobTaskNo = "110", JobTaskName = "110 - Plant" },

new JobTask() { JobNo = "400", JobTaskNo = "120", JobTaskName = "120 - Unproductive Work" },

new JobTask() { JobNo = "400", JobTaskNo = "140", JobTaskName = "140 - Remedial Work" },

new JobTask() { JobNo = "400", JobTaskNo = "WET", JobTaskName = "WET - 900 Wet Weather" },

new JobTask() { JobNo = "440", JobTaskNo = "010", JobTaskName = "010 - Preliminary & General" },

new JobTask() { JobNo = "440", JobTaskNo = "015", JobTaskName = "015 - Traffic Management" },

new JobTask() { JobNo = "440", JobTaskNo = "020", JobTaskName = "020 - Clearing & Demolition" },

new JobTask() { JobNo = "440", JobTaskNo = "030", JobTaskName = "030 - Sediment & Erosion Control" },

new JobTask() { JobNo = "440", JobTaskNo = "040", JobTaskName = "040 - Earthworks" },

new JobTask() { JobNo = "440", JobTaskNo = "045", JobTaskName = "045 - Geotech" },

new JobTask() { JobNo = "440", JobTaskNo = "050", JobTaskName = "050 - Drainage" },

new JobTask() { JobNo = "440", JobTaskNo = "060", JobTaskName = "060 - Roading" },

new JobTask() { JobNo = "440", JobTaskNo = "070", JobTaskName = "070 - Services" },

new JobTask() { JobNo = "440", JobTaskNo = "080", JobTaskName = "080 - Concrete" },

new JobTask() { JobNo = "440", JobTaskNo = "090", JobTaskName = "090 - Structures" },

new JobTask() { JobNo = "440", JobTaskNo = "100", JobTaskName = "100 - Variations" },

new JobTask() { JobNo = "440", JobTaskNo = "120", JobTaskName = "120 - Unproductive Work" },

new JobTask() { JobNo = "440", JobTaskNo = "140", JobTaskName = "140 - Remedial Work" },

new JobTask() { JobNo = "440", JobTaskNo = "WET", JobTaskName = "WET - 900 Wet Weather" },

new JobTask() { JobNo = "441", JobTaskNo = "010", JobTaskName = "010 - Preliminary & General" },

new JobTask() { JobNo = "441", JobTaskNo = "015", JobTaskName = "015 - Traffic Management" },

new JobTask() { JobNo = "441", JobTaskNo = "020", JobTaskName = "020 - Clearing & Demolition" },

new JobTask() { JobNo = "441", JobTaskNo = "030", JobTaskName = "030 - Sediment & Erosion Control" },

new JobTask() { JobNo = "441", JobTaskNo = "040", JobTaskName = "040 - Earthworks" },

new JobTask() { JobNo = "441", JobTaskNo = "045", JobTaskName = "045 - Geotech" },

new JobTask() { JobNo = "441", JobTaskNo = "050", JobTaskName = "050 - Drainage" },

new JobTask() { JobNo = "441", JobTaskNo = "060", JobTaskName = "060 - Roading" },

new JobTask() { JobNo = "441", JobTaskNo = "070", JobTaskName = "070 - Services" },

new JobTask() { JobNo = "441", JobTaskNo = "080", JobTaskName = "080 - Concrete" },

new JobTask() { JobNo = "441", JobTaskNo = "090", JobTaskName = "090 - Structures" },

new JobTask() { JobNo = "441", JobTaskNo = "100", JobTaskName = "100 - Variations" },

new JobTask() { JobNo = "441", JobTaskNo = "120", JobTaskName = "120 - Unproductive Work" },

new JobTask() { JobNo = "441", JobTaskNo = "140", JobTaskName = "140 - Remedial Work" },

new JobTask() { JobNo = "441", JobTaskNo = "150", JobTaskName = "150 - Retentions" },

new JobTask() { JobNo = "441", JobTaskNo = "900", JobTaskName = "900 - Wet Weather" }

}



private void OncboJobChanged(object sender, Syncfusion.Maui.Inputs.SelectionChangedEventArgs e)

{

    if (cboJobs.SelectedItem == null) return;


    getJobName = (cboJobs.SelectedItem as Job).JobName.ToString();

    getJobNo = (cboJobs.SelectedItem as Job).JobNo.ToString();

    getcboJobIndex = cboJobs.SelectedIndex;

    getlinetype = 0;

}


xaml

<editors:SfComboBox

  
x
:Name="cboJobs"

  
Grid.Row
="2"

  
Grid.ColumnSpan
="3"

  
ItemsSource
="{Binding Jobs}"

  
DisplayMemberPath
="JobName"

  
TextMemberPath
="JobName"

  
SelectionChanged
="OncboJobChanged"          

  
SelectedValuePath
="JobName"

  
Placeholder
="Select a job"

  
TextSearchMode
="Contains"

  
IsEditable
="true"

  
IsFilteringEnabled
="true"

           

/>


<editors:SfComboBox

  
x
:Name="cboJobTasks"

  
Grid.Row
="4"

  
Grid.ColumnSpan
="3"

  
MaxDropDownHeight
="500"

  
ItemsSource
="{Binding JobTasks}"

  
DisplayMemberPath
="JobTaskName"

  
SelectionChanged
="OncboJobTaskChanged"          

  
SelectedValuePath
="JobTaskName"

  
Placeholder
="Select a task"

  
TextSearchMode
="Contains"

  
IsEditable
="true"

  
IsFilteringEnabled
="true">


<editors:SfComboBox.FilterBehavior>

    <local:JobTaskFilteringBehavior/>

</editors:SfComboBox.FilterBehavior>

 

/>



public class JobTaskFilteringBehavior : IComboBoxFilterBehavior

{

   

    public List<int> GetMatchingIndexes(SfComboBox source, ComboBoxFilterInfo filterInfo)

    {

        List<int> filteredlist = new List<int>();

        List<JobTask> TaskItems = source.ItemsSourceList.OfType<JobTask>().ToList();


        filteredlist.AddRange(from JobTask item in TaskItems

                              where item.JobNo.StartsWith(filterInfo.Text, StringComparison.CurrentCultureIgnoreCase)     

                              select JobTask.IndexOf(item));


        return filteredlist;

    }

}


3 Replies

KP Kamalesh Periyasamy Syncfusion Team March 5, 2024 02:34 PM UTC

Hi Ross,


Thank you for your patience.


We have validated the reported query, Based on the provided details and code snippet we have developed the sample to meet your requirements. In the sample, when a JobName is selected from the first ComboBox, it filters the JobTaskName in the second ComboBox based on the JobNo in the collection.


Please review the sample provided and let us know if it fulfills your requirements. If you have any additional questions or concerns, don't hesitate to reach out.


Regards,

Kamalesh P


Attachment: ComboBoxSample_4fc492a5.zip


RB Ross Bell Syer March 6, 2024 06:32 AM UTC

Thanks so much for this Kamalesh - awesome support as always. I will take a look and see if your example solves my problem.



PR Preethi Rajakandham Syncfusion Team March 7, 2024 06:04 AM UTC

Hi Ross Bell Syer,


You're welcome. Please test if the provided example works for you and let us know. We will wait to hear further updates from you.


Regards,

Preethi R


Loader.
Up arrow icon