You are getting much closer to getting this to work. The edits are moving in the right direction but lets cover some changes you need to make:
- You created a MainViewModel and set the DataContext of the root grid in your xaml to that ViewModel. That is perfect... exactly what you need to do. Now all the bindings and commands in the xaml will be tied back to that MainViewModel. (and remember that... everything on the view will tie to the ViewModel)
- You added HostViewModel and LogViewModel as public properties on the MainViewModel. You don't actually need these classes. They are adding unnecessary complexity. Rather, you need a HostModel and LogModel that expose the data and methods to get the data... nothing more and nothing less. Here is what the LogModel should look like:
public class LogModel
{
private ObservableCollection<logfilemodel> _logData = new ObservableCollection<logfilemodel>();
public ObservableCollection<logfilemodel> LogData
{
get { return _logData; }
set { _logData = value; OnPropertyChanged("LogData"); }
}
public void GetData(string hostName)
{
try
{
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();
LogData.Clear();
for (int i = 0; i < ndt.Rows.Count; ++i)
LogData.Add(new LogFileModel
{
HostID = Convert.ToInt32(ndt.Rows[i][0]),
LogID = ndt.Rows[i][1].ToString(),
LogPath = ndt.Rows[i][2].ToString(),
Date = Convert.ToDateTime(ndt.Rows[i][3]),
LastAcivity = ndt.Rows[i][4].ToString(),
});
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyname)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyname));
}
}</logfilemodel></logfilemodel></logfilemodel>
Notice that all we are doing is getting the log entries for the selected host (this is important... you MUST filter by the selected host) and putting them into the collection? We clear the collection of records every time we fetch data. This ensures that only the rows we are interested in are exposed via the LogData property. (You could make this more intelligent by screening for only newer records via a last update timestamp or something similar only adding new records then clearing the collection when you see a different selected host identifier.)
With the LogModel looking like this, you make the MainViewModel.SubLogViewModel property of type LogModel. This, in turn, exposes the data as MainViewModel.SubLogModel.LogData.
- Back in your SelectedHosts property setter, you call _subLogModel.GetData(selectedHostIdentifier). This will make your LogModel fetch the log entries for the selected host. The next line should be OnpropertyChanged("SubLogModel"). Yes... you raise that event from the selected host setter after you have fetched the data. That will raise the property changed event on the log data so that the log grid knows the records have changed.
- Finally, and I've said it before, you MUST change 'DataContext="{Binding SubLogViewModel}"' to '
DataSource="{Binding SubLogModel.LogData}"' on your grids. The DataContext specifies a class which implements INotifyPropertyChanged for the grid to bind it's properties and events to. DataSource specifies a class which implements IEnumerable that holds the data to display. Generally, unless there is a really, really good reason to do it, you should not override the DataContext of any control on a page. For grids, assign the data source to the source of the data... not the data context. (Yes... this is confusing terminology).
Last but not least, you have a timer for updating the log data. This should NOT be in the model but should be in the ViewModel. Put the timer in the MainViewModel and start it in the SelectedHost property setter. When it times out, call _subLogModel.LogData.GetData(selectedHostIdentifier) followed by the OnPropertyChanged method just like in the SelectedHost setter. This will make the log data model re-fetch the data and re-populate the data set (updating the display grid) each time the timer fires. If you don't want to toss the entire data set, you would have to add some logic to catch only new records and simply update them into the collection as I mentioned above.
Good luck.
Jason