Try following demo:
SQL:
USE [CollegeDB]
GO
/****** Object: Table [dbo].[Moderators] ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Moderators](
[ID] [int] IDENTITY(1,1) NOT NULL,
[PartNumber] nvarchar(20) null,
[Material] nvarchar(20) null,
[Mass] nvarchar(10) null
CONSTRAINT [PK_Moderators] 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].[ModeratorType] *****/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[ModeratorType](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Moderator] nvarchar(20) not null,
[Type] varchar(1) not null,
[Mass] nvarchar(10) not null
CONSTRAINT [PK_ModeratorType] 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
INSERT [dbo].[Moderators] ([PartNumber], [Material], [Mass]) VALUES ('1234','Plastic','<30')
GO
INSERT [dbo].[Moderators] ([PartNumber], [Material], [Mass]) VALUES ('1234','Water','Hot')
GO
INSERT [dbo].[Moderators] ([PartNumber], [Material], [Mass]) VALUES ('1234','Water','Cold')
GO
INSERT [dbo].[Moderators] ([PartNumber], [Material], [Mass]) VALUES ('4567','Metal','Silver')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Plastic','p','<30')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Plastic','p','>50')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Plastic','p','=100')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Water','w','Hot')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Water','w','Cold')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Metal','m','Silver')
GO
INSERT [dbo].[ModeratorType] ([Moderator], [Type], [Mass]) VALUES ('Metal','m','Gold')
GO
MainWindow:
<Window x:Class="WpfApp1.Window004"
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:WpfApp004"
xmlns:uc="clr-namespace:WpfApp004"
mc:Ignorable="d"
Title="Yvon_240406" Height="500" Width="800">
<Window.Resources>
<local:ViewModelMain x:Key="vm"/>
</Window.Resources>
<Grid DataContext="{StaticResource vm}" Margin="10">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="10"/>
<Setter Property="Width" Value="150"/>
<Setter Property="Height" Value="25"/>
<Setter Property="VerticalAlignment" Value="Top"/>
</Style>
<Style TargetType="Label">
<Setter Property="Margin" Value="5"/>
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="100"/>
<RowDefinition Height="auto"/>
<RowDefinition Height="250"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="220"/>
</Grid.ColumnDefinitions>
<uc:UserControl2 Grid.Row="3" Grid.Column="0" Margin="5"
DataGridItemsSource="{Binding AllModerators}"/>
<Button Grid.Row="3" Grid.Column="1" Margin="5" Width="150" HorizontalAlignment="Left"
Content="AddModerator"
Command="{Binding Cmd}" CommandParameter="AddModerator"/>
<StackPanel Grid.Row="4" Grid.ColumnSpan="2" HorizontalAlignment="Right" Orientation="Horizontal" >
<Button Content="CancelAll" Command="{Binding Cmd}" CommandParameter="CancelAll"/>
<Button Content="SaveAll" Command="{Binding Cmd}" CommandParameter="SaveAll"/>
</StackPanel>
</Grid>
</Window>
XAML UserControl:
<UserControl x:Name="userControl"
x:Class="WpfApp004.UserControl2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfApp004"
xmlns:vm="clr-namespace:WpfApp004"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<vm:ModeratorsDataGridViewModel x:Key="viewModel"/>
<Color x:Key="GlyphColor">#FF444444</Color>
</UserControl.Resources>
<Grid x:Name="grid" DataContext="{StaticResource viewModel}">
<DataGrid x:Name="dg"
AutoGenerateColumns="False"
CanUserAddRows="False"
ItemsSource="{Binding DataGridItemsSource, RelativeSource={RelativeSource AncestorType=UserControl}}"
SelectedItem="{Binding SelectedItem}">
<!--local:ModeratorsDataGridViewModel.AttProp="True">-->
<DataGrid.Columns>
<DataGridTextColumn Header="Place" Width="120" Binding="{Binding PartNumber}" />
<DataGridComboBoxColumn Header="Material" Width="130"
SelectedItemBinding="{Binding Material}"
ItemsSource="{Binding AllMaterials, Source={StaticResource viewModel}}"/>
<DataGridTemplateColumn Header="Mass" Width="140">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<TextBlock Text="{Binding Mass}"/>
<Grid Grid.Column="1" MouseDown="Path_MouseDown">
<Path Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="M 0 0 L 4 4 L 8 0 Z" >
<Path.Fill>
<SolidColorBrush Color="{DynamicResource GlyphColor}"/>
</Path.Fill>
</Path>
</Grid>
</Grid>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox
ItemsSource="{Binding CurrentMaterial, Source={StaticResource viewModel}}"
SelectedValue="{Binding Mass, UpdateSourceTrigger=PropertyChanged}"/>
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="Operation">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<Button Content="Delete Record" Margin="2"
Command="{Binding CmdDelete, Source={StaticResource viewModel}}"
CommandParameter="{Binding}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</UserControl>
CodeBehind UserControl:
using System;
using System.Collections;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespace WpfApp004
{
/// <summary>
/// Interaction logic for UserControl2.xaml
/// </summary>
public partial class UserControl2 : UserControl
{
public UserControl2()
{
InitializeComponent();
}
public static readonly DependencyProperty DataGridItemsSourceProperty =
DependencyProperty.Register("DataGridItemsSource", typeof(IEnumerable), typeof(UserControl2), new PropertyMetadata(null));
public IEnumerable DataGridItemsSource
{
get { return (IEnumerable)GetValue(DataGridItemsSourceProperty); }
set { SetValue(DataGridItemsSourceProperty, value); }
}
private void Path_MouseDown(object sender, MouseButtonEventArgs e)
{
HitTestResult hitTestResult = VisualTreeHelper.HitTest(dg, e.GetPosition(dg));
DataGridRow dataGridRow = hitTestResult.VisualHit.GetParentOfType<DataGridRow>();
if (dataGridRow == null) return;
int index = dataGridRow.GetIndex();
var item = dg.Items[index];
if (dg.SelectedItem != item || dg.SelectedItem == null) dg.SelectedItem = item;
DataGridCell dgc = hitTestResult.VisualHit.GetParentOfType<DataGridCell>();
if (dgc == null) return;
dgc.Focus();
dg.BeginEdit();
}
public T GetParentOfType<T>(DependencyObject element) where T : DependencyObject
{
Type type = typeof(T);
if (element == null) return null;
DependencyObject parent = VisualTreeHelper.GetParent(element);
if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) parent = ((FrameworkElement)element).Parent;
if (parent == null) return null;
else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) return parent as T;
return GetParentOfType<T>(parent);
}
}
}
Other Code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using WpfApp1;
namespace WpfApp004
{
public class ViewModelMain : INotifyPropertyChanged
{
public ViewModelMain()
{
DAL da = new DAL();
da.LoadData();
cvsModerators.Source = da.GetModerators();
}
private CollectionViewSource cvsModerators = new CollectionViewSource();
public ICollectionView AllModerators { get => cvsModerators.View; }
public ICommand Cmd { get => new RelayCommand(CmdExec); }
private void CmdExec(object obj)
{
switch (obj.ToString())
{
case "AddModerator":
(new DAL()).AddModerator();
break;
case "SaveAll":
(new DAL()).SaveAll();
break;
case "CancelAll":
(new DAL()).CancelAll();
OnPropertyChanged(nameof(AllModerators));
break;
default:
break;
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
}
public partial class ModeratorsDataGridViewModel
{
public List<String> AllMaterials { get => new DAL().GetMaterials(); }
public DataRowView SelectedItem { get; set; }
public List<String> CurrentMaterial { get => new DAL().GetMassForMaterial(SelectedItem); }
public ICommand CmdDelete { get => new RelayCommand(CmdDeleteExec); }
private void CmdDeleteExec(object obj) => (obj as DataRowView).Delete();
public static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
if (depObj == null) return null;
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
{
var child = VisualTreeHelper.GetChild(depObj, i);
var result = (child as T) ?? GetChildOfType<T>(child);
if (result != null) return result;
}
return null;
}
}
public class DAL
{
private string ConnString = WpfApp1.Properties.Settings.Default.cnSQL_CollegDB;
private static Window004DS ds;
public void LoadData()
{
ds = new Window004DS();
using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Moderators", ConnString)) da.Fill(ds.Moderators);
using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM ModeratorType", ConnString)) da.Fill(ds.ModeratorType);
}
internal IEnumerable<DataRow> GetModerators() => ds.Moderators;
internal List<string> GetMaterials() => new List<string>(ds.ModeratorType.AsEnumerable().Select(row => row.Moderator).Distinct());
internal List<string> GetMassForMaterial(DataRowView item)
{
if (item == null) return new List<string>();
string mat = ((Window004DS.ModeratorsRow)item.Row).Material;
return new List<string>(ds.ModeratorType.AsEnumerable().Where(row => row.Moderator == mat).Select(row => row.Mass).Distinct());
}
internal void AddModerator() => ds.Moderators.Rows.Add(ds.Moderators.NewRow());
internal void SaveAll()
{
using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Moderators", ConnString))
{
SqlCommandBuilder cb = new SqlCommandBuilder(da);
da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
da.RowUpdated += OnRowUpdated;
da.Update(ds.Moderators);
}
}
private void OnRowUpdated(object sender, SqlRowUpdatedEventArgs e)
{
// Include a variable and a command to retrieve the identity value from the Access database.
SqlCommand idCMD = new SqlCommand("SELECT @@IDENTITY", e.Command.Connection);
if (e.StatementType != StatementType.Insert) return;
// Retrieve the identity value and store it in the ID column.
object newID = idCMD.ExecuteScalar();
// ID column
DataColumn primCol = e.Row.Table.PrimaryKey[0];
e.Row[primCol] = Convert.ChangeType(newID, primCol.DataType);
}
internal void CancelAll() => ds.RejectChanges();
}
public class RelayCommand : ICommand
{
private readonly Predicate<object> _canExecute;
private readonly Action<object> _action;
public RelayCommand(Action<object> action) { _action = action; _canExecute = null; }
public RelayCommand(Action<object> action, Predicate<object> canExecute) { _action = action; _canExecute = canExecute; }
public void Execute(object o) => _action(o);
public bool CanExecute(object o) => _canExecute == null ? true : _canExecute(o);
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
}
namespace WpfApp004
{
public static class MyExtensions
{
public static T GetParentOfType<T>(this DependencyObject element) where T : DependencyObject
{
Type type = typeof(T);
if (element == null) return null;
DependencyObject parent = VisualTreeHelper.GetParent(element);
if (parent == null && ((FrameworkElement)element).Parent is DependencyObject) parent = ((FrameworkElement)element).Parent;
if (parent == null) return null;
else if (parent.GetType() == type || parent.GetType().IsSubclassOf(type)) return parent as T;
return GetParentOfType<T>(parent);
}
}
}
Result: