Search code examples
c#wpfxamldatagriddatatemplate

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


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:

   //CountriesModel
   public partial class CountriesModel : ObservableObject
   {
       [ObservableProperty]
       string countryName;
   }

   //ProvincesModel
   public partial class ProvincesModel : ObservableObject
   {
       [ObservableProperty]
       string countryName;

       [ObservableProperty]
       int provinceID;

       [ObservableProperty]
       string provinceName;
   }

   //DistrictsModel
   public partial class DistrictsModel : ObservableObject
   {
       [ObservableProperty]
       int provinceID;

       [ObservableProperty]
       int districtID;

       [ObservableProperty]
       string districtName;
   }

   //PlacesOfInterest
       public partial class PlacesOfInterest : ObservableObject
   {
       [ObservableProperty]
       int iD;

       [ObservableProperty]
       string countryName;

       [ObservableProperty]
       int provinceID;

       [ObservableProperty]
       int districtID;
   }

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

Solution

  • I solved the issue by Using Converters and CellTemplating, Here is what i added and Changed in the Code and Xaml:

    1. Added Converter two Converters: ConvProvinceID:
        public class ConvProvinceID : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                int i = 0;
    
                if (values[0] != DependencyProperty.UnsetValue)
                {
                    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();
            }
        }
    

    ConvDistrictID:

        public class ConvDistrictID : IMultiValueConverter
        {
            public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
            {
                int i = 0;
    
                if (values[0] != DependencyProperty.UnsetValue)
                {
                    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();
            }
        }
    
    1. Changed the Grid in XAML like this:
    //Here I Added the Converters reference to the Windows Resources:
        <Window.Resources>
            <vm:MainWindowViewModel x:Key="vm" />
            <conveters:ConvProvinceID x:Key="ConvProvinceID" />
            <conveters:ConvDistrictID x:Key="ConvDistrictID" />
        </Window.Resources>
    
    
    //... Other parts of the Code as i provided before in the question
    
    
    //I Added the Datacontext for the Grid and connected it to the viewmodel
    <Grid DataContext="{StaticResource vm}">
    
    
    //... Other parts of the Code as i provided before in the question
    <DataGrid
        AutoGenerateColumns="False"
        ItemsSource="{Binding PlacesOfInterest}"
        SelectedItem="{Binding SelectedPlace}"
        ColumnHeaderStyle="{StaticResource MaterialDesignFlatButton}">
        <DataGrid.Columns>
            <DataGridTemplateColumn Header="Country">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <ComboBox
                            Width="120"
                            DisplayMemberPath="CountryName"
                            ItemsSource="{Binding Countries, Source={StaticResource vm}}"
                            SelectedValue="{Binding CountryName, UpdateSourceTrigger=PropertyChanged}"
                            SelectedValuePath="CountryName" />
                    </DataTemplate>
                </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Province">
                <DataGridTemplateColumn.CellTemplate>
                    <DataTemplate>
                        <TextBlock>
                            <TextBlock.Text>
                                <MultiBinding Converter="{StaticResource ConvProvinceID}">
                                    <Binding Path="ProvinceID" />
                                    <Binding Path="Provinces" 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="Districts" 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>
    
    //... Other parts of the Code as i provided before in the question
    
    1. In the MainWindowViewModel i added:
    
            public object CurrentProvinces
            { get => new ObservableCollection<ProvincesModel>(Provinces.Where((p) => p.CountryName == SelectedPlace.CountryName)); }
            public object CurrentDistricts
            { get => new ObservableCollection<DistrictsModel>(Districts.Where((p) => p.ProvinceID == SelectedPlace.ProvinceID)); }
    
            private PlacesOfInterest _selectedPlace;
            public PlacesOfInterest SelectedPlace
            {
                get => this._selectedPlace;
                set { this._selectedPlace = value; }
            }
    
    
    1. And Changed the PlacesOfInterestModel to:
        public partial class PlacesOfInterest : ObservableObject
        {
            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(); }
            }
        }
    

    Solved

    Now with that Solved, another issue on the part of the UI rose;

    1. The province and the District Column don't look like a ComboBox untill the user double clicks in it unlike the Country Column which is how i wanted the ComboBoxes to look like.
    2. The province and the District Column's values Becomes empty when clicked in except the first row. (Look at the gif when i click in the second row)

    I went through the XAML and found that the issue was the CellTemplate has two Controls; One a TextBox to Display the value and the Other one was ComboBox in CellEditingTemplate.

    Now How can i make that ComboBox be on top or display them like the Country Column's ComboBoxes so that my Users can't confuse them with a textbox.