How to save all the updates in a datagrid (set of comboboxes) MVVM back to the database in WPF C#?

Yvon 50 Reputation points
2024-02-22T18:34:30.8433333+00:00

I have similar issue as @Mesh Ka working on the filtering between comboboxes. https://learn.microsoft.com/en-us/answers/questions/1481853/filtering-a-combobox-in-a-datagrid-based-on-anothe Thanks for the solution! The challenge I have is to save all the changes back to the database when user updates those comboboxes in the datagrid under MVVM. I can create DAL to do the save but need to figure out which row is for update/delete or even an insert on a new row.

.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,386 questions
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,674 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,264 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} votes

Accepted answer
  1. Peter Fleischer (former MVP) 19,231 Reputation points
    2024-03-20T05:46:59.15+00:00

    Hi, you can try my Solution:

    XAML MainWindow:

    <Window x:Class="WpfApp1.Window003"
            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:WpfApp003"
            xmlns:uc="clr-namespace:WpfApp003"
            mc:Ignorable="d"
            Title="Yvon_240305" Height="600" Width="900">
      <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>
        </Grid.Resources>
        <Grid.RowDefinitions>
          <RowDefinition Height="auto"/>
          <RowDefinition Height="200"/>
          <RowDefinition Height="auto"/>
          <RowDefinition Height="200"/>
          <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
          <ColumnDefinition/>
          <ColumnDefinition Width="220"/>
        </Grid.ColumnDefinitions>
        <Label Grid.Row="0" Grid.Column="0" Content="TeacherAddress" Margin="5"/>
        <uc:PlacesDataGrid Grid.Row="1" Grid.Column="0" Margin="5"
                           DataGridItemsSource="{Binding AllTeachers}"/>
        <Button Grid.Row="1" Grid.Column="1" Margin="5" Width="150" HorizontalAlignment="Left"
                Content="AddTeacherAddress" 
                Command="{Binding Cmd}" CommandParameter="AddTeacher"/>
        <Label Grid.Row="2" Grid.Column="0" Content="StudentAddress" Margin="5"/>
        <uc:PlacesDataGrid Grid.Row="3" Grid.Column="0" Margin="5"
                           DataGridItemsSource="{Binding AllStudents}"/>
        <Button Grid.Row="3" Grid.Column="1"  Margin="5" Width="150" HorizontalAlignment="Left"
                Content="AddStudentAddress"
                Command="{Binding Cmd}" CommandParameter="AddStudent"/>
        <StackPanel Grid.Row="4" Grid.ColumnSpan="2" HorizontalAlignment="Right" Orientation="Horizontal" >
          <Button Content="CancelAll" Command="{Binding Cmd}" CommandParameter="CancelAll" Margin="5"/>
          <Button Content="SaveAll" Command="{Binding Cmd}" CommandParameter="SaveAll" Margin="5"/>
        </StackPanel>
      </Grid>
    </Window>
    

    XAML UserControl:

    <UserControl x:Name="userControl"
                 x:Class="WpfApp003.PlacesDataGrid"
                 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:WpfApp003"
                 xmlns:vm="clr-namespace:WpfApp003"
                 mc:Ignorable="d" 
                 d:DesignHeight="450" d:DesignWidth="800">
      <UserControl.Resources>
        <vm:PlacesDataGridViewModel x:Key="viewModel"/>
        <local:ConvProvinceID x:Key="ConvProvenceID"/>
        <local:ConvDistrictID x:Key="ConvDistrictID"/>
        <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:PlacesDataGridViewModel.AttProp="True">
          <DataGrid.Columns>
            <DataGridTemplateColumn Header="Country" Width="120">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <ComboBox
                    ItemsSource="{Binding Countries, Source={StaticResource viewModel}}"
                    DisplayMemberPath="CountryName"
                    SelectedValue="{Binding CountryName, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="CountryName">
                  </ComboBox>
                </DataTemplate>
              </DataGridTemplateColumn.CellTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="Province" Width="130">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Grid>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition />
                      <ColumnDefinition Width="20" />
                    </Grid.ColumnDefinitions>
                    <TextBlock>
                      <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource ConvProvenceID}">
                          <Binding Path="ProvinceID"/>
                          <Binding Path="Provinces" Source="{StaticResource viewModel}"/>
                        </MultiBinding>
                      </TextBlock.Text>
                    </TextBlock>
                    <Grid Grid.Column="1" MouseDown="Path_MouseDown">
                      <Path 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 DataType="ComboBox">
                  <ComboBox
                    DisplayMemberPath="ProvinceName"
                    ItemsSource="{Binding CurrentProvinces, Source={StaticResource viewModel}}"
                    SelectedValue="{Binding ProvinceID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="ProvinceID" />
                </DataTemplate>
              </DataGridTemplateColumn.CellEditingTemplate>
            </DataGridTemplateColumn>
            <DataGridTemplateColumn Header="District" Width="140">
              <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                  <Grid>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition />
                      <ColumnDefinition Width="20" />
                    </Grid.ColumnDefinitions>
                    <TextBlock>
                      <TextBlock.Text>
                        <MultiBinding Converter="{StaticResource ConvDistrictID}">
                          <Binding Path="DistrictID"/>
                          <Binding Path="Districts" Source="{StaticResource viewModel}"/>
                        </MultiBinding>
                      </TextBlock.Text>
                    </TextBlock>
                    <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
                    DisplayMemberPath="DistrictName"
                    ItemsSource="{Binding CurrentDistricts, Source={StaticResource viewModel}}"
                    SelectedValue="{Binding DistrictID, UpdateSourceTrigger=PropertyChanged}"
                    SelectedValuePath="DistrictID" />
                </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.Collections.Generic;
    using System.Data;
    using System.Globalization;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using WpfApp1;
    namespace WpfApp003
    {
    	/// <summary>
    	/// Interaction logic for Window003UC1.xaml
    	/// </summary>
    	public partial class PlacesDataGrid : UserControl
    	{
    		public PlacesDataGrid()
    		{
    			InitializeComponent();
    		}
    		public static readonly DependencyProperty DataGridItemsSourceProperty =
    				DependencyProperty.Register("DataGridItemsSource", typeof(IEnumerable), typeof(PlacesDataGrid), 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);
    		}
    	}
    	public class ConvProvinceID : IMultiValueConverter
    	{
    		public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    		{
    			if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue || values[1] == null) return string.Empty;
    			int i = (int)values[0];
    			IList<DataRow> l = (IList<DataRow>)values[1];
    			return i > 0 && (l.Count > 0) ? ((Window003DS.ProvincesRow)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)
    		{
    			if (values[0] == DependencyProperty.UnsetValue || values[1] == DependencyProperty.UnsetValue || values[1] == null) return string.Empty;
    			int i = (int)values[0];
    			IList<DataRow> l = (IList<DataRow>)values[1];
    			return (i > 0 && l.Count > 0) ? ((Window003DS.DistrictsRow)l[i - 1]).DistrictName : string.Empty;
    		}
    		public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    		{
    			throw new NotImplementedException();
    		}
    	}
    }
    

    Additional classes:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Linq;
    using System.Reflection;
    using System.Runtime.CompilerServices;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Input;
    using System.Windows.Media;
    using WpfApp1;
    namespace WpfApp003
    {
    	public partial class PlacesDataGridViewModel
    	{
    		public PlacesDataGridViewModel() { LoadData(); }
    		private void LoadData()
    		{
    			DAL da = new DAL();
    			this.Countries = new ObservableCollection<DataRow>(da.LoadCountries());
    			this.Provinces = new ObservableCollection<DataRow>(da.LoadProvinces());
    			this.Districts = new ObservableCollection<DataRow>(da.LoadDistricts());
    		}
    		public ObservableCollection<DataRow> Countries { get; set; }
    		public ObservableCollection<DataRow> Provinces { get; set; }
    		public ObservableCollection<DataRow> Districts { get; set; }
    		public object CurrentProvinces => (new DAL()).ProvincesByCountry(SelectedItem?.Row);
    		public object CurrentDistricts => (new DAL()).DistrictsByProvinceID(SelectedItem?.Row);
    		public DataRowView SelectedItem { get; set; }
    		public ICommand CmdDelete { get => new RelayCommand(CmdDeleteExec); }
    		private void CmdDeleteExec(object obj) => (obj as DataRowView).Delete();
    		public static readonly DependencyProperty AttPropProperty = DependencyProperty.Register("AttProp",
    			typeof(bool), typeof(DataGrid), new UIPropertyMetadata(false, OnAttProp));
    		public static bool GetAttProp(DependencyObject obj) => (bool)obj.GetValue(AttPropProperty);
    		public static void SetAttProp(DependencyObject obj, bool value) => obj.SetValue(AttPropProperty, value);
    		private static void OnAttProp(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
    		{
    			var dg = depObj as DataGrid; if (dg == null) return;
    			if ((e.NewValue is bool) && (bool)(e.NewValue)) dg.Loaded += Dg_Loaded;
    		}
    		private static void Dg_Loaded(object sender, RoutedEventArgs e)
    		{
    			DataGrid dg = sender as DataGrid;
    			if (dg == null) return;
    			PlacesDataGridViewModel vm = dg.DataContext as PlacesDataGridViewModel;
    			if (vm == null) return;
    			vm.dg = dg;
    		}
    		DataGrid dg;
    		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 ViewModelMain : INotifyPropertyChanged
    	{
    		public ViewModelMain()
    		{
    			DAL da = new DAL();
    			da.LoadData();
    			cvsTeachers.Source = da.GetTeachers();
    			cvsStudents.Source = da.GetStudents();
    			OnPropertyChanged(nameof(AllTeachers));
    			OnPropertyChanged(nameof(AllStudents));
    		}
    		private CollectionViewSource cvsTeachers = new CollectionViewSource();
    		public ICollectionView AllTeachers { get => cvsTeachers.View; }
    		private CollectionViewSource cvsStudents = new CollectionViewSource();
    		public ICollectionView AllStudents { get => cvsStudents.View; }
    		public ICommand Cmd { get => new RelayCommand(CmdExec); }
    		private void CmdExec(object obj)
    		{
    			switch (obj.ToString())
    			{
    				case "AddTeacher":
    					(new DAL()).AddTeacher();
    					break;
    				case "AddStudent":
    					(new DAL()).AddStudent();
    					break;
    				case "SaveAll":
    					(new DAL()).SaveAll();
    					break;
    				case "CancelAll":
    					(new DAL()).CancelAll();
    					OnPropertyChanged(nameof(AllTeachers));
    					OnPropertyChanged(nameof(AllStudents));
    					break;
    				default:
    					break;
    			}
    		}
    		public event PropertyChangedEventHandler PropertyChanged;
    		private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    	}
    	public class DAL
    	{
    		private string ConnString = WpfApp1.Properties.Settings.Default.cnSQL_CollegDB;
    		private static Window003DS ds;
    		public void LoadData()
    		{
    			ds = new Window003DS();
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Teachers", ConnString)) da.Fill(ds.Teachers);
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Students", ConnString)) da.Fill(ds.Students);
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Countries", ConnString)) da.Fill(ds.Countries);
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Provinces", ConnString)) da.Fill(ds.Provinces);
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Districts", ConnString)) da.Fill(ds.Districts);
    			ds.Teachers.RowChanged += (sender, e) =>
    			{
    				if (e.Action == DataRowAction.Change)
    				{
    					Window003DS.TeachersRow row = e.Row as Window003DS.TeachersRow;
    					if (ProvincesByCountry(row).Where((p) => p.ProvinceID == row.ProvinceID).FirstOrDefault() == null && row.ProvinceID != 0) row.ProvinceID = 0;
    					if (DistrictsByProvinceID(row).Where((p) => p.DistrictID == row.DistrictID).FirstOrDefault() == null && row.DistrictID != 0) row.DistrictID = 0;
    				}
    			};
    			ds.Students.RowChanged += (sender, e) =>
    			{
    				if (e.Action == DataRowAction.Change)
    				{
    					Window003DS.StudentsRow row = e.Row as Window003DS.StudentsRow;
    					if (ProvincesByCountry(row).Where((p) => p.ProvinceID == row.ProvinceID).FirstOrDefault() == null && row.ProvinceID != 0) row.ProvinceID = 0;
    					if (DistrictsByProvinceID(row).Where((p) => p.DistrictID == row.DistrictID).FirstOrDefault() == null && row.DistrictID != 0) row.DistrictID = 0;
    				}
    			};
    		}
    		internal object GetTeachers() => ds.Teachers;
    		internal object GetStudents() => ds.Students;
    		internal void AddTeacher() => ds.Teachers.Rows.Add(ds.Teachers.NewRow());
    		internal void AddStudent() => ds.Students.Rows.Add(ds.Students.NewRow());
    		internal void SaveAll()
    		{
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Teachers", ConnString))
    			{
    				SqlCommandBuilder cb = new SqlCommandBuilder(da);
    				da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    				da.RowUpdated += OnRowUpdated;
    				da.Update(ds.Teachers);
    			}
    			using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM Students", ConnString))
    			{
    				SqlCommandBuilder cb = new SqlCommandBuilder(da);
    				da.MissingSchemaAction = MissingSchemaAction.AddWithKey;
    				da.RowUpdated += OnRowUpdated;
    				da.Update(ds.Students);
    			}
    		}
    		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 IEnumerable<DataRow> LoadCountries() => ds.Countries.AsEnumerable();
    		public IEnumerable<DataRow> LoadProvinces() => ds.Provinces.AsEnumerable();
    		public IEnumerable<DataRow> LoadDistricts() => ds.Districts.AsEnumerable();
    		internal List<Window003DS.ProvincesRow> ProvincesByCountry(DataRow item)
    		{
    			if (item == null) return null;
    			var countryName = item?.GetType().GetProperty("CountryName")?.GetValue(item, null);
    			if (countryName == null) return null;
    			return ds.Provinces.Where((p) => ((Window003DS.ProvincesRow)p).CountryName == countryName.ToString()).ToList();
    		}
    		internal List<Window003DS.DistrictsRow> DistrictsByProvinceID(DataRow item)
    		{
    			var provinceID = item?.GetType().GetProperty("ProvinceID")?.GetValue(item, null);
    			if (provinceID == null) return null;
    			return ds.Districts.Where((p) => ((Window003DS.DistrictsRow)p).ProvinceID == (int)provinceID).ToList().ToList();
    		}
    	}
    	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 WpfApp003
    {
    	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);
    		}
    		public static IEnumerable<T> Query<T>(this IDbConnection con, string sql)
    		{
    			if (con.State == ConnectionState.Closed) con.Open();
    			using (IDbCommand cmd = con.CreateCommand())
    			{
    				cmd.CommandText = sql;
    				IDataReader rdr = cmd.ExecuteReader();
    				while (rdr.Read())
    				{
    					T obj = (T)Activator.CreateInstance(typeof(T));
    					for (int i = 0; i < rdr.FieldCount; i++)
    					{
    						PropertyInfo prop = obj.GetType().GetProperty(rdr.GetName(i), BindingFlags.Public | BindingFlags.Instance);
    						if (null != prop && prop.CanWrite) prop.SetValue(obj, rdr.GetValue(i), null);
    					}
    					yield return obj;
    				}
    			}
    		}
    	}
    }
    

    typed DataSet:

    x

    2 people found this answer helpful.
    0 comments No comments

