Search code examples
wpfxamlmvvmwpf-controlswpfdatagrid

One ViewModel per View?


I am developing a UI application which displays 3 datagrids, each of them are dependent on each other(selectedItem binding)

This is what I have done so far:

datagrid1 has one Model and one ViewModel,

datagrid2 has one Model and one ViewModel,

datagrid3 has one Model and one ViewModel.

and all three ViewModels are mapped to the View using DataContext in each <Datagrid.DataContext> property. The reason for setting ViewModel for each model is, The datagrid has to select the items from their respective tables from the database.

But now I am facing a difficulty when I try to set the SelectedItem in each datagrid. I am pasting a sample code for one datagrid. Like this I have created viewmodel for other two datagrid's also.

XAML

<DataGrid DataContext="{Binding Path=HostData,NotifyOnTargetUpdated=True,Mode=OneWay}" 
AutoGenerateColumns="False" Name="hostDatagrid" Margin="171,32,235,230">
<Datagrid.DataContext>
<host:HostViewModel>
</Datagrid.DataContext>
<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.DataContext>
<host:LogViewModel>
</Datagrid.DataContext>
 <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}"/>

c#- Model

 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

  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();
      //for this select statement only I have created separate ViewModel for the respective Model
         SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM [LocalDB].[dbo].[LogFiles]", sqlcon);
         da.Fill(ndt);
         da.Dispose();
         sqlcon.Close();
         return ndt;
     }
 } 
}

Is there any other way to overcome this issue and to have one ViewModel for one View, with their respective datagrid - select statements?


Solution

  • You are always free to split your view in different sub-views (like user controls). The same thing you can do with the ViewModels too.

    You can create one ViewModel which represents the whole view knowing the three sub viewmodels...

    public class MainViewModel : ViewModel
    {
        private LogViewModel _SubLogViewModel = new LogViewModel();
        public LogViewModel SubLogViewModel
        {
            get
            {
                return _SubLogViewModel;
            }
            set
            {
                if (_SubLogViewModel != value)
                {
                    _SubLogViewModel = value;
                    OnpropertyChanged("SubLogViewModel");
                }
            }
        }
    
        private HostViewModel _SubHostViewModel = new HostViewModel();
        public HostViewModel SubHostViewModel
        {
            get
            {
                return _SubHostViewModel;
            }
            set
            {
                if (_SubHostViewModel != value)
                {
                    _SubHostViewModel = value;
                    OnpropertyChanged("SubHostViewModel");
                }
            }
        }
    
        private Host _SelectedHost;
        public Host SelectedHost
        {
            get
            {
                return _SelectedHost;
            }
            set
            {
                if (_SelectedHost!= value)
                {
                    _SelectedHost= value;
                    OnpropertyChanged("SelectedHost");
                    if(this.SelectedHost != null && this.SubLogViewModel != null)
                    {
                        this.SubLogViewModel.LoadLogFor(this.SelectedHost);
                    }
                }
            }
        }
    }
    

    and the XAML something like:

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