Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
437 views
in Technique[技术] by (71.8m points)

update gridview column values from another form in c# winform?

I have two winforms MainForm and GridForm

in MainForm.cs

executing cmd rmdir command one by one using foreach

Now I want to show list of all directory name and its status name wether it is process or not.

  foreach (var item in listBox1.Items)
  {
     System.Diagnostics.Process.Start("cmd.exe", "/c rmdir " + item);
     // want to show inside gridview in GridForm which folder is done - so uodate status as done

     var p = proc.ExitCode;
     string status;
     if (p == 1){ status = "fail"}
     else {status = "success"}
     // How to pass status text value to GridForm from here? 
     I tried like 
     // grid view bind which will pass items , what about status ?
     GridForm statusForm = new GridForm(listBox1.Items);
     GridForm.ShowDialog();
 }

Problem is I'm unable to pass status value to GridForm

GridForm.cs

   private void GridForm_Load(object sender, EventArgs e)
   {
        DataTable dt = new DataTable();
        dt.Columns.Add("Name");
        foreach (string items in _ItemList)
        {
            DataRow row = dt.NewRow();
            dt.Rows.Add(items);
        }
        this.statusGridView.DataSource = dt;
   }

grid with no status

My question is on MainForm there is a foreach which execute rmdir one by one , now when I click on execute button on MainForm it will execute above foreach code and which will open another form GridForm which shows gridview with two column FolderName and Status I will get all FoolderName from ItemList and Current Status from foreach .

Now how can I bind it to gridview?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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:

set datacolumns in grid


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...