none
WPF SelectedItem binding between two datagrids

    Question

  • I am developing a User Interface for a host monitoring application, which is already being monitored on database level. I have displayed 2 datagrids on my UI which will populate on run time.These two datagrids are connected by the HostID ( HostID is the Foreign Key in the LogDatagrid).

    The First datagrid displays the list of Host with their Status(either Running or Stopped). I would like to display the Log Status of the respective HostID when a user wants to know the status in detail. How to achieve this when a user selects the Host ID in the HostDatagrid ? I have added my XAML and screenshot of my UI. ( the datagrid data is populated from a Database-kindly have a look in the ViewModel code).May I know how do I the binding between the selected Item in the Host datagrid to the respective details getting displayed in the Log datagrid? Kindly help 
    May I know how I do the binding between selected Item in grid and controls in the detail UI? 

    Xaml Design View :

    here is the Model class for my Log table

    public LogFileModel()
        {
    
        }
        private int _hostID;
        public int HostID
        {
            get { return _hostID; }
            set { _hostID= value; OnpropertyChanged("HostID"); }
        }
    
        private string _logid;
        public string LogID
        {
            get { return _logid; }
            set { _logid= value; OnpropertyChanged("LogID"); }
        }
    
        private string _logpath;
        public string LogPath
        {
            get { return _logPath; }
            set { _logPath = value; OnpropertyChanged("LogPath"); }
        }
    
        private DateTime _date;
        public DateTime Date;
        {
            get { return _date; }
            set { _date= value; OnpropertyChanged("Date"); }
        }
    
        private bool _activity;
        public bool LastActivity
        {
            get { return _activity; }
            set { _activity= value; OnpropertyChanged("LastActivity"); }
        }

    ViewModel for my log table

     LogModel _myModel = new LogModel();
        private ObservableCollection<LogFileModel> _logFileData = new  ObservableCollection<LogFileModel>();
        public ObservableCollection<LogFileModel> LogFileData
        {
            get { return _logFileData; }
            set { _logFileData = value; OnPropertyChanged("LogFileData"); }
        }
       public LogFileViewModel()
        {
            initializeload();
            timer.Tick += new EventHandler(timer_Tick);
            timer.Interval = new TimeSpan(0, 0, 3);
            timer.Start();
        }
    
        ~LogFileViewModel()
        {
            Dispose(false);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    timer.Stop();
                    timer.Tick -= new EventHandler(timer_Tick);
                }
                disposed = true;
            }
        }
    
        private void timer_Tick(object sender, EventArgs e)
        {
            try
            {
                LogFileData.Clear();
                initializeload();
            }
            catch (Exception ex)
            {
                timer.Stop();
                Console.WriteLine(ex.Message);
    
            }
        }
    
        private void initializeload()
        {
            try
            {
                DataTable table = _myModel.getData();
    
                for (int i = 0; i < table.Rows.Count; ++i)
                    LogFileData.Add(new LogFileModel
                    {
                       HostID= Convert.ToInt32(table.Rows[i][0]),
                       LogID = table.Rows[i][1].ToString(),
                       LogPath = table.Rows[i][2].ToString(),
                       Date = Convert.ToDateTime(table.Rows[i][3]),
                       LastAcivity= table.Rows[i][4].ToString(),                   
                    });
            }
    
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
    
        private void OnPropertyChanged(string propertyname)
        {
            var handler = PropertyChanged;
            if (handler != null)
                handler(this, new PropertyChangedEventArgs(propertyname));
        }
    
        public class LogModel
        {
            public DataTable getData()
            {
                DataTable ndt = new DataTable();
                SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
                sqlcon.Open();
                SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [LocalDB].[dbo].[LogFiles]", sqlcon);
                da.Fill(ndt);
                da.Dispose();
                sqlcon.Close();
                return ndt;
            }
        }
    }

    XAML

    <DataGrid DataContext="{Binding Path=HostData,NotifyOnTargetUpdated=True,Mode=OneWay}" 
        AutoGenerateColumns="False" Name="hostDatagrid" Margin="171,32,235,230">
        <DataGrid.Columns>
        <DataGridTextColumn Header="Host" Width="auto" Binding="{Binding HostID}" />
         <DataGridTextColumn Header="Status" Width="auto" Binding="{Binding HostStatus}"/> 
         </DataGrid.Columns>
      </DataGrid>
     <DataGrid DataContext="{Binding Path=LogData,NotifyOnTargetUpdated=True,Mode=OneWay}"
       AutoGenerateColumns="False" Name="LogDatagrid" Margin="103,108,102,145">
        <DataGrid.Columns>
        <DataGridTextColumn Header="Host ID" Width="auto"  Binding="{Binding HostID}" />
        <DataGridTextColumn Header="Logs" Width="auto"  Binding="{Binding LogID}" />
        <DataGridTextColumn Header="Log Path" Width="auto"  Binding="{Binding LogPath}"/>
        <DataGridTextColumn Header="Date" Width="auto"  Binding="{Binding Date}"/>
        <DataGridTextColumn Header="Last Activity" Width="auto"  Binding="{Binding LastActivity}"/>
      </DataGrid.Columns>
    I have followed the same pattern for the Host Model and ViewModel too.

    Kindly help me to proceed further. 

    Thanks indeed




    • Edited by BuBa1947 Wednesday, February 06, 2013 9:24 PM
    Wednesday, February 06, 2013 8:57 PM

