You can use a BindingSource to have the datagrid respond to changes in the instances of a viewmodel. You can update the property of the specific viewmodel and the BindingSource and databinding framework takes care of repainting and updating rows of any grid.
First create a viewmodel class that implements INotifyPropertyChanged. For brevity I only implemented the Status property to raise the property changed event.
class FolderStatusViewModel:INotifyPropertyChanged
{
string _status;
string _folder;
private void Changed(string propertyName)
{
var changed = PropertyChanged;
if (changed != null)
{
changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public string Status
{
get { return _status; }
set
{
_status = value;
Changed("Status");
}
}
public string Folder { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
Make sure to compile your project before continuing to the next step.
On your MainForm drag and drop a BindingSource
from the Toolbox data category. I named mine folders
. Set the DataSource
property to a new project datasource and select FolderStatusViewModel
as the type.
Set the DataSource
of your datagrid to the folders
bindingsource.
In your main form load event create a collection (I prefer a List) with an instance of FolderStatusViewModel
for each folder
private void MainForm_Load(object sender, EventArgs e)
{
var folders = new List<FolderStatusViewModel>();
foreach (var folder in Directory.EnumerateDirectories(@"c:emp"))
{
folders.Add(new FolderStatusViewModel {
Folder = folder
});
}
this.folders.DataSource = folders;
}
On your GridFrom add a DataGrid and BindingSource (I named this one folders again). Set the BindingSource to the same project datasource FolderStatusViewModel
and hookup the datagrid with the binding source.
The overloaded constructor of GridForm should take an object which we assign to the BindingSource in the Load event:
public partial class GridForm : Form
{
public GridForm()
{
InitializeComponent();
}
object source = null;
public GridForm(object dataSource):this()
{
this.source = dataSource;
}
private void GridForm_Load(object sender, EventArgs e)
{
this.folders.DataSource = source;
}
}
When you instantiate the GridForm you can simply pass the value of DataSource property of the BindingSource on the mainform to the constructor of the GridForm:
// the grid form takes the DataSource from the folders BindingSource
var grid = new GridForm(this.folders.DataSource);
grid.Show();
// process each folder, making sure to get an instance of the
// instances of the ViewModel, in this case by casting
// the DataSource object back to the List
foreach(var folderStatus in (List<FolderStatusViewModel>) this.folders.DataSource)
{
var pi = new ProcessStartInfo();
pi.FileName ="cmd.exe";
pi.Arguments ="/c dir /s *.*";
pi.CreateNoWindow = true;
var p = new Process();
p.EnableRaisingEvents = true;
p.Exited += (s,ee) => {
// here the instance of a FolderStatusViewModel
// gets its Status property updated
// all subscribers to the PropertyChanged event
// get notified. BindingSource instances do subscribe to these
// events, so that is why the magic happens.
if (p.ExitCode > 0)
{
folderStatus.Status = String.Format("fail {0}", p.ExitCode);
}
else
{
folderStatus.Status = "succes";
}
};
p.StartInfo = pi;
p.Start();
}
By leveraging the BindingSource multiple froms that are databound to any of these instances will get updates simultaneously. The databinding framewoek will do the heavy lifting for you.
If you don't want to use a self created ViewModel but an existing DataTable adapt above code as follows:
The form_load event:
private void MainForm_Load(object sender, EventArgs e)
{
var folders = new DataTable();
folders.Columns.Add("Status");
folders.Columns.Add("Folder");
foreach (var folder in Directory.EnumerateDirectories(@"c:emp"))
{
var row = folders.NewRow();
folders.Rows.Add(row);
row["Folder"] = folder;
}
this.folders.DataSource = folders;
}
The processing:
// other code omitted
foreach(DataRow folderStatus in ((DataTable) this.folders.DataSource).Rows)
{
// other code omitted
p.Exited += (s,ee) => {
if (p.ExitCode > 0)
{
folderStatus["Status"] = String.Format("fail {0}", p.ExitCode);
}
else
{
folderStatus["Status"] = "succes";
}
};
// other code omitted
}
As the DataGrid has now no way to know which columns will exist you have to explicitly add those to each datagrid AND set the DataPropertyName of each Column: