Filtering a ComboBox in a DataGrid based on another combobox in the datagrid in WPF C#?

Mesh Ka 345 Reputation points
2024-01-07T16:23:22.5066667+00:00

In my Example Here i have a 3 ComboBoxes in a Datagrid displayoing Countries, Provinces and Districts respectively.How can i Filter the Provinces by Countries and Districts by Provinces in such a way that when the user selects a country he only gets the provinces that belong to the selected country and when he selects a province he only gets the districts belonging to that province and when he changes the country the province and districts are set to null and when he changes the province the district is set to null:Here is the MainWindwo.xaml:

<Window
    x:Class="DataGridBindingExample.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:local="clr-namespace:DataGridBindingExample"
    xmlns:materialdesign="http://materialdesigninxaml.net/winfx/xaml/themes"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:vm="clr-namespace:DataGridBindingExample"
    Title="MainWindow"
    Width="800"
    Height="450"
    Topmost="True"
    mc:Ignorable="d">
    <Window.Resources>
        <vm:MainWindowViewModel x:Key="MainWindowViewModel" />
    </Window.Resources>

    <Grid>
        <Grid.Background>
            <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
                <GradientStop Offset="1" Color="#FF06013F" />
                <GradientStop Color="#FF040F2E" />
            </LinearGradientBrush>
        </Grid.Background>
        <StackPanel>
            <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding PlacesOfInterest}">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Country">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                                    Width="120"
                                    DisplayMemberPath="CountryName"
                                    ItemsSource="{Binding DataContext.Countries, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
                                    SelectedValue="{Binding CountryName}"
                                    SelectedValuePath="CountryName" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Province">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                                    Width="120"
                                    DisplayMemberPath="ProvinceName"
                                    ItemsSource="{Binding DataContext.Provinces, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
                                    SelectedValue="{Binding ProvinceID}"
                                    SelectedValuePath="ProvinceID" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="District">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                                    Width="120"
                                    DisplayMemberPath="DistrictName"
                                    ItemsSource="{Binding DataContext.Districts, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}"
                                    SelectedValue="{Binding DistrictID}"
                                    SelectedValuePath="DistrictID" />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </

And Here is the ViewModel:

using CommunityToolkit.Mvvm.ComponentModel;
using DataGridBindingExample.Models;
using MaterialDesignFixedHintTextBox;
using System.Collections.ObjectModel;

namespace DataGridBindingExample
{
    public partial class MainWindowViewModel : ObservableObject
    {
        [ObservableProperty]
        ObservableCollection<PlacesOfInterest> placesOfInterest;
        [ObservableProperty]
        ObservableCollection<CountriesModel> countries;
        [ObservableProperty]
        ObservableCollection<ProvincesModel> provinces;
        [ObservableProperty]
        ObservableCollection<DistrictsModel> districts;


        public MainWindowViewModel()
        {
            this.PlacesOfInterest = new ObservableCollection<PlacesOfInterest>(DAL.LoadPlacesOfInterest());
            this.Countries = new ObservableCollection<CountriesModel>(DAL.LoadCountries());
            this.Provinces = new ObservableCollection<ProvincesModel>(DAL.LoadProvinces());
            this.Districts = new ObservableCollection<DistrictsModel>(DAL.LoadDistricts());
        }

    }
}

And Here is the Data Access Layer:

using Dapper;
using DataGridBindingExample.Models;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;

namespace MaterialDesignFixedHintTextBox
{
    public class DAL
    {
        private static readonly string ConnString = "Data Source=(local);Initial Catalog=CollegeDB;Integrated Security=True";

        //**************************************************************************************************

        public static List<PlacesOfInterest> LoadPlacesOfInterest()
        {
            using (IDbConnection conn = new SqlConnection(ConnString))
            {
                if (conn.State == ConnectionState.Closed) conn.Open();
                return conn.Query<PlacesOfInterest>("SELECT * FROM PlacesOfInterest").ToList();
            }
        }

        public static List<CountriesModel> LoadCountries()
        {
            using (IDbConnection conn = new SqlConnection(ConnString))
            {
                if (conn.State == ConnectionState.Closed) conn.Open();
                return conn.Query<CountriesModel>("SELECT * FROM Countries").ToList();
            }
        }

        public static List<ProvincesModel> LoadProvinces()
        {
            using (IDbConnection conn = new SqlConnection(ConnString))
            {
                if (conn.State == ConnectionState.Closed) conn.Open();
                return conn.Query<ProvincesModel>("SELECT * FROM Provinces").ToList();
            }
        }