Answers

  • This is my ViewModel:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    
    namespace WPFGridViewTemplate
    {
        public class Person : INotifyPropertyChanged
        {
            private string _Title;
    
            private string _FirstName;
    
            private string _LastName;
    
            private string _Description;
    
            public string Title
            {
                get { return _Title; }
                set { _Title = value;
                  RaisePropertyChanged(this, "Title");
                }
            }
            
            public string FirstName
            {
                get { return _FirstName; }
                set { _FirstName = value;
                    RaisePropertyChanged(this, "FirstName");
                }
            }
    
            public string LastName
            {
                get { return _LastName; }
                set { _LastName = value;
                    RaisePropertyChanged(this, "LastName");
                }
            }
    
            public string Description
            {
                get { return _Description; }
                set { _Description = value;
                    RaisePropertyChanged(this, "Description");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void RaisePropertyChanged(object sender, string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    
        //Small workaround to allow defining an ObservableCollection<Person> in XAML
        public class ListOfPersons : ObservableCollection<Person> { }
    }
    And this is my XAML:
    <Window x:Class="WPFGridViewTemplate.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WPFGridViewTemplate"
            Title="MainWindow" Height="350" Width="525">
        
        <Window.Resources>
            <app:ListOfPersons x:Key="LOP">
                <app:Person Title="Darth" FirstName="Anakin" LastName="Skywalker"
                            Description="Went really Drakside"/>
                <app:Person Title="Dr." FirstName="John" LastName="Doolitle"
                            Description="A guy who speak with animals"/>
            </app:ListOfPersons>
        </Window.Resources>
        
        <DockPanel>
            <DataGrid IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource ResourceKey=LOP}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Full Name">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <DockPanel>
                                    <Label Content="{Binding Title}"/>
                                    <Label Content="{Binding FirstName}"/>
                                    <Label Content="{Binding LastName}"/>
                                </DockPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
    
            <DataGrid IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource ResourceKey=LOP}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
                </DataGrid.Columns>
            </DataGrid>
        </DockPanel>
    </Window>
    One Datacontext with one List of Items. Two DataGrids each showing only part of the fields.

    Even if you can#t use it, "IsSynchronizedWithCurrentItem="True"" might help you.
    Thursday, February 07, 2013 12:23 PM
  • Lets assume a ViewModel "MainViewModel"

    public class MainViewModel
        {
            private ObservableCollection<Host> hostValues;
    
            public ObservableCollection<Host> Hosts
            {
                get { return hostValues; }
                set { this.SetProperty<ObservableCollection<Host>>(ref this.hostValues, value);
                }
            }
    
            private ObservableCollection<Log> logsValue;
    
            public ObservableCollection<Log> Logs
            {
                get { return this.LoadLogs(this.SelectedHost.Id); }
            }
    
            private Host selectedHostValue;
    
            public Host SelectedHost
            {
                get { return selectedHostValue; }
                set { this.SetProperty<Host>(ref this.selectedHostValue, value);
                this.RaiseNotification("Logs");
                }
            }
            
        }

    Bind the "Hosts" to grid 1 and "SelectedHost" to the selected item of grid1 and then bind the "Logs" to grid2.
    • Marked as answer by BuBa1947 Thursday, February 14, 2013 1:19 PM
    Thursday, February 07, 2013 10:44 AM
  • The above example works perfect ! Thanks a lot.. i am going to implement the same concept on my program and I am going to get back to u... thank u soo much 

    Beauty is within what you see & feel !

    • Marked as answer by BuBa1947 Thursday, February 07, 2013 3:25 PM
    • Unmarked as answer by BuBa1947 Thursday, February 07, 2013 3:25 PM
    • Marked as answer by BuBa1947 Wednesday, February 20, 2013 1:10 PM
    Thursday, February 07, 2013 3:25 PM
  • Hello Mr. Jebarson, 

    I have tried with your same logic as below ( for Person database ),and it worked perfect for me ! thanks a lot for your response.

    I am posting the solution here, so that it may help someone else who are facing the same issue.

    I am creating two models (Person.cs & PersonDetails.cs) & set their properties, creating a sqlconnection to their respective table in the database and one MainViewModel which is then used for binding with the View (MainWindow.xaml)

    Setting the Sqlconnection string in the app.config file

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <add name="MyConnectionString"  connectionString="Data Source=UserBuBa;Initial Catalog=Person;Persist Security Info=True;User ID=myuserid;Password=myPassword"/>
      </connectionStrings>
    </configuration>
    

    BindableBase.cs - 

     public class BindableBase
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName = null)
            {
                member = value;
                this.RaiseNotification(propertyName);
            }
    
            protected void RaiseNotification(string propertyName)
            {
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }


    Person.cs - Person Model

     public class Person : BindableBase
        {
            private int _PersonID;
            private string _FirstName;
            private string _LastName;
    
            public int PersonID
            {
                get { return _PersonID; }
                set { this.SetProperty<int>(ref this._PersonID, value); }
            }
    
            public string FirstName
            {
                get { return _FirstName; }
                set { this.SetProperty<string>(ref this._FirstName, value); }
            }
    
            public string LastName
            {
                get { return _LastName; }
                set { this.SetProperty<string>(ref this._LastName, value); }
            }
    
            public static ObservableCollection<Person> GetPersons()
            {
                ObservableCollection<Person> persons = new ObservableCollection<Person>();
                try
                {
                    DataTable ndt = new DataTable();
                    SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
                    sqlcon.Open();
                    SqlDataAdapter da = new SqlDataAdapter("select * from [Person].[dbo].[persons]", sqlcon);
                    da.Fill(ndt);
                    da.Dispose();
                    sqlcon.Close();
    
                    persons.Clear();
    
                    for (int i = 0; i < ndt.Rows.Count; ++i)
                        persons.Add(new Person
                        {
                            PersonID = Convert.ToInt32(ndt.Rows[i][0]),
                            FirstName = ndt.Rows[i][1].ToString(),
                            LastName = ndt.Rows[i][2].ToString()
                        });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
    
                }
                return persons;
            }
            
    
        }

    PersonDetails.cs - PersonDetail Model

    public class PersonDetails : BindableBase
        {
            private int _PersonID;
            public int PersonID
            {
                get { return _PersonID; }
                set { this.SetProperty<int>(ref this._PersonID, value); }
            }
    
            private string address;
            public string Address
            {
                get { return address; }
                set { this.SetProperty<string>(ref this.address, value); }
             }
    
            private string _Description;
            public string Description
            {
                get { return _Description; }
                set { this.SetProperty<string>(ref this._Description, value); }
            }
    
            public static ObservableCollection<PersonDetails> GetDetails()
            {
                ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
                try
                {
                    DataTable ndt = new DataTable();
                    SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
                    sqlcon.Open();
                    SqlDataAdapter da = new SqlDataAdapter("select * from [Person].[dbo].[personDetails]", sqlcon);
                    da.Fill(ndt);
                    da.Dispose();
                    sqlcon.Close();
    
                    details.Clear();
    
                    for (int i = 0; i < ndt.Rows.Count; ++i)
                        details.Add(new PersonDetails
                        {
                            PersonID = Convert.ToInt32(ndt.Rows[i][0]),
                            Address = ndt.Rows[i][1].ToString(),
                            Description = ndt.Rows[i][2].ToString()
                        });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return details;
            }
        }
    MainViewModel.cs - The ViewModel class
     public class MainViewModel : BindableBase, INotifyPropertyChanged
        {
            public MainViewModel()
            {
                this.Persons = Person.GetPersons();
            }
    
            private ObservableCollection<Person> personValues;
            public ObservableCollection<Person> Persons
            {
                get { return personValues; }
                set { this.SetProperty<ObservableCollection<Person>>(ref this.personValues, value); }
            }
    
    
            private ObservableCollection<PersonDetails> detailsvalues;
            public ObservableCollection<PersonDetails> Details
            {
                get
                {
                    if (this.Selectedperson == null)
                    {
                        return null;
                    }
                    return this.LoadDetails(this.Selectedperson.PersonID);
                }
    
            }
    
            private ObservableCollection<PersonDetails> LoadDetails(int personID)
            {
                ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
                foreach (PersonDetails detail in PersonDetails.GetDetails().Where(item => item.PersonID == personID))
                {
                    details.Add(detail);
                }
                return details;
            }
    
            private Person selectedPersonValue;
            public Person Selectedperson
            {
                get { return selectedPersonValue; }
                set
                {
                    this.SetProperty<Person>(ref this.selectedPersonValue, value);
                    this.RaiseNotification("Details");
                }
            }
           
        }

    MainWindow.xaml - The View

    <Grid>
     <DataGrid Margin="100,20,116,211" ItemsSource="{Binding Persons}" SelectedItem="{Binding Selectedperson, Mode=TwoWay}"  />
     <DataGrid Margin="100,130,116,101" ItemsSource="{Binding Details}" />
     </Grid>

    Mainwindow.xaml.cs class

    public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new MainViewModel();
            }

    Output :

    I hope it helps others. Thank you Mr.Jebarson




    • Edited by BuBa1947 Wednesday, February 20, 2013 1:09 PM
    • Marked as answer by BuBa1947 Wednesday, February 20, 2013 1:09 PM
    Wednesday, February 20, 2013 1:08 PM

All replies

  • Just make one datacontext that contains the values for both Datagrids. Then disable auto-generation of coloumns and define each datagrid to only show "his" coloumns.

    Expression towards the user should never imply anything about the storage/business logic.

    If you really think you need two seperate DataContexts, you should bind the selected values of the DataContext instead. After all the data context can be manipulated by user (via the Datagrid) and your Code.

    Also of interest might be the OnSelectionChanged Method and the SelectionChanged Event

    Thursday, February 07, 2013 1:11 AM
  • could you please explain with some example ? my concern to have two ViewModels is, each of the datagrid has to select its ItemsSource from its respective Database table.


    Beauty is within what you see & feel !

    Thursday, February 07, 2013 10:26 AM
  • Lets assume a ViewModel "MainViewModel"

    public class MainViewModel
        {
            private ObservableCollection<Host> hostValues;
    
            public ObservableCollection<Host> Hosts
            {
                get { return hostValues; }
                set { this.SetProperty<ObservableCollection<Host>>(ref this.hostValues, value);
                }
            }
    
            private ObservableCollection<Log> logsValue;
    
            public ObservableCollection<Log> Logs
            {
                get { return this.LoadLogs(this.SelectedHost.Id); }
            }
    
            private Host selectedHostValue;
    
            public Host SelectedHost
            {
                get { return selectedHostValue; }
                set { this.SetProperty<Host>(ref this.selectedHostValue, value);
                this.RaiseNotification("Logs");
                }
            }
            
        }

    Bind the "Hosts" to grid 1 and "SelectedHost" to the selected item of grid1 and then bind the "Logs" to grid2.
    • Marked as answer by BuBa1947 Thursday, February 14, 2013 1:19 PM
    Thursday, February 07, 2013 10:44 AM
  • Hello Jebarson, 

    Thanks for your reply. I have understood that you are asking to be have a common ViewModel named as MainViewModel and to put all ObservableCollection<> lists by mapping the

    using UserInterface.HostModels; and using UserInterface.LogModels; but I am getting error in the following : 

    set { this.SetProperty<ObservableCollection<Host>>(ref this.hostValues, value);

    and 

    get { return this.LoadLogs(this.SelectedHost.Id); }
            }

    what should I define in LoadLogs() ??



    Beauty is within what you see & feel !

    Thursday, February 07, 2013 11:22 AM
  • SetProperty is a placeholder method where you will place the logic for setting the property value and raise the event notification.

    The LoadLogs method is again a placeholder for you to load the logs based on the selected host. let me know if you are able to achieve it.

    Thursday, February 07, 2013 11:25 AM
  • actually I am working on WPF since one month and what you have specified is quite new to me.. could you please explain with some example ? that will be really helpful.

    Beauty is within what you see & feel !

    Thursday, February 07, 2013 11:27 AM
  • I have implemented the code below

    public class MainViewModel : INotifyPropertyChanged
        {
            private ObservableCollection<Host> hostValues;
    
            public ObservableCollection<Host> Hosts
            {
                get { return hostValues; }
                set
                {
                    this.SetProperty<ObservableCollection<Host>>(ref this.hostValues, value);
                }
            }
    
            private ObservableCollection<Log> logsValue;
    
            public ObservableCollection<Log> Logs
            {
                get { return this.LoadLogs(this.SelectedHost.Id); }
            }
    
            private Host selectedHostValue;
    
            public Host SelectedHost
            {
                get { return selectedHostValue; }
                set
                {
                    this.SetProperty<Host>(ref this.selectedHostValue, value);
                    this.RaiseNotification("Logs");
                }
            }
    
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            private void SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName)
            {
    
                member = value;
    
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }

    Please write your own logic for LoadLogs. Hope this helps
    Thursday, February 07, 2013 11:33 AM
  • This is my ViewModel:

    using System.Collections.ObjectModel;
    using System.ComponentModel;
    
    namespace WPFGridViewTemplate
    {
        public class Person : INotifyPropertyChanged
        {
            private string _Title;
    
            private string _FirstName;
    
            private string _LastName;
    
            private string _Description;
    
            public string Title
            {
                get { return _Title; }
                set { _Title = value;
                  RaisePropertyChanged(this, "Title");
                }
            }
            
            public string FirstName
            {
                get { return _FirstName; }
                set { _FirstName = value;
                    RaisePropertyChanged(this, "FirstName");
                }
            }
    
            public string LastName
            {
                get { return _LastName; }
                set { _LastName = value;
                    RaisePropertyChanged(this, "LastName");
                }
            }
    
            public string Description
            {
                get { return _Description; }
                set { _Description = value;
                    RaisePropertyChanged(this, "Description");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
    
            public void RaisePropertyChanged(object sender, string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(sender, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    
        //Small workaround to allow defining an ObservableCollection<Person> in XAML
        public class ListOfPersons : ObservableCollection<Person> { }
    }
    And this is my XAML:
    <Window x:Class="WPFGridViewTemplate.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:app="clr-namespace:WPFGridViewTemplate"
            Title="MainWindow" Height="350" Width="525">
        
        <Window.Resources>
            <app:ListOfPersons x:Key="LOP">
                <app:Person Title="Darth" FirstName="Anakin" LastName="Skywalker"
                            Description="Went really Drakside"/>
                <app:Person Title="Dr." FirstName="John" LastName="Doolitle"
                            Description="A guy who speak with animals"/>
            </app:ListOfPersons>
        </Window.Resources>
        
        <DockPanel>
            <DataGrid IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource ResourceKey=LOP}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTemplateColumn Header="Full Name">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <DockPanel>
                                    <Label Content="{Binding Title}"/>
                                    <Label Content="{Binding FirstName}"/>
                                    <Label Content="{Binding LastName}"/>
                                </DockPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
    
            <DataGrid IsSynchronizedWithCurrentItem="True" ItemsSource="{StaticResource ResourceKey=LOP}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Description" Binding="{Binding Description}"/>
                </DataGrid.Columns>
            </DataGrid>
        </DockPanel>
    </Window>
    One Datacontext with one List of Items. Two DataGrids each showing only part of the fields.

    Even if you can#t use it, "IsSynchronizedWithCurrentItem="True"" might help you.
    Thursday, February 07, 2013 12:23 PM
  • Many thanks Christopher.. but this is not my question. I am trying to understand how to set the placeholder method as Jebarson have mentioned

    I need to create a single Viewmodel to existing Viewmodels

    Kindly help


    Beauty is within what you see & feel !

    Thursday, February 07, 2013 2:15 PM
  • What do you think about this Jaberson ? 

      
    public class MainViewModel : ViewModel
     {
    private LogViewModel _SubLogViewModel = new LogViewModel();
    public LogViewModel SubLogViewModel
      {
       get
        {
          return _SubLogViewModel;
        }
        set
       {
          if (_SubLogViewModel != value)
        {
        _SubLogViewModel = value;
        RaisePropertyChanged(() => this.SubLogViewModel);
        }
      }
     }
      
    private HostViewModel _SubHostViewModel = new HostViewModel();
    public HostViewModel SubHostViewModel
    {
     get
      {
       return _SubHostViewModel;
     }
    set
    {
     if (_SubHostViewModel != value)
    {
    _SubHostViewModel = value;
    RaisePropertyChanged(() => this.SubHostViewModel);
    }
    }
    }
         
     
    private Foo _SelectedBar;
    public Foo SelectedBar
    {
        get
     {
       return _SelectedBar;
      }
       set
       {
       if (_SelectedBar != value)
         {
      _SelectedBar = value;
     RaisePropertyChanged(() => this.SelectedBar);
       }
     }      
    
    
      void RaisePropertyChanged(string propertyName)
     { if (PropertyChanged != null) PropertyChanged(this, new   PropertyChangedEventArgs(propertyName)); }
            
     public event PropertyChangedEventHandler PropertyChanged;
    
    protected void OnPropertyChanged(string propertyname)
    {
     var handler = PropertyChanged;
     if (handler != null)
     handler(this, new PropertyChangedEventArgs(propertyname));
       }
      }
     }
    XAML

    <Grid> <Grid.DataContext> <host:MainViewModel /> </Grid.DataContext> <DataGrid Name="hostDataGrid" DataContext="{Binding SubHostModel}" SelectedItem="{Binding SelectedBar, Mode=TwoWay}"> ... </DataGrid> <DataGrid Name="LogDatagrid" DataContext="{Binding SubLogModel}"> </DataGrid> </Grid>

    Kindly check whether this approach is ok ?


    • Edited by BuBa1947 Thursday, February 07, 2013 2:24 PM
    Thursday, February 07, 2013 2:17 PM
  • As far as I understood the Items shown in both datagrids are in a 1:1 relationship. In that case it is an requirement of the view (and only the view) that part of the data has to be shown in a seperate DataGrid.

    So just make a single ViewModel that contains the values for both DataGrids/all UI elements.
    Or don't use two datagrids at all, take one and use it's Feature to show details for the selected row(s):

    http://wpftutorial.net/DataGrid.html#rowDetails

    Or is it not a 1:1 but a 1:N relationship?

    Thursday, February 07, 2013 2:30 PM
  • Let me know if you are still not able to get a working sample. I can provide with one.
    Thursday, February 07, 2013 2:32 PM
  • I have already pasted what I have tried so far.. I am stuck up with the Foo ( placeholder thing) I dont know how to proceed. It will b great if u provide some example.. working with two datagrids. Many thanks indeed



    • Edited by BuBa1947 Thursday, February 07, 2013 2:52 PM
    Thursday, February 07, 2013 2:34 PM
  • OK let me make it clear.. 

    The top datagrid displays the values from database with the HostIDs and status information as 

    when the user wants to see the detailed information of any particular HOSTID, he can select the ID and check the status of the log files in the LOG datagrid . In this above example, Server C is stopped. so when the user selects Server C, the respective log information should be displayed on the Log datagrid like this

    both the tables have HOSTID to map each other in the database. I have written the code in my question. 

    so it is 1:1 relationship ( top level is dependent on the bottom level)

    if it is not clear, pls let me know



    • Edited by BuBa1947 Thursday, February 07, 2013 2:51 PM
    Thursday, February 07, 2013 2:50 PM
  • public class BindableBase
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName = null)
            {
                member = value;
                this.RaiseNotification(propertyName);
            }
    
            protected void RaiseNotification(string propertyName)
            {
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }
    
        public class Host : BindableBase
        {
            private int hostIdValue;
    
            public int HostId
            {
                get { return hostIdValue; }
                set { this.SetProperty<int>(ref this.hostIdValue, value); }
            }
    
            private string nameValue;
    
            public string Name
            {
                get { return nameValue; }
                set { this.SetProperty<string>(ref this.nameValue, value); }
            }
    
            public static ObservableCollection<Host> GetHosts()
            {
                ObservableCollection<Host> hosts = new ObservableCollection<Host>();
                hosts.Add(new Host() { HostId = 1, Name = "Host 1" });
                hosts.Add(new Host() { HostId = 2, Name = "Host 2" });
                hosts.Add(new Host() { HostId = 3, Name = "Host 3" });
                hosts.Add(new Host() { HostId = 4, Name = "Host 4" });
    
                return hosts;
            }
        }
    
        public class Log : BindableBase
        {
            private int hostIdValue;
    
            public int HostId
            {
                get { return hostIdValue; }
                set { this.SetProperty<int>(ref this.hostIdValue, value); }
            }
    
            private string logMessageValue;
    
            public string LogMessage
            {
                get { return logMessageValue; }
                set { this.SetProperty<string>(ref this.logMessageValue, value); }
            }
    
            public static ObservableCollection<Log> GetLogs()
            {
                ObservableCollection<Log> logs = new ObservableCollection<Log>();
                logs.Add(new Log() { HostId = 1, LogMessage = "Log 1 for host 1" });
                logs.Add(new Log() { HostId = 1, LogMessage = "Log 2 for host 1" });
                logs.Add(new Log() { HostId = 2, LogMessage = "Log 1 for host 2" });
                logs.Add(new Log() { HostId = 2, LogMessage = "Log 2 for host 2" });
                logs.Add(new Log() { HostId = 3, LogMessage = "Log 1 for host 3" });
                logs.Add(new Log() { HostId = 3, LogMessage = "Log 2 for host 3" });
    
                return logs;
            }
        }
    
        public class MainViewModel : BindableBase, INotifyPropertyChanged
        {
            public MainViewModel()
            {
                this.Hosts = Host.GetHosts();
            }
    
            private ObservableCollection<Host> hostValues;
    
            public ObservableCollection<Host> Hosts
            {
                get { return hostValues; }
                set
                {
                    this.SetProperty<ObservableCollection<Host>>(ref this.hostValues, value);
                }
            }
    
            private ObservableCollection<Log> logsValue;
    
            public ObservableCollection<Log> Logs
            {
                get
                {
                    if (this.SelectedHost == null)
                    {
                        return null;
                    }
    
                    return this.LoadLogs(this.SelectedHost.HostId);
                }
            }
    
            private ObservableCollection<Log> LoadLogs(int hostId)
            {
                ObservableCollection<Log> logs = new ObservableCollection<Log>();
    
                foreach (Log log in Log.GetLogs().Where(item => item.HostId == hostId))
                {
                    logs.Add(log);
                }
    
                return logs;
            }
    
            private Host selectedHostValue;
    
            public Host SelectedHost
            {
                get { return selectedHostValue; }
                set
                {
                    this.SetProperty<Host>(ref this.selectedHostValue, value);
                    this.RaiseNotification("Logs");
                }
            }
        }

    XAML

        <StackPanel>
            <DataGrid ItemsSource="{Binding Hosts}" SelectedItem="{Binding SelectedHost}"  />
            <DataGrid ItemsSource="{Binding Logs}" />
        </StackPanel>

    Code Behind

     public MainWindow()
            {
                InitializeComponent();
    
                this.DataContext = new MainViewModel();
    
            }

    Above is a working sample. Excuse my coding standards as the code was typed in hurry. Let me know if it resolves your need
    • Marked as answer by BuBa1947 Thursday, February 07, 2013 3:25 PM
    • Unmarked as answer by BuBa1947 Friday, February 08, 2013 2:31 PM
    Thursday, February 07, 2013 2:52 PM
  • The above example works perfect ! Thanks a lot.. i am going to implement the same concept on my program and I am going to get back to u... thank u soo much 

    Beauty is within what you see & feel !

    • Marked as answer by BuBa1947 Thursday, February 07, 2013 3:25 PM
    • Unmarked as answer by BuBa1947 Thursday, February 07, 2013 3:25 PM
    • Marked as answer by BuBa1947 Wednesday, February 20, 2013 1:10 PM
    Thursday, February 07, 2013 3:25 PM
  • Please use appropriate  access qualifiers. You might have marked your class "Log" as internal / private and in this class you are referring it as public. change you log class to public
    Monday, February 11, 2013 11:27 AM
  • Ok I am going to try it now.. but could you please tell that my code structure is in the right pattern ??

    since I am new to the MVVM pattern, I just want to make sure whether the use of Model and ViewModels are structured in the right way..

    many thanks




    • Edited by BuBa1947 Monday, February 11, 2013 12:09 PM
    Monday, February 11, 2013 12:07 PM
  • Please bing for mvvm. there are lot of samples / documentation and KB articles in msdn, channel 9 and other sites.
    Monday, February 11, 2013 12:19 PM
  • how will the LoadLogs look like here in this context ?

    Beauty is within what you see & feel !

    Tuesday, February 12, 2013 10:02 AM
  • Hello Mr. Jebarson, 

    I have tried with your same logic as below ( for Person database ),and it worked perfect for me ! thanks a lot for your response.

    I am posting the solution here, so that it may help someone else who are facing the same issue.

    I am creating two models (Person.cs & PersonDetails.cs) & set their properties, creating a sqlconnection to their respective table in the database and one MainViewModel which is then used for binding with the View (MainWindow.xaml)

    Setting the Sqlconnection string in the app.config file

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <connectionStrings>
        <add name="MyConnectionString"  connectionString="Data Source=UserBuBa;Initial Catalog=Person;Persist Security Info=True;User ID=myuserid;Password=myPassword"/>
      </connectionStrings>
    </configuration>
    

    BindableBase.cs - 

     public class BindableBase
        {
            public event PropertyChangedEventHandler PropertyChanged;
    
            protected void SetProperty<T>(ref T member, T value, [CallerMemberName] string propertyName = null)
            {
                member = value;
                this.RaiseNotification(propertyName);
            }
    
            protected void RaiseNotification(string propertyName)
            {
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
                }
            }
        }


    Person.cs - Person Model

     public class Person : BindableBase
        {
            private int _PersonID;
            private string _FirstName;
            private string _LastName;
    
            public int PersonID
            {
                get { return _PersonID; }
                set { this.SetProperty<int>(ref this._PersonID, value); }
            }
    
            public string FirstName
            {
                get { return _FirstName; }
                set { this.SetProperty<string>(ref this._FirstName, value); }
            }
    
            public string LastName
            {
                get { return _LastName; }
                set { this.SetProperty<string>(ref this._LastName, value); }
            }
    
            public static ObservableCollection<Person> GetPersons()
            {
                ObservableCollection<Person> persons = new ObservableCollection<Person>();
                try
                {
                    DataTable ndt = new DataTable();
                    SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
                    sqlcon.Open();
                    SqlDataAdapter da = new SqlDataAdapter("select * from [Person].[dbo].[persons]", sqlcon);
                    da.Fill(ndt);
                    da.Dispose();
                    sqlcon.Close();
    
                    persons.Clear();
    
                    for (int i = 0; i < ndt.Rows.Count; ++i)
                        persons.Add(new Person
                        {
                            PersonID = Convert.ToInt32(ndt.Rows[i][0]),
                            FirstName = ndt.Rows[i][1].ToString(),
                            LastName = ndt.Rows[i][2].ToString()
                        });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
    
                }
                return persons;
            }
            
    
        }

    PersonDetails.cs - PersonDetail Model

    public class PersonDetails : BindableBase
        {
            private int _PersonID;
            public int PersonID
            {
                get { return _PersonID; }
                set { this.SetProperty<int>(ref this._PersonID, value); }
            }
    
            private string address;
            public string Address
            {
                get { return address; }
                set { this.SetProperty<string>(ref this.address, value); }
             }
    
            private string _Description;
            public string Description
            {
                get { return _Description; }
                set { this.SetProperty<string>(ref this._Description, value); }
            }
    
            public static ObservableCollection<PersonDetails> GetDetails()
            {
                ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
                try
                {
                    DataTable ndt = new DataTable();
                    SqlConnection sqlcon = new SqlConnection(ConfigurationManager.ConnectionStrings["MyConnectionString"].ConnectionString);
                    sqlcon.Open();
                    SqlDataAdapter da = new SqlDataAdapter("select * from [Person].[dbo].[personDetails]", sqlcon);
                    da.Fill(ndt);
                    da.Dispose();
                    sqlcon.Close();
    
                    details.Clear();
    
                    for (int i = 0; i < ndt.Rows.Count; ++i)
                        details.Add(new PersonDetails
                        {
                            PersonID = Convert.ToInt32(ndt.Rows[i][0]),
                            Address = ndt.Rows[i][1].ToString(),
                            Description = ndt.Rows[i][2].ToString()
                        });
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
                return details;
            }
        }
    MainViewModel.cs - The ViewModel class
     public class MainViewModel : BindableBase, INotifyPropertyChanged
        {
            public MainViewModel()
            {
                this.Persons = Person.GetPersons();
            }
    
            private ObservableCollection<Person> personValues;
            public ObservableCollection<Person> Persons
            {
                get { return personValues; }
                set { this.SetProperty<ObservableCollection<Person>>(ref this.personValues, value); }
            }
    
    
            private ObservableCollection<PersonDetails> detailsvalues;
            public ObservableCollection<PersonDetails> Details
            {
                get
                {
                    if (this.Selectedperson == null)
                    {
                        return null;
                    }
                    return this.LoadDetails(this.Selectedperson.PersonID);
                }
    
            }
    
            private ObservableCollection<PersonDetails> LoadDetails(int personID)
            {
                ObservableCollection<PersonDetails> details = new ObservableCollection<PersonDetails>();
                foreach (PersonDetails detail in PersonDetails.GetDetails().Where(item => item.PersonID == personID))
                {
                    details.Add(detail);
                }
                return details;
            }
    
            private Person selectedPersonValue;
            public Person Selectedperson
            {
                get { return selectedPersonValue; }
                set
                {
                    this.SetProperty<Person>(ref this.selectedPersonValue, value);
                    this.RaiseNotification("Details");
                }
            }
           
        }

    MainWindow.xaml - The View

    <Grid>
     <DataGrid Margin="100,20,116,211" ItemsSource="{Binding Persons}" SelectedItem="{Binding Selectedperson, Mode=TwoWay}"  />
     <DataGrid Margin="100,130,116,101" ItemsSource="{Binding Details}" />
     </Grid>

    Mainwindow.xaml.cs class

    public MainWindow()
            {
                InitializeComponent();
                this.DataContext = new MainViewModel();
            }

    Output :

    I hope it helps others. Thank you Mr.Jebarson




    • Edited by BuBa1947 Wednesday, February 20, 2013 1:09 PM
    • Marked as answer by BuBa1947 Wednesday, February 20, 2013 1:09 PM
    Wednesday, February 20, 2013 1:08 PM
  • Hello Mr.Christopher, 

    kindly have a look at the above solution, where I have worked for Sqlconnection. Thanks for your support so far !


    Beauty is within what you see & feel !

    Wednesday, February 20, 2013 1:13 PM