How to populate textboxes using datagrid navigation

DPlug 41 Reputation points
2020-12-24T15:35:01.777+00:00

Please I want to populate the textboxes and combo boxes in WPF with data from the datagrid as the user navigates from one row to the other in the datagrid. When the user click on a particular row, the record on the row populated the textboxes and combo boxes. How can I achieved this?

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,676 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,279 questions
0 comments No comments
{count} votes

4 answers

Sort by: Most helpful
  1. Karen Payne MVP 35,191 Reputation points
    2020-12-24T15:49:15.827+00:00

    Hello @DPlug

    Note that the following are not plug in code solution but instead paths to lead you to what you want.

    Following along with the following Microsoft code sample. Then for a start see the following TechNet article and code which does not have a ComboBox nor DataGrid but instead a ListBox, don't get hung up on the ListBox.

    The screenshot below is for the TechNet article, ignore VB.NET as the actual code has one project for C#, one for VB.NET
    51165-a1111.png

    DataGrid

    51283-grid.png

    MainWindow Modified source

    protected override async void OnContentRendered(EventArgs e)  
    {  
        base.OnContentRendered(e);  
      
        if (_hasShown)  
        {  
            return;  
        }  
      
        _hasShown = true;  
      
        var employeeCollection = new ObservableCollection<Employees>();  
      
        //await Task.Run(async () =>  
        //{  
        //    employeeCollection = new ObservableCollection<Employees>(await _context.Employees.ToListAsync());  
        //});  
      
        await Task.Delay(1);  
        employeeCollection = new ObservableCollection<Employees>(EmployeesOperations.List());  
      
      
        EmployeeGrid.ItemsSource = employeeCollection;  
        employeeCollection.CollectionChanged += EmployeeCollection_CollectionChanged;  
        DataContext = employeeCollection;  
      
        /*  
         * Find employee by last name, if found  
         * select and scroll into view in the DataGrid  
         */  
        var employee = (employeeCollection)  
            .FirstOrDefault(emp => emp.LastName == "Russell");  
      
        if (employee == null) return;  
      
        EmployeeGrid.SelectedItem = employee;  
        EmployeeGrid.ScrollIntoView(employee);  
      
        SaveButton.IsEnabled = true;  
      
    }  
    

    Data reader

    Code added, used above. Note extension class DbExtensions should be in it's own file

    using System;  
    using System.Collections.Generic;  
    using System.Data;  
    using System.Globalization;  
    using System.Linq;  
    using System.Text;  
    using System.Threading.Tasks;  
    using Microsoft.Data.SqlClient;  
    using WpfApp1.Models;  
      
    namespace WpfApp1.Classes  
    {  
        public class EmployeesOperations  
        {  
            public static string ConnectionString =  
                "Data Source=.\\SQLEXPRESS;database=HumanResources;Integrated Security=True";  
      
            public static List<Employees> List()  
            {  
                var list = new List<Employees>() ;  
                  
                var selectStatement =  
                    @"  
                SELECT   
                    employee_id, first_name, last_name, email, phone_number, hire_date, job_id, salary, manager_id, department_id   
                FROM   
                    dbo.employees;  
    ";  
      
                using (var cn = new SqlConnection() { ConnectionString = ConnectionString })  
                {  
                    using (var cmd = new SqlCommand() { Connection = cn, CommandText = selectStatement})  
                    {  
                        cn.Open();  
                        var reader = cmd.ExecuteReader();  
                        while (reader.Read())  
                        {  
                             
                            var employee = new Employees()  
                            {  
                                EmployeeId = reader.GetInt32(0),  
                                FirstName = reader.GetString(1),  
                                LastName = reader.GetString(2),  
                                Email = reader.GetString(3),  
                                PhoneNumber = reader.SafeGetString(4),  
                                HireDate = reader.GetDateTime(5),  
                                JobId = reader.GetInt32(6),  
                                Salary = reader.GetDecimal(7),  
                                ManagerId = reader["manager_id"].DbCast<int>(),  
                                DepartmentId = reader.GetInt32(9),  
                                Manager = new Employees(),   
                                InverseManager = new List<Employees>()  
                            };  
      
                            list.Add(employee);  
                        }  
                    }  
                }  
      
                return list;  
            }  
        }  
      
        public static class DbExtensions  
        {  
            public static T? DbCast<T>(this object dbValue) where T : struct  
            {  
                switch (dbValue)  
                {  
                    case null:  
                    case DBNull _:  
                        return null;  
                }  
      
                T? value = dbValue as T?;  
                if (value != null)  
                {  
                    return value;  
                }  
      
                if (dbValue is IConvertible conv)  
                {  
                    value = (T)conv.ToType(typeof(T), CultureInfo.InvariantCulture);  
                }  
                  
                return value;  
            }  
            public static string SafeGetString(this SqlDataReader reader, int colIndex)  
            {  
                if (!reader.IsDBNull(colIndex))  
                {  
                    return reader.GetString(colIndex);  
                }  
      
                return string.Empty;  
            }  
        }  
    }  
    
    0 comments No comments

  2. DaisyTian-1203 11,616 Reputation points
    2020-12-25T02:36:18.487+00:00

    I will give you a demo with MVVM to implement what you want.

    Part 1: Code for MainWindow.xaml

    <Window.Resources>  
            <ObjectDataProvider x:Key="sexEnum" MethodName="GetValues" xmlns:assembly="clr-namespace:System;assembly=mscorlib" ObjectType="{x:Type assembly:Enum}" >  
                <ObjectDataProvider.MethodParameters>  
                    <x:Type Type="local:SexOpt"/>  
                </ObjectDataProvider.MethodParameters>  
            </ObjectDataProvider>  
        </Window.Resources>  
        <Window.DataContext>  
            <local:PersonViewModel></local:PersonViewModel>  
        </Window.DataContext>  
        <WrapPanel>  
            <DataGrid Width="200" Height="200" Name="dataGrid"  HorizontalAlignment="Left" AutoGenerateColumns="False"  SelectionMode="Extended" SelectionUnit="FullRow"   
                      ItemsSource="{Binding LtPersons}"                    
                      SelectedItem="{Binding User}"  
                      >  
                <DataGrid.Columns>  
                    <DataGridTextColumn Header="Name" Width="80" Binding="{Binding Name,Mode=TwoWay}"/>  
                    <DataGridTextColumn Header="Age" Width="50" Binding="{Binding Age,Mode=TwoWay}" />  
                    <DataGridComboBoxColumn Width="80" Header="Sex"   SelectedItemBinding="{Binding Sex}"  ItemsSource="{Binding Source={StaticResource sexEnum}}"/>  
                </DataGrid.Columns>  
            </DataGrid>  
            <StackPanel>  
                <WrapPanel>  
                    <Label Content="Name:" HorizontalAlignment="Right"/>  
                    <TextBox x:Name="txtAddName" Margin="4" Text="{Binding User.Name,Mode=TwoWay}" HorizontalAlignment="Left" Width="150"/>  
                </WrapPanel>  
                <WrapPanel>  
                    <Label Content="Sex:" HorizontalAlignment="Right"/>  
                    <ComboBox  ItemsSource="{Binding LtPersons}" SelectedItem="{Binding User}" DisplayMemberPath="Sex" Width="150" HorizontalAlignment="Left"></ComboBox>  
                </WrapPanel>  
            </StackPanel>  
        </WrapPanel>  
    

    Part 2: Code for MainWindow.xaml.cs

      public enum SexOpt { Male, Female };  
      
        public class PersonModel : NotifyObject  
        {        
            private string name;  
            public string Name  
            {  
                get { return name; }  
                set  
                {  
                    name = value;  
                    OnPropertyChange("Name");  
                }  
            }  
            private int age;  
            public int Age  
            {  
                get { return age; }  
                set  
                {  
                    age = value;  
                    OnPropertyChange("Age");  
                }  
            }  
      
            private SexOpt sex;  
            public SexOpt Sex   
            {  
                get { return sex; }  
                set {  
                    sex = value;  
                    OnPropertyChange("Sex");  
                }  
            }  
        }  
      
      
        class PersonViewModel: NotifyObject  
        {  
            private PersonModel user;  
            public PersonModel User  
            {  
                get { return user; }  
                set  
                {  
                    user = value;  
                    OnPropertyChange("User");  
                }  
            }  
      
            private ObservableCollection<PersonModel> ltPersons = new ObservableCollection<PersonModel>();  
            public ObservableCollection<PersonModel> LtPersons  
            {  
                get { return ltPersons; }  
                set  
                {  
                    this.ltPersons = value;  
                    OnPropertyChange("LtPersons");  
                }  
            }  
      
            public PersonViewModel()  
            {  
                LtPersons = new ObservableCollection<PersonModel>()   
                {   
                    new PersonModel { Name = "John", Age = 11 , Sex = SexOpt.Male},   
                    new PersonModel { Name = "Juli", Age = 12 ,Sex = SexOpt.Female},   
                    new PersonModel { Name = "Brace", Age = 13 ,Sex = SexOpt.Male}   
                };  
            }  
        }  
      
      
        public class NotifyObject : INotifyPropertyChanged  
        {  
            public event PropertyChangedEventHandler PropertyChanged;  
            protected void OnPropertyChange(string propertyName)  
            {  
                if (PropertyChanged != null)  
                {  
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));  
                }  
            }  
        }  
    

    The picture for result:
    51055-capture.png


    If the response is helpful, please click "Accept Answer" and upvote it.
    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.


  3. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-12-25T08:32:07.647+00:00

    Hi,
    try following demo. Al left window side you see the DataGrid with rows for each data object. At rigth side you see the selected row (data object) for editing.

    XAML:

    <Window x:Class="WpfApp1.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
            xmlns:local="clr-namespace:WpfApp1"  
            mc:Ignorable="d"  
            Title="MainWindow" Height="450" Width="800">  
      <Window.Resources>  
        <local:ViewModel x:Key="vm"/>  
      </Window.Resources>  
      <Grid DataContext="{StaticResource vm}">  
        <Grid.ColumnDefinitions>  
          <ColumnDefinition/>  
          <ColumnDefinition/>  
        </Grid.ColumnDefinitions>  
        <DataGrid ItemsSource="{Binding ViewData}"   
                  AutoGenerateColumns="False"   
                  IsReadOnly="True">  
          <DataGrid.Columns>  
            <DataGridTextColumn Header="ID"   
                                Binding="{Binding ID}"/>  
            <DataGridTextColumn Header="Info"   
                                Binding="{Binding Info}"/>  
            <DataGridComboBoxColumn Header="LookUp"  
                                    ItemsSource="{Binding ViewLookUp, Source={StaticResource vm}}"  
                                    DisplayMemberPath="Text"  
                                    SelectedValuePath="ID"  
                                    SelectedValueBinding="{Binding FK}"/>  
          </DataGrid.Columns>  
        </DataGrid>  
        <Grid Grid.Column="1"  
              DataContext="{Binding SelectedObject}">  
          <Grid.ColumnDefinitions>  
            <ColumnDefinition/>  
            <ColumnDefinition/>  
          </Grid.ColumnDefinitions>  
          <Grid.RowDefinitions>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition Height="Auto"/>  
            <RowDefinition/>  
          </Grid.RowDefinitions>  
          <Grid.Resources>  
            <Style TargetType="Label">  
              <Setter Property="HorizontalAlignment" Value="Right"/>  
              <Setter Property="Margin" Value="5"/>  
            </Style>  
            <Style TargetType="TextBox">  
              <Setter Property="Margin" Value="5"/>  
            </Style>  
            <Style TargetType="ComboBox">  
              <Setter Property="Margin" Value="5"/>  
            </Style>  
          </Grid.Resources>  
          <Label Content="Details"/>  
      
          <Label Grid.Row="1" Grid.Column="0" Content="ID"/>  
          <TextBox Grid.Row="1" Grid.Column="1" Text="{Binding ID}" IsReadOnly="True"/>  
      
          <Label Grid.Row="2" Grid.Column="0" Content="Info"/>  
          <TextBox Grid.Row="2" Grid.Column="1" Text="{Binding Info}"/>  
      
          <Label Grid.Row="3" Grid.Column="0" Content="Lookup"/>  
          <ComboBox Grid.Row="3" Grid.Column="1"   
                    ItemsSource="{Binding ViewLookUp, Source={StaticResource vm}}"  
                    DisplayMemberPath="Text"  
                    SelectedValuePath="ID"  
                    SelectedValue="{Binding FK}"/>  
        </Grid>  
      </Grid>  
    </Window>  
    

    And classes:

    using System;  
    using System.Collections.ObjectModel;  
    using System.ComponentModel;  
    using System.Runtime.CompilerServices;  
    using System.Windows.Data;  
      
    namespace WpfApp1  
    {  
      class ViewModel : INotifyPropertyChanged  
      {  
        // ctor to fill demo data  
        public ViewModel()  
        {  
          Random rnd = new Random();  
      
          // Lookup data (display list in ComboBox)  
          ObservableCollection<LookUpData> colLookUp = new ObservableCollection<LookUpData>();  
          for (int i = 1; i < 10; i++) colLookUp.Add(new LookUpData { ID = i, Text = $"Lookup-Text {i}" });  
          cvsLookUp.Source = colLookUp;  
      
          // data objects (DataGrid rows)  
          ObservableCollection<Data> colData = new ObservableCollection<Data>();  
          for (int i = 1; i < 50; i++) colData.Add(new Data { ID = i, Info = $"Row {i}", FK = rnd.Next(1,colLookUp.Count+1) });  
          cvsData.Source = colData;  
      
          cvsData.View.CurrentChanged += (sender, e) => { SelectedObject = cvsData.View.CurrentItem; };  
          cvsData.View.MoveCurrentToPosition(-1);  
          cvsData.View.MoveCurrentToFirst();  
        }  
      
        // DataGrid view  
        private CollectionViewSource cvsData = new CollectionViewSource();  
        public ICollectionView ViewData { get { return cvsData.View; } }  
      
        // ComboBox view  
        private CollectionViewSource cvsLookUp = new CollectionViewSource();  
        public ICollectionView ViewLookUp { get { return cvsLookUp.View; } }  
      
        // for Detail display and edit  
        private object _selectedObject = null;  
        public object SelectedObject  
        {  
          get => this._selectedObject;  
          set { this._selectedObject = value; OnPropertyChanged(); }  
        }  
    
     public event PropertyChangedEventHandler PropertyChanged;  
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));  
      
      }  
      
      // DataGrid data  
      public class Data  
      {  
        public int ID { get; set; }  
        public string Info { get; set; }  
        public int FK { get; set; } // foreign key value  
      }  
      
      // ComboBox list data (lookup data)  
      public class LookUpData  
      {  
        public int ID { get; set; } // Key value  
        public string Text { get; set; } // text to display in DataGrid (ComboBoxColumn)  
      }  
    }  
    

    Result:

    51119-x.gif


  4. Peter Fleischer (former MVP) 19,231 Reputation points
    2020-12-25T20:50:27.997+00:00

    Hi,
    if you want to use ADO.NET to read data from SQL Server you can use this classes instead of my other code.

    Classes:

    using System;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Runtime.CompilerServices;
    using System.Windows.Data;
    
    namespace WpfApp1
    {
      class ViewModel : INotifyPropertyChanged
      {
        // ctor to load demo data
        public ViewModel()
        {
          Model mod = new Model();
    
          // Lookup data (display list in ComboBox)
          cvsLookUp.Source = mod.GetLookUp();
    
          // data objects (DataGrid rows)
          cvsData.Source = mod.GetData();
    
          cvsData.View.CurrentChanged += (sender, e) => { SelectedObject = cvsData.View.CurrentItem; };
          cvsData.View.MoveCurrentToPosition(-1);
          cvsData.View.MoveCurrentToFirst();
        }
    
        // DataGrid view
        private CollectionViewSource cvsData = new CollectionViewSource();
        public ICollectionView ViewData { get { return cvsData.View; } }
    
        // ComboBox view
        private CollectionViewSource cvsLookUp = new CollectionViewSource();
        public ICollectionView ViewLookUp { get { return cvsLookUp.View; } }
    
        // for Detail display and edit
        private object _selectedObject = null;
        public object SelectedObject
        {
          get => this._selectedObject;
          set { this._selectedObject = value; OnPropertyChanged(); }
        }
    
        public event PropertyChangedEventHandler PropertyChanged;
        private void OnPropertyChanged([CallerMemberName] string propName = "") => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
    
      }
    
      internal class Model
      {
        internal DataTable GetLookUp()
        {
          DataTable dt = new DataTable();
          using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [Table2]", WpfApp1.Properties.Settings.Default.cnSQL))
            da.Fill(dt);
          return dt;
        }
        internal DataTable GetData()
        {
          DataTable dt = new DataTable();
          using (SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [Table1]", WpfApp1.Properties.Settings.Default.cnSQL))
            da.Fill(dt);
          return dt;
        }
      }
    }
    

    To create SQL server tables and fill with demo data you can use following method:

    internal void CraeteData()
    {
      using (SqlConnection cn = new SqlConnection(WpfApp1.Properties.Settings.Default.cnSQL))
      {
        cn.Open();
        using (SqlCommand cmd = new SqlCommand { Connection = cn })
        {
          // delete previous table in SQL Server 2016 and above
          cmd.CommandText = "DROP TABLE IF EXISTS Table1;DROP TABLE IF EXISTS Table2;";
          cmd.ExecuteNonQuery();
          // Create Table
          cmd.CommandText = "CREATE Table [Table1]([ID] int Identity, [Info] nvarchar(50), [FK] int, CONSTRAINT [PK_Table1] PRIMARY KEY ([ID]))";
          cmd.ExecuteNonQuery();
          cmd.CommandText = "CREATE Table [Table2]([ID] int Identity, [Text] nvarchar(50), CONSTRAINT [PK_Table2] PRIMARY KEY ([ID]))";
          cmd.ExecuteNonQuery();
    
          // data objects (DataGrid rows)
          Random rnd = new Random();
          cmd.CommandText = "INSERT [Table1](Info, FK) VALUES (@info, @fk);";
          cmd.Parameters.Add("@info", SqlDbType.NVarChar, 50);
          cmd.Parameters.Add("@fk", SqlDbType.Int);
          for (int i = 1; i < 50; i++)
          {
            cmd.Parameters["@info"].Value = $"Row {i}";
            cmd.Parameters["@fk"].Value = rnd.Next(1, 10);
            cmd.ExecuteNonQuery();
          }
    
          // Lookup data (display list in ComboBox)  
          cmd.CommandText = "INSERT [Table2](Text) VALUES (@text);";
          cmd.Parameters.Clear();
          cmd.Parameters.Add("@text", SqlDbType.NVarChar, 50);
          for (int i = 1; i < 10; i++)
          {
            cmd.Parameters["@text"].Value = $"Lookup-Text {i}";
            cmd.ExecuteNonQuery();
          }
        }
      }
    }