        public static List<DistrictsModel> LoadDistricts()
        {
            using (IDbConnection conn = new SqlConnection(ConnString))
            {
                if (conn.State == ConnectionState.Closed) conn.Open();
                return conn.Query<DistrictsModel>("SELECT * FROM Districts").ToList();
            }
        }
    }
}

And are the Models:

using CommunityToolkit.Mvvm.ComponentModel;

namespace DataGridBindingExample.Models
{
    public partial class PlacesOfInterest : ObservableObject
    {
        [ObservableProperty]
        int iD;

        [ObservableProperty]
        string countryName;

        [ObservableProperty]
        int provinceID;

        [ObservableProperty]
        int districtID;

    }
}

using CommunityToolkit.Mvvm.ComponentModel;

namespace DataGridBindingExample.Models
{
    public partial class CountriesModel : ObservableObject
    {
        [ObservableProperty]
        string countryName;
    }
}

using CommunityToolkit.Mvvm.ComponentModel;

namespace DataGridBindingExample.Models
{
    public partial class ProvincesModel : ObservableObject
    {
        [ObservableProperty]
        string countryName;

        [ObservableProperty]
        int provinceID;

        [ObservableProperty]
        string provinceName;

    }
}

using CommunityToolkit.Mvvm.ComponentModel;

namespace DataGridBindingExample.Models
{
    public partial class DistrictsModel : ObservableObject
    {
        [ObservableProperty]
        int provinceID;

        [ObservableProperty]
        int districtID;

        [ObservableProperty]
        string districtName;

    }
}

DATABASE:

