locked
populate wpf textbox from listbox selected item - MVVM RRS feed

  • Question

  • Hello,
    I am working on WPF MVVM...
    The window has a listbox which is populated with FullNames of students
    The bit I need help on is when you click on a name in the listbox then the textboxes to be populated with FirstName in textbox1 and textbox2 with Address1 fields

    This is what I am doing so far but DetailData does not seem to be populating...

    //frmDetailsTest
    
    <Window x:Class="Rustam.frmDetailsTest"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="frmDetailsTest" Height="501.6" Width="455.686"
            xmlns:scr="clr-namespace:Rustam"
            Loaded="Window_Loaded">
    
        <Window.Resources>
            <scr:clsStudentViewModel x:Key="StudentViewModel"/>
        </Window.Resources>
        <Grid Margin="0,0,5.2,-0.2"
              DataContext="{Binding Source={StaticResource StudentViewModel}}">
            <StackPanel Orientation="Vertical">
                <ListBox Name="lstNames" 
                     ItemsSource="{Binding Path=DataCollection}"
                     SelectedValuePath="StudentID"
                     DisplayMemberPath="FullName"
                     HorizontalAlignment="Left" Height="253" Margin="10,10,0,0" VerticalAlignment="Top" Width="236" SelectionChanged="lstNames_SelectionChanged" Grid.ColumnSpan="7"
                     >
                </ListBox>
                <Grid Grid.Row="2"
                      Margin="5,5,4.6,5"
                      x:Name="grdDetail"
                       Height="166"
                      DataContext="{Binding Path=DetailData}"
                      >
                    <Grid.RowDefinitions>
                        <RowDefinition Height="Auto" />
                        <RowDefinition Height="Auto" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="120"></ColumnDefinition>
                        <ColumnDefinition Width="*"></ColumnDefinition>
                    </Grid.ColumnDefinitions>
                    <TextBox 
                        Text="{Binding Path=Address1, Mode=TwoWay}"
                        Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,9.2,0,-30.6" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
                    <TextBox 
                        Text="{Binding Path=FirstName, Mode=TwoWay}"
                        Grid.Column="1" HorizontalAlignment="Left" Height="23" Margin="10,37.2,0,-57" Grid.Row="1" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
                </Grid>
            </StackPanel>
    
        </Grid>
    </Window>
    
    using System.Data;
    using System.Data.SqlClient;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    using DataAccess;
    
    namespace Rustam
    {
        public class clsStudentViewModel : INotifyPropertyChanged
        {
            clsStudentAccess _DataManager = new clsStudentAccess();
    
            #region Constructor - Initialize Product Data Collection
            public clsStudentViewModel()
            {
                DataCollection = _DataManager.GetStudentNamesCol();
            }
            #endregion
            
            #region INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
            protected void RaisePropertyChanged(string propertyName)
            {
                PropertyChangedEventHandler handler = this.PropertyChanged;
                if (handler != null)
                {
                    PropertyChangedEventArgs args = new PropertyChangedEventArgs(propertyName);
    
                    // Raise the PropertyChanged event.
                    handler(this, args);
                }
            }
            #endregion
    
            #region DataCollection Property
            private ObservableCollection<clsStudentDetails> _DataCollection;
    
            public ObservableCollection<clsStudentDetails> DataCollection
            {
                get { return _DataCollection; }
                set
                {
                    _DataCollection = value;
                    RaisePropertyChanged("DataCollection");
                }
            }
            #endregion
    
            #region DetailData Property
            private clsStudentDetails mDetailData;
    
            public clsStudentDetails DetailData
            {
                get { return mDetailData; }
                set
                {
                    mDetailData = value;
                    RaisePropertyChanged("DetailData");
                }
            }
            #endregion
    }
    
    -----------------------------------------------------------------------
    -----------------------------------------------------------------------
    --------------------------------------------------------------------
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Data;
    using System.Data.Common;
    using System.ComponentModel;
    using System.Collections.ObjectModel;
    
    namespace DataAccess
    {
        public class clsStudentAccess 
        {   
            public ObservableCollection<clsStudentDetails> GetStudentNamesCol()
            {
                ObservableCollection<clsStudentDetails> ret = new ObservableCollection<clsStudentDetails>();
    
                // get a configured DbCommand object
                DbCommand comm = clsGenericDataAccess.CreateCommand();
                // set the stored procedure name
                comm.CommandText = "uspGetAllStudentNames";
                // execute the stored procedure and return the results
                DataTable table = new DataTable();
                table = clsGenericDataAccess.ExecuteSelectCommand(comm);
    
                if (table.Rows.Count > 0)
                {
                    foreach (DataRow dr in table.Rows)
                    {
                        clsStudentDetails student = new clsStudentDetails();
    
                        student.StudentID = int.Parse(dr["StudentID"].ToString());
                        student.FullName = dr["FullName"].ToString();
    
                        ret.Add(student);
                    }
                }                      
    
                return ret;
            }
    
    
    public clsStudentDetails GetStudentDetailsUniqueMVVM(int intStudentID)
            {
                DbCommand comm = clsGenericDataAccess.CreateCommand();
                comm.CommandText = "uspGetStudentDetailsUnique";
    
                DbParameter param = comm.CreateParameter();
                if (intStudentID > 0)
                {
                    param.ParameterName = "@StudentID";
                    param.Value = intStudentID;
                    param.DbType = DbType.Int32;
                    comm.Parameters.Add(param);
                }
    
                DataTable table = new DataTable();
                table = clsGenericDataAccess.ExecuteSelectCommand(comm);
                clsStudentDetails details = new clsStudentDetails();
                if (table.Rows.Count > 0)
                {
                    details.FirstName = table.Rows[0]["FirstName"].ToString();
                    details.Address1 = table.Rows[0]["Address1"].ToString();
                }
    
                return details;
            }
    --------------------------------------------------------------------
    --------------------------------------------------------------------
    --------------------------------------------------------------------
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ComponentModel;
    
    namespace DataAccess
    {
        public class clsStudentDetails : INotifyPropertyChanged
        {
    
            #region INotifyPropertyChanged
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void RaisePropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
            #endregion
    
            private int _StudentID;
            public int StudentID
            {
                get { return _StudentID; }
                set
                {
                    if (_StudentID != value)
                    {
                        _StudentID = value;
                        RaisePropertyChanged("StudentID");
                    }
                }
            }
    
            private string _FullName;
            public string FullName
            {
                get { return _FullName; }
                set
                {
                    if (_FullName != value)
                    {
                        _FullName = value;
                        RaisePropertyChanged("FullName");
                    }
                }
            }
    
            private string _FirstName;
            public string FirstName
            {
                get { return _FirstName; }
                set
                {
                    if (_FirstName != value)
                    {
                        _FullName = value;
                        RaisePropertyChanged("FirstName");
                    }
                }
            }
    
            private string _Address1;
            public string Address1
            {
                get { return _Address1; }
                set
                {
                    if (_Address1 != value)
                    {
                        _Address1 = value;
                        RaisePropertyChanged("Address1");
                    }
                }
            }
        }
    }
    


    Wednesday, September 2, 2015 4:15 PM

Answers

  • Hi arkiboys,

    you need to set the DetailData-property of your ViewModel when an item in the ListBox is selected. To do this, bind the SelectedItem-Property of the ListBox to the DetailData-property of your ViewModel:

     <ListBox Name="lstNames" 
                     ItemsSource="{Binding Path=DataCollection}"
                     SelectedItem="{Binding Path=DetailData,Mode=TwoWay}"

    Now you see the Address shows up correctly, but not so the FirstName. The FirstName does not show up because you've a typo in the property. When you look at your code, you see that you set the _FullName-field inside of the setter instead of the _FirstName-field. So change this like here:

      public string FirstName
        {
          get { return _FirstName; }
          set
          {
            if (_FirstName != value)
            {
              _FirstName = value;
              // _FullName = value;
              RaisePropertyChanged("FirstName");
            }
          }
        }

    Now it works like a charm. ;-)


    Thomas Claudius Huber

    "If you can't make your app run faster, make it at least look & feel extremly fast"

    My latest Pluralsight-courses:
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth

    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com

    • Proposed as answer by Andy ONeill Thursday, September 3, 2015 8:54 AM
    • Marked as answer by Xavier Xie-MSFT Wednesday, September 16, 2015 9:21 AM
    Wednesday, September 2, 2015 5:32 PM

All replies

  • Hi arkiboys,

    you need to set the DetailData-property of your ViewModel when an item in the ListBox is selected. To do this, bind the SelectedItem-Property of the ListBox to the DetailData-property of your ViewModel:

     <ListBox Name="lstNames" 
                     ItemsSource="{Binding Path=DataCollection}"
                     SelectedItem="{Binding Path=DetailData,Mode=TwoWay}"

    Now you see the Address shows up correctly, but not so the FirstName. The FirstName does not show up because you've a typo in the property. When you look at your code, you see that you set the _FullName-field inside of the setter instead of the _FirstName-field. So change this like here:

      public string FirstName
        {
          get { return _FirstName; }
          set
          {
            if (_FirstName != value)
            {
              _FirstName = value;
              // _FullName = value;
              RaisePropertyChanged("FirstName");
            }
          }
        }

    Now it works like a charm. ;-)


    Thomas Claudius Huber

    "If you can't make your app run faster, make it at least look & feel extremly fast"

    My latest Pluralsight-courses:
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth

    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com

    • Proposed as answer by Andy ONeill Thursday, September 3, 2015 8:54 AM
    • Marked as answer by Xavier Xie-MSFT Wednesday, September 16, 2015 9:21 AM
    Wednesday, September 2, 2015 5:32 PM
  • Hi arkiboys,

    you need to set the DetailData-property of your ViewModel when an item in the ListBox is selected. To do this, bind the SelectedItem-Property of the ListBox to the DetailData-property of your ViewModel:

     <ListBox Name="lstNames" 
                     ItemsSource="{Binding Path=DataCollection}"
                     SelectedItem="{Binding Path=DetailData,Mode=TwoWay}"

    Now you see the Address shows up correctly, but not so the FirstName. The FirstName does not show up because you've a typo in the property. When you look at your code, you see that you set the _FullName-field inside of the setter instead of the _FirstName-field. So change this like here:

      public string FirstName
        {
          get { return _FirstName; }
          set
          {
            if (_FirstName != value)
            {
              _FirstName = value;
              // _FullName = value;
              RaisePropertyChanged("FirstName");
            }
          }
        }

    Now it works like a charm. ;-)


    Thomas Claudius Huber

    "If you can't make your app run faster, make it at least look & feel extremly fast"

    My latest Pluralsight-courses:
    XAML Layout in Depth
    Windows Store Apps - Data Binding in Depth

    twitter: @thomasclaudiush
    homepage: www.thomasclaudiushuber.com

    Still I do not get my textboxes populated after I select a name from the listbox.
    I think somewhere I need to call the database by passing the selected StudentID and get the FirstName and Address1 of that StudentID

    ?

    Thanks

    Wednesday, September 2, 2015 8:55 PM
  • Think about it.

    How was Thomas ( or anyone ) supposed to know you hadn't got the address from the database?

    Anyone trying to answer your questions only knows what you tell us.


    Thursday, September 3, 2015 8:59 AM