I am trying to do something like this:
for (int i = 1; i < nCounter ; i++)
{
string dvName = "dv" + i.ToString();
System.Windows.Forms.DataGridView dvName = new DataGridView();
// other operations will go here..
}
As you can guess, what I am trying to do is at i == 1, create a DataGridView with name dv1, and at i == 2, create a DataGridView with name dv2, but I can't.
Visual studio squiggles saying "a local variable named dvName is already delared in this scope" I also tried the following:
for (int i = 1; i <nCounter ; i++)
{
System.Windows.Forms.DataGridView dv & i = new DataGridView();
// other operations will go here..
}
But VS squiggles again, I hope you understood what I am trying to accomplish. Can anyone suggest how can I do this?
What you really need is a Dictionary<int, DataGridView> grids. Populate it in your for loop (grids[i] = new DataGridView();) and then, later, use the required grid (grids[someCalculatedIndex])
Hope this helps.
try a data structure where you can hold your variables eg dict etc
System.Collections.Generic.Dictionary<string,System.Windows.Forms.DataGridView>
grids = new Dictionary<string,System.Windows.Forms.DataGridView>();
for (int i = 1; i <nCounter ; i++)
{
grids.Add("dv" + i.ToString(), new DataGridView());
}
// to work on grid 1
DataGridView grid1 = grids["dv1"];
// so on
So your are trying to create the variable name dynamically? That's not possible. Why not use an Array or a List (or even a Dictionary)? Or do you want to just set the name of the control?
var list = new List<DataGridView>();
for (int i = 1; i <nCounter ; i++)
{
System.Windows.Forms.DataGridView dvName = new DataGridView();
dvName.Name = "dv" + i.ToString();
list.Add(dvName);
// other operations will go here..
}
foreach (var dv in list)
{
...do something...
}
DataGridView secondDv = list.Single(dv=>dv.Name == "dv2");
secondDv.DoSomething()
Not clear want you want to do...
Related
I have done the following code and works well. I am wondering how I can do a for loop to clean this code from 38 lines into 2 lines.
s0s.Text = seg[0].start.ToString("X8");
s0e.Text = seg[0].end.ToString("X8");
s1s.Text = seg[1].start.ToString("X8");
s1e.Text = seg[1].end.ToString("X8");
// .. many more ..
s19s.Text = seg[19].start.ToString("X8");
s19e.Text = seg[19].end.ToString("X8");
I can obviously do the seg[i] substitution, but how do i do it with the text boxes?
I suppose you could use the Controls property and call OfType<T>() to get all the instances of TextBoxes in your Form instance
Filters the elements of an IEnumerable based on a specified type.
Then convert the results to a Dictionary based on the control Name
// this could potentially be done in the constructor
var dict = Controls.OfType<TextBox>().ToDictionary(x => x.Name);
for (int i = 0; i < 19; i++)
{
dict[$"s{i}s"].Text = $"{seg[i].Start:X8}";
dict[$"s{i}e"].Text = $"{seg[i].End:X8}";
}
Note : This code is untested and only a guide to a possible solution
I'd be tempted to do it this way. First create two lists of your controls, the starts and the ends:
var starts = new List<TextBox>
{
s0s,
s1s,
//...
s19s
};
var ends = new List<TextBox>
{
s0e,
s1e,
//...
s19e
};
Then loop over each list:
var i = 0;
foreach (var start in starts)
{
start.Text = seg[i].start.ToString("X8");
++i;
}
i = 0;
foreach (var end in ends)
{
start.Text = seg[i].end.ToString("X8");
++i;
}
Your indexes and control numbers would need to line up perfectly though.
Note: Like TheGeneral's code, this is untested (neither of us wants to create a form with 38 text boxes with specific names)
Based on the textboxes names I would suggest alternative approach to use control designed to display collection of things - DataGridView would be one of the options.
With data binding you can achieve little bit more maintainable code
public class MyItem
{
public int Start { get; set; }
public int End { get; set; }
}
In the form create a datagridview with two bounded columns, you can do this in winforms designer without manually writing the code below.
// constructor
public MyForm()
{
var startColumn = new DataGridViewTextBoxColumn();
startColumn.DataPropertyName = "Start"; // Name of the property in MyItem class
startColumn.DefaultCellStyle.Format = "X8";
var endColumn = new DataGridViewTextBoxColumn();
endColumn.DataPropertyName = "End"; // Name of the property in MyItem class
endColumn.DefaultCellStyle.Format = "X8";
myDataGridView.Columns.AddRange(startColumn, endColumn);
myDataGridView.AutoGenerateColumns = false;
}
private void Form1_Load(object sender, EventArgs e)
{
var items = new List<MyItem>
{
new MyItem { Start = 10, End = 20 },
new MyItem { Start = 11, End = 19 },
new MyItem { Start = 12, End = 18 }
};
myDataGridView.DataSource = items;
}
firstly when you create they variables insert them all to an array. then run a loop as following:
for (int i; int < 19(your list); i++)
{
your list[i].Text = seg[i].start.ToString("X8");
your list[i].Text = seg[i].end.ToString("X8");
}
How to Clone or Serialize a Windows Forms Control?
When I am trying to Clone windows forms controls using this code "CloneControl(Control ct1)", it allows me to duplicate controls with some Serializable properties, not with all properties.
public Form1()
{
InitializeComponent();
Columns = new DataGridViewTextBoxColumn[2];
for (int i = 0; i < 2; i++)
{
Columns[i] = new System.Windows.Forms.DataGridViewTextBoxColumn();
//
// Columns[i]
//
Columns[i].HeaderText = "j" + (i + 1);
Columns[i].Name = "Column" + (i + 1);
Columns[i].Width = 50;
}
dataGridView1 = new System.Windows.Forms.DataGridView();
dataGridView1.Name = "dataGridView1";
dataGridView1.Location = new System.Drawing.Point(100, 100);
dataGridView1.RowHeadersWidth = 50;
dataGridView1.RowTemplate.Height = 25;
dataGridView1.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView1.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView1.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
dataGridView1.Columns.AddRange(Columns);
dataGridView1.TabIndex = 3;
dataGridView1.AllowUserToAddRows = false;
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
dataGridView1.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView1.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView1.Rows[0].Cells[0].Value = "value1";
Controls.Add(dataGridView1);
Control cloned1 = CloneControl(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
}
public Control CloneControl(Control ct1)
{
Hashtable PropertyList = new Hashtable();
PropertyDescriptorCollection Properties = TypeDescriptor.GetProperties(ct1);
Assembly controlAsm = Assembly.LoadWithPartialName(ct1.GetType().Namespace);
Type controlType = controlAsm.GetType(ct1.GetType().Namespace + "." + ct1.GetType().Name);
Control cloned1 = (Control)Activator.CreateInstance(controlType);
foreach (PropertyDescriptor pr1 in Properties)
{
if (pr1.PropertyType.IsSerializable)
{
PropertyList.Add(pr1.Name, pr1.GetValue(ct1));
}
if (PropertyList.Contains(pr1.Name))
{
try
{
Object obj = PropertyList[pr1.Name];
pr1.SetValue(cloned1, obj);
}
catch (Exception ex)
{
}
}
}
return ct2;
}
If you run the code... the you will get
As you can see in the main method I create a clone of dataGridView1, which has a few properties.
And actually each cell value is null in a cloned dataGridView.
Also size of a columns are not cloned!
You may have a question: if Visual Studio or SharpDeveloper as IDE which is written in C# can handle this problem, then it might be possible to write that kind of code! Right?
In Visual Studio When you are trying drag and drop controls, or copy and paste controls, it not only duplicates that controls with all properties (including Serializable or non-Serializable) but also it changes the name of control itself from "dataGridView1" to "dataGridView2" as well as in SharpDeveloper!
What should I do?
What kind of method should I create?
Maybe another control has a many non-Serializable properties!
How to duplicate all of them?
Please anyone.....
Like #Hans mentioned in the comment, Clone is not that easy. If you want to get some identical controls with only a bit different, you'd better use a function to define general behavior and pass the different properties in as parameters. For example, we define a function with some general properties which apply to DataGridView:
private void InitDataGridView(DataGridView dataGridView, string name)
{
dataGridView.Name = name;
// configure other properties here
dataGridView.Location = new System.Drawing.Point(100, 100);
dataGridView.RowHeadersWidth = 50;
dataGridView.RowTemplate.Height = 25;
dataGridView.Size = new System.Drawing.Size(55 + 50 * 2, 25 + dataGridView1.RowTemplate.Height * 2);
dataGridView.Anchor = System.Windows.Forms.AnchorStyles.None;
dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
// remember to initialize your columns, or pass it in as a parameter
dataGridView.Columns.AddRange(Columns);
dataGridView.AllowUserToAddRows = false;
dataGridView.Rows.Add();
dataGridView.Rows.Add();
dataGridView.Rows[0].HeaderCell.Value = "i" + 1;
dataGridView.Rows[1].HeaderCell.Value = "i" + 2;
dataGridView.Rows[0].Cells[0].Value = "value1";
}
public Form1()
{
InitializeComponent();
var dataGridView1 = new DataGridView();
var dataGridView2 = new DataGridView();
InitDataGridView(dataGridView1, "dataGridView1");
InitDataGridView(dataGridView2, "dataGridView2");
}
IDE (e.g. Visual Studio) is using PropertyDescriptors, DesignerSerializationVisibility and ShouldSerializeValue, but DataGrid Rows are something special, because you cannot add them at design time! IDE cannot copy something that is not there, so, the solution must be different (if you want to clone controls beyond what IDE/Designer can do - see other answers and comments for this). Try my code (everything except grid rows got cloned without the extra check - the columns got cloned).
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
Note: The above can be done better (by check for the class at the end), but is as it is to be obvious.
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
namespace CloneControls {
public partial class Form1: Form {
public Form1() { InitializeComponent(); }
private void Form1_Load(object sender, EventArgs e) {
dataGridView1.Rows.Add();
dataGridView1.Rows.Add();
foreach(Control c in splitContainer1.Panel1.Controls)
splitContainer1.Panel2.Controls.Add((Control)Clone(c));
}
static object Clone(object o) {
return Copy(o, Activator.CreateInstance(o.GetType()));
}
static object Copy(object src, object dst) {
IList list = src as IList;
if(list != null) {
IList to = dst as IList;
foreach(var x in list)
to.Add(Clone(x));
return dst; }
foreach(PropertyDescriptor pd in TypeDescriptor.GetProperties(src)) {
if(!pd.ShouldSerializeValue(src)) {
if(src is DataGridView && pd.Name == "Rows")
CopyDataGridRows((DataGridView)src, (DataGridView)dst);
continue; }
switch(pd.SerializationVisibility) {
default: continue;
case DesignerSerializationVisibility.Visible:
if(pd.IsReadOnly) continue;
pd.SetValue(dst, pd.GetValue(src));
continue;
case DesignerSerializationVisibility.Content:
Copy(pd.GetValue(src), pd.GetValue(dst));
continue;
}
}
return dst;
}
static void CopyDataGridRows(DataGridView src, DataGridView dst) {
foreach(DataGridViewRow row in src.Rows)
if(!row.IsNewRow) dst.Rows.Add((DataGridViewRow)Clone(row));
}
}
}
I think I made more better method here.
This Method at first checks interface of property: if it is ICollection then it does the first job.
After this one loop ends in the method "DeepClone()", then it is necessary to do another loop without checking PropertyType Interface... I mean I could not mix these two operation into one loop?!
Also You can detect that there will be some kind of Run-time Exceptions and for this reason I put this code into try-catch block...
Control cloned1 = (Control)DeepClone(dataGridView1);
cloned1.SetBounds(cloned1.Location.X, cloned1.Location.Y + 300, cloned1.Width, ct1.Height);
Controls.Add(cloned1);
cloned1.Show();
public dynamic DeepClone(dynamic ob1)
{
dynamic ob2 = null;
if (ob1.GetType().IsSerializable && !ob1.GetType().IsArray)
{
if (ob1 != null)
{
using (MemoryStream ms = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(ms, ob1);
ms.Position = 0;
ob2 = formatter.Deserialize(ms);
}
}
}
else
{
if (ob1.GetType().IsArray)
{
var r1 = ob1.Rank;
object[] d1 = new object[r1];
long[] V1 = new long[r1];
for (int i = 0; i < r1; i++)
{
V1[i] = 0;
d1[i] = ob1.GetUpperBound(i) + 1;
}
ob2 = Activator.CreateInstance(ob1.GetType(), d1);
for (long i = 0; i <= ob2.Length; i++)
{
ob2.SetValue(DeepClone(ob1.GetValue(V1)), V1);
for (int j = 0; j <= V1.GetUpperBound(0); j++)
{
if (V1[j] < ob2.GetUpperBound(j))
{
V1[j]++;
break;
}
else
{
V1[j] = 0;
}
}
}
}
else
{
PropertyInfo[] P1 = ob1.GetType().GetProperties();
ob2 = Activator.CreateInstance(ob1.GetType());
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.GetInterface("System.Collections.ICollection", true) != null)
{
dynamic V2 = p1.GetValue(ob1) as IEnumerable;
MethodInfo gm1 = p1.PropertyType.GetMethods().Where(m => m.Name == "Add").Where(p => p.GetParameters().Count() == 1).First(f => V2[0].GetType().IsSubclassOf(f.GetParameters()[0].ParameterType) || f.GetParameters()[0].ParameterType == V2[0].GetType());
if (V2[0].GetType().IsSubclassOf(gm1.GetParameters()[0].ParameterType) || gm1.GetParameters()[0].ParameterType == V2[0].GetType())
{
for (int i = 0; i < V2.Count; i++)
{
dynamic V3 = DeepClone(V2[i]);
gm1.Invoke(p1.GetValue(ob2), new[] {V3});
}
}
}
}
catch (Exception ex)
{
}
}
foreach (PropertyInfo p1 in P1)
{
try
{
if (p1.PropertyType.IsSerializable && p1.CanWrite)
{
var v2 = p1.GetValue(ob1);
p1.SetValue(ob2, v2);
}
if (!p1.PropertyType.IsSerializable && p1.CanWrite)
{
dynamic V2 = p1.GetValue(ob1);
if (p1.PropertyType.GetMethod("Clone") != null)
{
dynamic v1 = V2.Clone();
p1.SetValue(ob2, v1);
}
}
}
catch (Exception ex)
{
}
}
}
}
return ob2;
}
You may say that this Method does not copy some kind of property, But it does copy of main properties and the Cloned control will look like an original control!
Trying to clone a control is overkill except if you really need a totally generic control clone method. Most of the time, you only need to clone a specific control and you have an easy access to the code that created it (see the Form designer generated code, and the setup code you wrote yourself).
But nevertheless, I once used a trick to duplicate many controls at once in order to fill the new tabs of a TabControl, choosing one out of ten tab designs.
I also wanted to use the Form design tool of the C# IDE to edit and modify the 10 template.
So, besides my Tab control form, and using the VS IDE, I created 10 "control factory dummy forms" in my project. I put a dummy Panel control in each of it.
Each time I had to dynamically create a new Tab, I simply instantiated a new dummy window of the desired style. Then I simply moved the Parent pane to my ControlTab (using the Controls.Add() method of the new tab).
This way, you must link the event handlers after the Tab creation (after the controls move). And the event handler's code should be written in you main window class, otherwise you will have "this" reference problems.
Obviously, you will have to store control references somewhere, to be able to access them. The easiest way to do this is to just keep track of each "dummy template Form" you instantiate and to set the "modifier" of your controls to be "public". You can use the Tag property of the destination tab page to store that reference. But, to avoid many casts, it is better to declare an array of each form class, and to store the references there.
I have a form (Windows Forms) with dynamically created textboxes:
TextBox[] tbxCantServ = new TextBox[1];
int i;
for (i = 0; i < tbxCantServ.Length; i++)
{
tbxCantServ[i] = new TextBox();
}
foreach (TextBox tbxActualCant in tbxCantServ)
{
tbxActualCant.Location = new Point(iHorizontal, iVertical);
tbxActualCant.Name = "tbx" + counter++;
tbxActualCant.Visible = true;
tbxActualCant.Width = 44;
tbxActualCant.MaxLength = 4;
this.Controls.Add(tbxActualCant);
}
Now I want to fill them with data, how could I do that?
If I created some textboxes dynamically with the names:
"tbxActualServ.Name = "txt" + counter;"
How can I write in them? How can I access to them?
For example, if I have created tbx1, tbx2 and tbx3, I would have a "for" that fills tbx1.Text with "1", tbx2.Text with "2", and tbx3.Text with "3".
something like
"for from i=0 to counter {
tbx[i] = i
}"
of like:
this.Controls.OfType<TextBox>().Where(r => r.Name == "tbx" + counter).¿¿Write??(r => r.Text = i).ToString();
Thanks!
You could do something like this:
this.Controls.OfType<TextBox>().ToList<TextBox>().ForEach(tb => tb.Text = "bla bla");
Evening,
Guessing from your tags that this is a web forms project.. Im going to have to make some other assumptions.
I am guessing that you are creating your text boxes in code, something like
TextBox tb1 = new TextBox();
form1.Controls.Add(tb1);
TextBox tb2 = new TextBox();
form1.Controls.Add(tb2);
If this is the case then I believe that you could do something like this:
for (int i = 0; i < 2; i++)
{
TextBox tb1 = page.findControl("tb" + i.ToString());
tb1.Text = "This is number " + i.ToString();
}
There is another alternative, you could keep a collection of the controls as you create them, you could then iterate over the collection.
To be honest, without more details about your code it will be difficult to give a full answer, I think that this answers what you are looking for, if not update your question with more details and more of the code (the code where you are dynamically creating the controls would be useful)
While it's possible to access controls by their names (the way you do it depends on the technology - are you using WinForms, WPF, Web Forms, ...?), using an array of controls is a much better solution. Here's some pseudo-C#:
MyControl[] controls = new MyControl[length];
for(int n = 0; n < controls.Length; n++)
{
controls[n] = new MyControl(...);
}
// ...
for(int n = 0; n < controls.Length; n++)
{
DoSomethingWith( controls[n] );
}
private void CreateNewControl()
{
List<Control> list = new List<Control>();
TableLayoutPanel layout = new TableLayoutPanel();
layout.Dock = DockStyle.Fill;
this.Controls.Add(layout);
layout.ColumnCount = 3;
layout.GrowStyle = TableLayoutPanelGrowStyle.AddRows;
for (int i = 0; i < 9; i++)
{
if (wantedType == DevExpress.XtraEditors.CheckEdit)
{
CheckBox chk = new CheckBox();
chk.Tag = i;
layout.Controls.Add(chk);
layout.AutoScroll = true;
}
if (wantedType == LabelControl)
{
Label chk = new Label();
chk.Tag = i;
layout.Controls.Add(chk);
layout.AutoScroll = true;
}
// I want to set the columnwidth of the layout so that when the labels are displayed they do not get clustered and look exactly like when displaying the checkboxes.How do I do it?
In general, what I do is:
Use the IDE in a 'prototype' project, to create a form with the controls in the positions that I want
Look at the source code created by the IDE (in the MyFormName.Designer.cs file) to see what source code is generated by the IDE to creat these controls
Create my own form in my real project, with hand-coded code that's based on what I learned from the prototype which I created using the IDE
// Loop through all the controls you want to add.
// Add a integer field that measures the highest width of each control like
int _iMaxWidth = 0;
for (int i=0; i < TotalControls.Count; ++i)
{
if ( control[i].Width > _iMaxWidth)
_iMaxWidth = control[i].Width
}
// Then you'll know what the width size of the column should be.
Col.Width = iMaxWidth + 2; // +2 to make things a little nicer.
What is the best way to refresh a DataGridView when you update an underlying data source?
I'm updating the datasource frequently and wanted to display the outcome to the user as it happens.
I've got something like this (and it works), but setting the DataGridView.DataSource to null doesn't seem like the right way.
List<ItemState> itemStates = new List<ItemState>();
dataGridView1.DataSource = itemStates;
for (int i = 0; i < 10; i++) {
itemStates.Add(new ItemState { Id = i.ToString() });
dataGridView1.DataSource = null;
dataGridView1.DataSource = itemStates;
System.Threading.Thread.Sleep(500);
}
I ran into this myself. My recommendation: If you have ownership of the datasource, don't use a List. Use a BindingList. The BindingList has events that fire when items are added or changed, and the DataGridView will automatically update itself when these events are fired.
Well, it doesn't get much better than that. Officially, you should use
dataGridView1.DataSource = typeof(List);
dataGridView1.DataSource = itemStates;
It's still a "clear/reset source" kind of solution, but I have yet to find anything else that would reliably refresh the DGV data source.
The cleanest, most efficient and paradigm-friendly solution in this case is to use a System.Windows.Forms.BindingSource as a proxy between your list of items (datasource) and your DataGridView:
var itemStates = new List<ItemState>();
var bindingSource1 = new System.Windows.Forms.BindingSource { DataSource = itemStates };
dataGridView1.DataSource = bindingSource1;
Then, when adding items, use Add() method of BindingSource instead of your list's Add() method:
for (var i = 0; i < 10; i++)
{
bindingSource1.Add(new ItemState { Id = i.ToString() });
System.Threading.Thread.Sleep(500);
}
This way you adding items to your list and notifying DataGridView about those additions with the same line of code. No need to reset DataGridView's DataSource every time you make a change to the list.
It also worth mentioning that you can drop a BindingSource onto your form directly in Visual Studio's Forms Designer and attach it as a data source to your DataGridView there as well, which saves you a line of code in the above example where I'm doing it manually.
Observablecollection :Represents a dynamic data collection that provides notifications
when items get added, removed, or when the whole list is refreshed.
You can enumerate over any collection that implements the IEnumerable interface.
However, to set up dynamic bindings so that insertions or deletions in the
collection update the UI automatically,
the collection must implement the INotifyCollectionChanged interface.
This interface exposes the CollectionChanged event,
an event that should be raised whenever the underlying collection changes.
Observablecollection<ItemState> itemStates = new Observablecollection<ItemState>();
for (int i = 0; i < 10; i++) {
itemStates.Add(new ItemState { Id = i.ToString() });
}
dataGridView1.DataSource = itemStates;
This is copy my answer from THIS place.
Only need to fill datagrid again like this:
this.XXXTableAdapter.Fill(this.DataSet.XXX);
If you use automaticlly connect from dataGridView this code create automaticlly in Form_Load()
You are setting the datasource inside of the loop and sleeping 500 after each add. Why not just add to itemstates and then set your datasource AFTER you have added everything. If you want the thread sleep after that fine. The first block of code here is yours the second block I modified.
for (int i = 0; i < 10; i++) {
itemStates.Add(new ItemState { Id = i.ToString() });
dataGridView1.DataSource = null;
dataGridView1.DataSource = itemStates;
System.Threading.Thread.Sleep(500);
}
Change your Code As follows: this is much faster.
for (int i = 0; i < 10; i++) {
itemStates.Add(new ItemState { Id = i.ToString() });
}
dataGridView1.DataSource = typeof(List);
dataGridView1.DataSource = itemStates;
System.Threading.Thread.Sleep(500);
Just delete all Rows and fill it after deleting:
BindingList<ItemState> itemStates = new BindingList<ItemState>();
datagridview1.Rows.Clear();
for(int i = 0; i < 10; i++)
{
itemStates.Add(new ItemState { id = i.ToString() });
}
datagridview1.DataSource = itemStates;
Thread.Sleep(500);
Try this Code
List itemStates = new List();
for (int i = 0; i < 10; i++)
{
itemStates.Add(new ItemState { Id = i.ToString() });
dataGridView1.DataSource = itemStates;
dataGridView1.DataBind();
System.Threading.Thread.Sleep(500);
}