USE [CollegeDB]
GO
/****** Object:  Table [dbo].[Countries]    Script Date: 1/7/2024 7:29:40 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Countries](
	[CountryName] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_Countries] PRIMARY KEY CLUSTERED 
(
	[CountryName] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Districts]    Script Date: 1/7/2024 7:29:40 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Districts](
	[ProvinceID] [int] NULL,
	[DistrictID] [int] IDENTITY(1,1) NOT NULL,
	[DistrictName] [nvarchar](50) NULL,
 CONSTRAINT [PK_Districts] PRIMARY KEY CLUSTERED 
(
	[DistrictID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[PlacesOfInterest]    Script Date: 1/7/2024 7:29:40 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[PlacesOfInterest](
	[ID] [int] IDENTITY(1,1) NOT NULL,
	[CountryName] [nvarchar](50) NULL,
	[ProvinceID] [int] NULL,
	[DistrictID] [int] NULL,
 CONSTRAINT [PK_PlacesOfInterest] PRIMARY KEY CLUSTERED 
(
	[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Provinces]    Script Date: 1/7/2024 7:29:40 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Provinces](
	[CountryName] [nvarchar](50) NULL,
	[ProvinceID] [int] IDENTITY(1,1) NOT NULL,
	[ProvinceName] [nvarchar](50) NULL,
 CONSTRAINT [PK_Provinces] PRIMARY KEY CLUSTERED 
(
	[ProvinceID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[Countries] ([CountryName]) VALUES (N'Country1')
GO
INSERT [dbo].[Countries] ([CountryName]) VALUES (N'Country2')
GO
INSERT [dbo].[Countries] ([CountryName]) VALUES (N'Country3')
GO
INSERT [dbo].[Countries] ([CountryName]) VALUES (N'Country4')
GO
INSERT [dbo].[Countries] ([CountryName]) VALUES (N'Country5')
GO
SET IDENTITY_INSERT [dbo].[Districts] ON 
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (1, 1, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (1, 2, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (2, 3, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (2, 4, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (3, 5, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (3, 6, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (4, 7, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (4, 8, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (5, 9, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (5, 10, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (6, 11, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (6, 12, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (7, 13, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (7, 14, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (8, 15, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (8, 16, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (9, 17, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (9, 18, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (10, 19, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (10, 20, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (11, 21, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (11, 22, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (12, 23, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (12, 24, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (13, 25, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (13, 26, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (14, 27, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (14, 28, N'District2')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (15, 29, N'District1')
GO
INSERT [dbo].[Districts] ([ProvinceID], [DistrictID], [DistrictName]) VALUES (15, 30, N'District2')
GO
SET IDENTITY_INSERT [dbo].[Districts] OFF
GO
SET IDENTITY_INSERT [dbo].[PlacesOfInterest] ON 
GO
INSERT [dbo].[PlacesOfInterest] ([ID], [CountryName], [ProvinceID], [DistrictID]) VALUES (1, N'Country1', 1, 1)
GO
SET IDENTITY_INSERT [dbo].[PlacesOfInterest] OFF
GO
SET IDENTITY_INSERT [dbo].[Provinces] ON 
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country1', 1, N'Province1')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country1', 2, N'Province2')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country1', 3, N'Province3')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country2', 4, N'Province1')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country2', 5, N'Province2')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country2', 6, N'Province3')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country3', 7, N'Province1')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country3', 8, N'Province2')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country3', 9, N'Province3')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country4', 10, N'Province1')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country4', 11, N'Province2')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country4', 12, N'Province3')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country5', 13, N'Province1')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country5', 14, N'Province2')
GO
INSERT [dbo].[Provinces] ([CountryName], [ProvinceID], [ProvinceName]) VALUES (N'Country5', 15, N'Province3')
GO
SET IDENTITY_INSERT [dbo].[Provinces] OFF
GO
ALTER TABLE [dbo].[Districts]  WITH CHECK ADD  CONSTRAINT [FK_Districts_Provinces] FOREIGN KEY([ProvinceID])
REFERENCES [dbo].[Provinces] ([ProvinceID])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Districts] CHECK CONSTRAINT [FK_Districts_Provinces]
GO
ALTER TABLE [dbo].[PlacesOfInterest]  WITH CHECK ADD  CONSTRAINT [FK_PlacesOfInterest_Countries] FOREIGN KEY([CountryName])
REFERENCES [dbo].[Countries] ([CountryName])
GO
ALTER TABLE [dbo].[PlacesOfInterest] CHECK CONSTRAINT [FK_PlacesOfInterest_Countries]
GO
ALTER TABLE [dbo].[PlacesOfInterest]  WITH CHECK ADD  CONSTRAINT [FK_PlacesOfInterest_Districts] FOREIGN KEY([DistrictID])
REFERENCES [dbo].[Districts] ([DistrictID])
GO
ALTER TABLE [dbo].[PlacesOfInterest] CHECK CONSTRAINT [FK_PlacesOfInterest_Districts]
GO
ALTER TABLE [dbo].[PlacesOfInterest]  WITH CHECK ADD  CONSTRAINT [FK_PlacesOfInterest_Provinces] FOREIGN KEY([ProvinceID])
REFERENCES [dbo].[Provinces] ([ProvinceID])
GO
ALTER TABLE [dbo].[PlacesOfInterest] CHECK CONSTRAINT [FK_PlacesOfInterest_Provinces]
GO
ALTER TABLE [dbo].[Provinces]  WITH CHECK ADD  CONSTRAINT [FK_Provinces_Countries] FOREIGN KEY([CountryName])
REFERENCES [dbo].[Countries] ([CountryName])
ON UPDATE CASCADE
ON DELETE CASCADE
GO
ALTER TABLE [dbo].[Provinces] CHECK CONSTRAINT [FK_Provinces_Countries]
GO

Windows Presentation Foundation
Windows Presentation Foundation
A part of the .NET Framework that provides a unified programming model for building line-of-business desktop applications on Windows.
2,675 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
10,268 questions
XAML
XAML
A language based on Extensible Markup Language (XML) that enables developers to specify a hierarchy of objects with a set of properties and logic.
765 questions
{count} vote

3 answers

Sort by: Most helpful
  1. Hui Liu-MSFT 38,331 Reputation points Microsoft Vendor
    2024-01-08T06:24:05.25+00:00

    Hi,@Mesh Ka.Welcome to Microsoft Q&A.

    I made the following modifications based on your code. You could modify it according to your namespace.

    <Window.DataContext> <local:MainWindowViewModel /> </Window.DataContext>

    
    <Window x:Class="ComboboxDemo.MainWindow"
     ...
            xmlns:local="clr-namespace:ComboboxDemo"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800">
        <Window.DataContext>
            <local:MainWindowViewModel />
        </Window.DataContext>
        <Grid >
    
        <StackPanel>
            <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding PlacesOfInterest}">
                <DataGrid.Columns>
    
                 
                    <DataGridTemplateColumn Header="Country">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                Width="120"
                DisplayMemberPath="CountryName"
                ItemsSource="{Binding DataContext.Countries, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                SelectedItem="{Binding DataContext.SelectedCountry, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Mode=TwoWay}" 
            />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="Province">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                Width="120"
                DisplayMemberPath="ProvinceName"
                ItemsSource="{Binding DataContext.Provinces, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                SelectedItem="{Binding DataContext.SelectedProvince, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Mode=TwoWay}"
            />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                    <DataGridTemplateColumn Header="District">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <ComboBox
                Width="120"
                DisplayMemberPath="DistrictName"
                ItemsSource="{Binding DataContext.Districts, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}"
                SelectedItem="{Binding DataContext.SelectedDistrict, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Mode=TwoWay}"
            />
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </StackPanel>
    </Grid>
    
    </Window>
    
    
    public partial class MainWindowViewModel : ObservableObject
      {
        [ObservableProperty]
        ObservableCollection<PlacesOfInterest> placesOfInterest;
        [ObservableProperty]
        ObservableCollection<CountriesModel> countries;
        [ObservableProperty]
        ObservableCollection<ProvincesModel> provinces;
        [ObservableProperty]
        ObservableCollection<DistrictsModel> districts;
    
    
        public MainWindowViewModel()
        {
          this.PlacesOfInterest = new ObservableCollection<PlacesOfInterest>(DAL.LoadPlacesOfInterest());
          this.Countries = new ObservableCollection<CountriesModel>(DAL.LoadCountries());
          this.Provinces = new ObservableCollection<ProvincesModel>(DAL.LoadProvinces());
          this.Districts = new ObservableCollection<DistrictsModel>(DAL.LoadDistricts());
        }
    
        private CountriesModel selectedCountry;
        public CountriesModel SelectedCountry
        {
          get { return selectedCountry; }
          set
          {
            selectedCountry = value;
            Provinces = GetProvincesForCountry(selectedCountry);
            SelectedProvince = null;
            SelectedDistrict = null;
            OnPropertyChanged(nameof(SelectedCountry));
          }
        }
    
        private ProvincesModel selectedProvince;
        public ProvincesModel SelectedProvince
        {
          get { return selectedProvince; }
          set
          {
            selectedProvince = value;
            Districts = GetDistrictsForProvince(selectedProvince);
            SelectedDistrict = null;
            OnPropertyChanged(nameof(SelectedProvince));
          }
        }
    
        private DistrictsModel selectedDistrict;
        public DistrictsModel SelectedDistrict
        {
          get { return selectedDistrict; }
          set
          {
            selectedDistrict = value;
            OnPropertyChanged(nameof(SelectedDistrict));
          }
        }
        private ObservableCollection<ProvincesModel> GetProvincesForCountry(CountriesModel country)
        {
          return new ObservableCollection<ProvincesModel>(DAL.LoadProvincesForCountry(country));
        }
    
        private ObservableCollection<DistrictsModel> GetDistrictsForProvince(ProvincesModel province)
        {
          return new ObservableCollection<DistrictsModel>(DAL.LoadDistrictsForProvince(province));
        }
    
      }
      public class DAL
      {
        private static readonly string ConnString = "...";
    
        
        public static List<PlacesOfInterest> LoadPlacesOfInterest()
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
            return conn.Query<PlacesOfInterest>("SELECT * FROM PlacesOfInterest").ToList();
          }
        }
    
        public static List<CountriesModel> LoadCountries()
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
            return conn.Query<CountriesModel>("SELECT * FROM Countries").ToList();
          }
        }
    
        public static List<ProvincesModel> LoadProvinces()
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
            return conn.Query<ProvincesModel>("SELECT * FROM Provinces").ToList();
          }
        }
        public static List<ProvincesModel> LoadProvincesForCountry(CountriesModel country)
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
            string query = "SELECT * FROM Provinces WHERE CountryName = @CountryName";
    
            
            return conn.Query<ProvincesModel>(query, new { CountryName = country.CountryName }).ToList();
          }
        }
        public static List<DistrictsModel> LoadDistricts()
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
            return conn.Query<DistrictsModel>("SELECT * FROM Districts").ToList();
          }
        }
        public static List<DistrictsModel> LoadDistrictsForProvince(ProvincesModel province)
        {
          using (IDbConnection conn = new SqlConnection(ConnString))
          {
            if (conn.State == ConnectionState.Closed) conn.Open();
    
            string query;
            if (province==null)
            {
              return conn.Query<DistrictsModel>("SELECT * FROM Districts").ToList();
    
            }
            else
            {
              query = "SELECT * FROM Districts WHERE ProvinceID = @ProvinceID";
              return conn.Query<DistrictsModel>(query, new { ProvinceID = province.ProvinceID }).ToList();
            }
          
          
          }
        }
      }
    
    
    

    The result:

    8


    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    1 person found this answer helpful.

  2. Peter Fleischer (former MVP) 19,231 Reputation points
    2024-01-08T15:27:09.7466667+00:00

    Hi,
    her is a possible solution:

    XAML:

    <Window x:Class="WpfApp1.Window135"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp135"
            mc:Ignorable="d"
            Title="Mesh Ka_230107" Height="450" Width="1000">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
        <local:ConvProvenceID x:Key="ConvProvenceID"/>
        <local:ConvDistrictID x:Key="ConvDistrictID"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <Grid.RowDefinitions>
          <RowDefinition Height="auto"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="600"/>
          <ColumnDefinition Width="200"/>
          <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <Label Grid.Column="0" Grid.Row="0" Content="DataGrid" HorizontalAlignment="Center"/>
        <DataGrid ItemsSource="{Binding ViewPlacesOfInterest}" 
                  SelectedItem="{Binding SelectedPlace}"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False"
                  Grid.Column="0" Grid.Row="1" Margin="5">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding PlaceName}" Header="Place"/>
            <DataGridTemplateColumn Header="Country">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <ComboBox
                    Width="120"
                    ItemsSource="{Binding AllCountries, Source={StaticResource vm}}"
                    DisplayMemberPath="CountryName"
                    SelectedValue="{Binding CountryID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="CountryID">
                  </ComboBox>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Province">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock>
                    <TextBlock.Text>
                      <MultiBinding Converter="{StaticResource ConvProvenceID}">
                        <Binding Path="ProvinceID"/>
                        <Binding Path="AllProvinces" Source="{StaticResource vm}"/>
                      </MultiBinding>
                    </TextBlock.Text>
                  </TextBlock> 
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
              <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate DataType="ComboBox">
                  <ComboBox
                    Width="120"
                    DisplayMemberPath="ProvinceName"
                    ItemsSource="{Binding CurrentProvinces, Source={StaticResource vm}}"
                    SelectedValue="{Binding ProvinceID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="ProvinceID" />
                </DataTemplate>
              </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="District">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock>
                    <TextBlock.Text>
                      <MultiBinding Converter="{StaticResource ConvDistrictID}">
                        <Binding Path="DistrictID"/>
                        <Binding Path="AllDistricts" Source="{StaticResource vm}"/>
                      </MultiBinding>
                    </TextBlock.Text>
                  </TextBlock>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
              <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                  <ComboBox
                    Width="120"
                    DisplayMemberPath="DistrictName"
                    ItemsSource="{Binding CurrentDistricts, Source={StaticResource vm}}"
                    SelectedValue="{Binding DistrictID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="DistrictID" />
                </DataTemplate>
              </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
    
        <Label Grid.Column="1" Grid.Row="0" Content="DetailView" HorizontalAlignment="Center"/>
        <Grid Grid.Column="1" Grid.Row="1"  DataContext="{Binding SelectedPlace}">
          <Grid.Resources>
            <Style TargetType="Label">
              <Setter Property="HorizontalAlignment" Value="Right"/>
            </Style>
            <Style TargetType="TextBox">
              <Setter Property="Margin" Value="5"/>
            </Style>
          </Grid.Resources>
          <Grid.RowDefinitions>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition Height="auto"/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="100"/>
            <ColumnDefinition/>
          </Grid.ColumnDefinitions>
          <Label Grid.Row="0" Grid.Column="0" Content="Selected place"/>
          <Label Grid.Row="1" Grid.Column="0" Content="Place"/>
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding PlaceName}"/>
          <Label Grid.Row="2" Grid.Column="0" Content="Country"/>
          <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding CountryID}"/>
          <Label Grid.Row="3" Grid.Column="0" Content="Province"/>
          <TextBox Grid.Row="3" Grid.Column="1" Text="{Binding ProvinceID}"/>
          <Label Grid.Row="4" Grid.Column="0" Content="District"/>
          <TextBox Grid.Row="4" Grid.Column="1" Text="{Binding DistrictID}"/>
        </Grid>
    
        <Label Grid.Column="2" Grid.Row="0" Content="Dispülay Hierarchy" HorizontalAlignment="Center"/>
        <TreeView Grid.Column="2" Grid.Row="1"  ItemsSource="{Binding AllCountries}" Margin="5">
          <TreeView.Resources>
            <!--<Style TargetType="TreeViewItem">
              <Setter Property="IsExpanded" Value="True"/>
            </Style>-->
            <HierarchicalDataTemplate DataType="{x:Type local:Country}" ItemsSource="{Binding ListOfProvinces}">
              <TextBlock Text="{Binding CountryName}"/>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:Province}" ItemsSource="{Binding ListOfDistricts}">
              <TextBlock Text="{Binding ProvinceName}"/>
            </HierarchicalDataTemplate>
            <HierarchicalDataTemplate DataType="{x:Type local:District}">
              <TextBlock Text="{Binding DistrictName}"/>
            </HierarchicalDataTemplate>
          </TreeView.Resources>
        </TreeView>
    
      </Grid>
    </Window>
    

    Code:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Globalization;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp135
    {
    	public class ViewModel : INotifyPropertyChanged
    	{
    		/// <summary>
    		/// generate demo data
    		/// </summary>
    		public ViewModel()
    		{
    			int cntPlaces = 30;
    			int cntCountries = 5;
    			int cntProvinces = 50;
    			int cntDistricts = 100;
    			Random rnd = new Random();
    			for (int i = 1; i < cntPlaces + 1; i++)
    				PlacesOfInterest.Add(new PlaceOfInterest() { iD = i, PlaceName = $"Place {i}", CountryID = rnd.Next(1, cntCountries + 1) });
    			for (int i = 1; i < cntCountries + 1; i++)
    				AllCountries.Add(new Country() { CountryID = i, CountryName = $"Country {i}" });
    			for (int i = 1; i < cntProvinces + 1; i++)
    				AllProvinces.Add(new Province() { ProvinceID = i, ProvinceName = $"Province {i}" });
    			for (int i = 1; i < cntDistricts + 1; i++)
    				AllDistricts.Add(new District() { DistrictID = i, DistrictName = $"District {i}" });
    
    			// include references
    			for (int i = 1; i < cntProvinces + 1; i++)
    				AllCountries[rnd.Next(0, cntCountries)].ListOfProvinces.Add(AllProvinces[i - 1]);
    			for (int i = 1; i < cntDistricts + 1; i++)
    				AllProvinces[rnd.Next(0, cntProvinces)].ListOfDistricts.Add(AllDistricts[i - 1]);
    			for (int i = 1; i < cntPlaces + 1; i++)
    			{
    				var l1 = AllCountries[PlacesOfInterest[i - 1].CountryID - 1].ListOfProvinces;
    				if (l1.Count > 0) PlacesOfInterest[i - 1].ProvinceID = l1[rnd.Next(0, l1.Count)].ProvinceID;
    				var l2 = AllProvinces[PlacesOfInterest[i - 1].CountryID - 1].ListOfDistricts;
    				if (l2.Count > 0) PlacesOfInterest[i - 1].DistrictID = l2[rnd.Next(0, l2.Count)].DistrictID;
    			}
    
    			cvsPlacesOfInterest.Source= PlacesOfInterest;
    		}
    		private ObservableCollection<PlaceOfInterest> PlacesOfInterest { get; set; } = new ObservableCollection<PlaceOfInterest>();
    		private CollectionViewSource cvsPlacesOfInterest = new CollectionViewSource();
    		public ICollectionView ViewPlacesOfInterest { get => cvsPlacesOfInterest.View; }
    
    		public ObservableCollection<Country> AllCountries { get; set; } = new ObservableCollection<Country>();
    		public ObservableCollection<Province> AllProvinces { get; set; } = new ObservableCollection<Province>();
    		public ObservableCollection<District> AllDistricts { get; set; } = new ObservableCollection<District>();
    
    		public object CurrentProvinces { get => AllCountries[SelectedPlace.CountryID-1].ListOfProvinces; }
    		public object CurrentDistricts { get => AllProvinces[SelectedPlace.ProvinceID-1].ListOfDistricts; }
    
    
    		private PlaceOfInterest _selectedPlace;
    		public PlaceOfInterest SelectedPlace
    		{
    			get => this._selectedPlace;
    			set { this._selectedPlace = value; OnPropertyChanged(); OnPropertyChanged(nameof(ViewPlacesOfInterest)); }
    		}
    
    		public event PropertyChangedEventHandler PropertyChanged;
    		public event EventHandler CanExecuteChanged;
    		private void OnPropertyChanged([CallerMemberName] String propertyName = "")
    				=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    	}
    
    
    	public class PlaceOfInterest : INotifyPropertyChanged
    	{
    		public int iD { get; set; }
    		public string PlaceName { get; set; }
    
    		int _countryID;
    		public int CountryID
    		{
    			get => this._countryID;
    			set { this._countryID = value; ProvinceID = 0; DistrictID = 0; OnPropertyChanged(); }
    		}
    
    		int _provinceID;
    		public int ProvinceID
    		{
    			get => this._provinceID;
    			set { this._provinceID = value; DistrictID = 0; OnPropertyChanged(); }
    		}
    
    		int _districtID;
    		public int DistrictID
    		{
    			get => this._districtID;
    			set { this._districtID = value; OnPropertyChanged(); }
    		}
    
    		public event PropertyChangedEventHandler PropertyChanged;
    		public event EventHandler CanExecuteChanged;
    		private void OnPropertyChanged([CallerMemberName] String propertyName = "")
    				=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    	}
    	public partial class Country
    	{
    		public int CountryID { get; set; }
    		public string CountryName { get; set; }
    	}
    	public partial class Province
    	{
    		public int ProvinceID { get; set; }
    		public string ProvinceName { get; set; }
    	}
    	public class District
    	{
    		public int DistrictID { get; set; }
    		public string DistrictName { get; set; }
    	}
    
    	// additional partial classes
    	public partial class Country
    	{
    		public List<Province> ListOfProvinces { get; } = new List<Province>();
    	}
    	public partial class Province
    	{
    		public List<District> ListOfDistricts { get; } = new List<District>();
    	}
    
    	public class ConvProvenceID : IMultiValueConverter
    	{
    
    		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    		{
    			int i = (int)values[0];
    			IList<Province> l = (IList<Province>)values[1];
    			return i>0 &&(l.Count > 0) ? l[i - 1].ProvinceName : string.Empty;
    		}
    		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    	public class ConvDistrictID : IMultiValueConverter
    	{
    
    		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    		{
    			int i = (int)values[0];
    			IList<District> l = (IList<District>)values[1];
    			return (i>0 && l.Count>0)?l[i - 1].DistrictName: string.Empty;
    		}
    		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    }
    

    Result:

    x


  3. Peter Fleischer (former MVP) 19,231 Reputation points
    2024-01-10T06:12:48.13+00:00

    Hi,
    here is another refactored code with your DataModel and Database and with removed parts for debugging and demonstration.

    XAML:

    <Window x:Class="WpfApp1.Window136"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:WpfApp136"
            mc:Ignorable="d"
            Title="Mesh Ka_230107" Height="400" Width="600">
      <Window.Resources>
        <local:ViewModel x:Key="vm"/>
        <local:ConvProvenceID x:Key="ConvProvenceID"/>
        <local:ConvDistrictID x:Key="ConvDistrictID"/>
      </Window.Resources>
      <Grid DataContext="{StaticResource vm}">
        <Grid.RowDefinitions>
          <RowDefinition Height="auto"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <Label Grid.Column="0" Grid.Row="0" Content="DataGrid" HorizontalAlignment="Center"/>
        <DataGrid ItemsSource="{Binding PlacesOfInterest}" 
                  SelectedItem="{Binding SelectedPlace}"
                  AutoGenerateColumns="False"
                  CanUserAddRows="False"
                  Grid.Column="0" Grid.Row="1" Margin="5">
          <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding PlaceName}" Header="Place"/>
            <DataGridTemplateColumn Header="Country">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <ComboBox
                    Width="120"
                    ItemsSource="{Binding AllCountries, Source={StaticResource vm}}"
                    DisplayMemberPath="CountryName"
                    SelectedValue="{Binding CountryName, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="CountryName">
                  </ComboBox>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Province">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock>
                    <TextBlock.Text>
                      <MultiBinding Converter="{StaticResource ConvProvenceID}">
                        <Binding Path="ProvinceID"/>
                        <Binding Path="AllProvinces" Source="{StaticResource vm}"/>
                      </MultiBinding>
                    </TextBlock.Text>
                  </TextBlock> 
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
              <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate DataType="ComboBox">
                  <ComboBox
                    Width="120"
                    DisplayMemberPath="ProvinceName"
                    ItemsSource="{Binding CurrentProvinces, Source={StaticResource vm}}"
                    SelectedValue="{Binding ProvinceID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="ProvinceID" />
                </DataTemplate>
              </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="District">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <TextBlock>
                    <TextBlock.Text>
                      <MultiBinding Converter="{StaticResource ConvDistrictID}">
                        <Binding Path="DistrictID"/>
                        <Binding Path="AllDistricts" Source="{StaticResource vm}"/>
                      </MultiBinding>
                    </TextBlock.Text>
                  </TextBlock>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
              <DataGridTemplateColumn.CellEditingTemplate>
                <DataTemplate>
                  <ComboBox
                    Width="120"
                    DisplayMemberPath="DistrictName"
                    ItemsSource="{Binding CurrentDistricts, Source={StaticResource vm}}"
                    SelectedValue="{Binding DistrictID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="DistrictID" />
                </DataTemplate>
              </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
          </DataGrid.Columns>
        </DataGrid>
      </Grid>
    </Window>
    
    
    

    and code:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Data;
    
    namespace WpfApp136
    {
    	public class ViewModel : INotifyPropertyChanged
    	{
    		/// <summary>
    		/// load data from database
    		/// </summary>
    		public ViewModel()
    		{
    			PlacesOfInterest = new ObservableCollection<PlacesOfInterest>(DAL.LoadPlacesOfInterest());
    			AllCountries = new ObservableCollection<CountriesModel>(DAL.LoadCountries());
    			AllProvinces = new ObservableCollection<ProvincesModel>(DAL.LoadProvinces());
    			AllDistricts = new ObservableCollection<DistrictsModel>(DAL.LoadDistricts());
    		}
    		public ObservableCollection<PlacesOfInterest> PlacesOfInterest { get; set; }
    		public ObservableCollection<CountriesModel> AllCountries { get; set; }
    		public ObservableCollection<ProvincesModel> AllProvinces { get; set; }
    		public ObservableCollection<DistrictsModel> AllDistricts { get; set; }
    
    		public object CurrentProvinces
    		{ get => new ObservableCollection<ProvincesModel>(AllProvinces.Where((p) => p.CountryName == SelectedPlace.CountryName)); }
    		public object CurrentDistricts
    		{ get => new ObservableCollection<DistrictsModel>(AllDistricts.Where((p) => p.ProvinceID == SelectedPlace.ProvinceID)); }
    
    		private PlacesOfInterest _selectedPlace;
    		public PlacesOfInterest SelectedPlace
    		{
    			get => this._selectedPlace;
    			set { this._selectedPlace = value;  }
    		}
    
    		public event PropertyChangedEventHandler PropertyChanged;
    		public event EventHandler CanExecuteChanged;
    		private void OnPropertyChanged([CallerMemberName] String propertyName = "")
    				=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    	}
    
    	public class DAL
    	{
    		private static readonly string ConnString = "Data Source=(local);Initial Catalog=CollegeDB;Integrated Security=True";
    
    		//**************************************************************************************************
    
    		public static List<PlacesOfInterest> LoadPlacesOfInterest()
    		{
    			using (IDbConnection conn = new SqlConnection(ConnString))
    			{
    				if (conn.State == ConnectionState.Closed) conn.Open();
    				return conn.Query<PlacesOfInterest>("SELECT * FROM PlacesOfInterest").ToList();
    			}
    		}
    
    		public static List<CountriesModel> LoadCountries()
    		{
    			using (IDbConnection conn = new SqlConnection(ConnString))
    			{
    				if (conn.State == ConnectionState.Closed) conn.Open();
    				return conn.Query<CountriesModel>("SELECT * FROM Countries").ToList();
    			}
    		}
    
    		public static List<ProvincesModel> LoadProvinces()
    		{
    			using (IDbConnection conn = new SqlConnection(ConnString))
    			{
    				if (conn.State == ConnectionState.Closed) conn.Open();
    				return conn.Query<ProvincesModel>("SELECT * FROM Provinces").ToList();
    			}
    		}
    
    		public static List<DistrictsModel> LoadDistricts()
    		{
    			using (IDbConnection conn = new SqlConnection(ConnString))
    			{
    				if (conn.State == ConnectionState.Closed) conn.Open();
    				return conn.Query<DistrictsModel>("SELECT * FROM Districts").ToList();
    			}
    		}
    	}
    
    	public partial class PlacesOfInterest : INotifyPropertyChanged
    	{
    		public int ID { get; set; }
    
    		string _countryName;
    		public string CountryName
    		{
    			get => this._countryName;
    			set { this._countryName = value; ProvinceID = 0; DistrictID = 0; OnPropertyChanged(); }
    		}
    
    		int _provinceID;
    		public int ProvinceID
    		{
    			get => this._provinceID;
    			set { this._provinceID = value; DistrictID = 0; OnPropertyChanged(); }
    		}
    
    		int _districtID;
    		public int DistrictID
    		{
    			get => this._districtID;
    			set { this._districtID = value; OnPropertyChanged(); }
    		}
    
    		public event PropertyChangedEventHandler PropertyChanged;
    		public event EventHandler CanExecuteChanged;
    		private void OnPropertyChanged([CallerMemberName] String propertyName = "")
    				=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    	}
    	public class CountriesModel
    	{
    		public string CountryName { get; set; }
    	}
    	public class ProvincesModel
    	{
    		public string CountryName { get; set; }
    		public int ProvinceID { get; set; }
    		public string ProvinceName { get; set; }
    	}
    	public class DistrictsModel
    	{
    		public int ProvinceID { get; set; }
    		public int DistrictID { get; set; }
    		public string DistrictName { get; set; }
    	}
    
    	// additional partial classes
    	public partial class PlacesOfInterest : INotifyPropertyChanged
    	{
    		public string PlaceName
    		{
    			get { return $"Place {ID}"; }
    			set { }
    		}
    	}
    
    	public class ConvProvenceID : IMultiValueConverter
    	{
    		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    		{
    			int i = (int)values[0];
    			IList<ProvincesModel> l = (IList<ProvincesModel>)values[1];
    			return i > 0 && (l.Count > 0) ? l[i - 1].ProvinceName : string.Empty;
    		}
    		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    	public class ConvDistrictID : IMultiValueConverter
    	{
    		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    		{
    			int i = (int)values[0];
    			IList<DistrictsModel> l = (IList<DistrictsModel>)values[1];
    			return (i > 0 && l.Count > 0) ? l[i - 1].DistrictName : string.Empty;
    		}
    		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    }
    
    

    Result:

    x