21 additional answers

Sort by: Most helpful
  1. Yvon 50 Reputation points
    2024-03-26T23:46:40.2966667+00:00

    User's image

    1 person found this answer helpful.
    0 comments No comments

  2. Yvon 50 Reputation points
    2024-03-26T23:48:01.52+00:00

    User's image

    1 person found this answer helpful.
    0 comments No comments

  3. Yvon 50 Reputation points
    2024-03-26T23:49:15.0033333+00:00

    My Window003.xaml.cs

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Threading.Tasks;

    using System.Windows;

    namespace WpfSimple_v2

    {

    /// <summary>
    
    /// Interaction logic for Window003.xaml
    
    /// </summary>
    
    public partial class Window003 : Window
    
    {
    
        public Window003()
    
        {
    
            InitializeComponent();
    
        }
    
    }
    

    }

    1 person found this answer helpful.
    0 comments No comments

  4. Yvon 50 Reputation points
    2024-04-05T22:46:17.8966667+00:00

    Thank you @Peter Fleischer (former MVP) . Thank whole workflow works!

    Now I need to use it as my POC with real situation (due to rewrite and can't change schema).

    Mine has a simple schema for just one of the tab menu.

    I continue use student dataset as guideline. My schema: 2 tables (Moderators and ModeratorType)

    Moderators is table containing data to be manipulated

    insert Moderators values ('1234','Plastic','<30')

    insert Moderators values ('1234','Water','Hot')

    insert Moderators values ('1234','Water','Code')

    insert Moderators values ('4567','Metal','Silver')

    ModeratorType is just a lookup table

    insert ModeratorType values ('Plastic','p','<=50');

    insert ModeratorType values ('Plastic','p','>50');

    insert ModeratorType values ('Plastic','p','=100');

    insert ModeratorType values ('Water','w','Hot');

    insert ModeratorType values ('Water','w','Cold');

    insert ModeratorType values ('Metal','m','Silver');

    insert ModeratorType values ('Metal','m','Gold');

    I create a new UserControl2.xaml and similar to UserControl1.xaml Except the schema different.

    But somehow the datagrid combobox didn't display the initial values

    Tried so many SelectedValue/SelectedValuePath/SelectedItem, and still not displaying initial values

    Plus I want the drop down combobox returns unique instead repeating (eg: Plastic)

    1 person found this answer helpful.