I'm trying to bind list to gridview. Situation is like this: I take data from .txt file, later I put it inside first list List<Mycolumns>. I have data in list (with 3 separated columns) that I created. I am taking data from one of the columns called System_Description. Now I would like to show this data in gridview, but only thing that I get is length of each row. How should I fix it? Here is my code.
private void button7_Click(object sender, EventArgs e)
{
List<MyColumns> list = new List<MyColumns>();
OpenFileDialog openFile1 = new OpenFileDialog();
openFile1.Multiselect = true;
if (openFile1.ShowDialog() != DialogResult.Cancel)
{
foreach (string filename in openFile1.FileNames)
{
using (StreamReader sr = new StreamReader(filename))
{
string line;
while ((line = sr.ReadLine()) != null)
{
string[] _columns = line.Split(",".ToCharArray());
MyColumns mc = new MyColumns();
mc.Time = _columns[0];
mc.System_Description = _columns[1];
mc.User_Description = _columns[2];
list.Add(mc);
}
}
}
DataTable ListAsDataTable = BuildDataTable<MyColumns>(list);
DataView ListAsDataView = ListAsDataTable.DefaultView;
this.dataGridView1.DataSource = view = ListAsDataView;
this.dataGridView1.AllowUserToAddRows = false;
dataGridView1.ClearSelection();
}
List<string> description = list.Select(x => x.System_Description).ToList<string>();
this.dataGridView2.DataSource = description;
}
class MyColumns
{
public string Time { get; set; }
public string System_Description { get; set; }
public string User_Description { get; set; }
}
EDIT:
I've read that DataBind() works for Web form, my app is desktop app. What should I do now?
I managed to solve this problem. I did it this way, maybe it will help someone. You can use DataTable and then bind DT to gridview.
DataTable dt = new DataTable();
dt.Columns.Add("values");
foreach(string items in description)
{
DataRow row = dt.NewRow();
dt.Rows.Add(items);
}
this.dataGridView2.DataSource = dt;
this.dataGridView1.DataSource = new BindingSource(list);
You are only selecting the System_Description field using the following statement:
List<string> description = list.Select(x => x.System_Description).ToList<string>();
Then you are binding this list to the gridview:
this.dataGridView2.DataSource = description;
If you want to bind the whole data to the gridview; just bind the list as a datasource.
this.dataGridView2.DataSource = list;
this.dataGridView2.DataBind();
Use this
this.dataGridView1.DataSource = description;
and add Bound field in gridview on aspx.
<asp:BoundField DataField="System_Description" HeaderText="System_Description"></asp:BoundField>
Related
I have a simple csv reader that I wrote, it receives data in the format List<string[]> . I need to show this data in wpf and edit it. I use mvvm. If I write just like that, it won't do anything.
<DataGrid AutoGenerateColumns="True" ItemsSource="{Binding Table}"> </DataGrid>
How can I do this? Is it possible for me to somehow output and edit data in a convenient format in the form of List<string[]>. A csv table can have an arbitrary number of columns, so I can't make any particular class inside the code. I tried to find an answer to this question on the Internet, looked at several similar projects, but something never figured it out.
Let's say I get the data this way
var _fileName = #"F:\test.csv";
CsvWriter reader = new CsvWriter(_fileName);
foreach(var item in reader.Read())
{
Table.Add(item);
}
There is a library called CSVReader.
It converts any csv files to DataTables
Example:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void OpenCSVButton_Click(object sender, RoutedEventArgs e)
{
DataTable dt = LoadCSVFileFromPath();
dataGrid.ItemsSource = dt.DefaultView;
//Simple method to convert DataTable to a List of strings
AddToList(dt);
}
private List<string> AddToList(DataTable table)
{
List<string> strTable = new List<string>();
foreach(DataRow rows in table.Rows)
{
foreach (DataColumn cols in table.Columns)
strTable.Add(rows[cols].ToString());
}
return strTable;
}
private DataTable LoadCSVFileFromPath()
{
//Use this method to convert your CSV file to DataTable
DataTable table = CSVReader.ReadCSVFile("FILEPATHGOESHERE", true);
return table;
}
}
You can play around and achieve this in MVVM by binding the DefaultView of the DataTable table to DataGrid
Dont use Binding.
XAML:
<DataGrid x:Name="dataGrid1" AutoGenerateColumns="True" />
Read the CSV data and conver it to DataTable, and place it into ItemsSource:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
LoadData();
}
DataTable GetDataTable(CsvReader csv)
{
var dt = new DataTable();
csv.Read();
csv.ReadHeader();
foreach (var header in csv.HeaderRecord)
dt.Columns.Add(header);
var cols = dt.Columns.Count;
while (csv.Read())
{
var row = dt.NewRow();
for (int i = 0; i < cols; i++)
row[i] = csv[i];
dt.Rows.Add(row);
}
return dt;
}
DataTable table;
string _fileName = #"F:\test.csv";
void LoadData()
{
using (var reader = new StreamReader(_fileName ))
using (var csvReader = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture) { Delimiter = "," }))
{
table = GetDataTable(csvReader);
table.AcceptChanges();
dataGrid1.ItemsSource = table.AsDataView();
}
}
void SaveData()
{
if (table.GetChanges() != null)
{
//write DataTable to csv...
}
}
}
Try to put some data from List to dataGridView, but have some problem with it.
Currently have method, that return me required List - please see picture below
code
public List<string[]> ReadFromFileBooks()
{
List<string> myIdCollection = new List<string>();
List<string[]> resultColl = new List<string[]>();
if (chooise == "all")
{
if (File.Exists(filePath))
{
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
StreamReader sr = new StreamReader(fs);
string[] line = sr.ReadToEnd().Split(new string[] { Environment.NewLine },
StringSplitOptions.RemoveEmptyEntries);
foreach (string l in line)
{
string[] result = l.Split(',');
foreach (string element in result)
{
myIdCollection.Add(element);
}
resultColl.Add(new string[] { myIdCollection[0], myIdCollection[1], myIdCollection[2], myIdCollection[3] });
myIdCollection.Clear();
}
sr.Close();
return resultColl;
}
}
....
this return to me required data in requred form (like list from arrays).
After this, try to move it to the dataGridView, that already have 4 columns with names (because i'm sure, that no than 4 colums required) - please see pic below
Try to put data in to dataGridView using next code
private void radioButtonViewAll_CheckedChanged(object sender, EventArgs e)
{
TxtLibrary myList = new TxtLibrary(filePathBooks);
myList.chooise = "all";
//myList.ReadFromFileBooks();
DataTable table = new DataTable();
foreach (var array in myList.ReadFromFileBooks())
{
table.Rows.Add(array);
}
dataGridViewLibrary.DataSource = table;
}
But as result got error - "required more rows that exist in dataGridVIew", but accordint to what I'm see (pic above) q-ty of rows (4) equal q-ty of arrays element in List (4).
Try to check result by putting additional temp variables - but it's ok - please see pic below
Where I'm wrong? Maybe i use dataGridView not in correct way?
EDIT
example of file (simple csv)
11111, Author, Name, Categories
11341, Author1, Name1, Categories1
You need to add columns to your DataTable first before adding rows:
private void radioButtonViewAll_CheckedChanged(object sender, EventArgs e)
{
TxtLibrary myList = new TxtLibrary(filePathBooks);
myList.chooise = "all";
DataTable table = new DataTable();
//add columns first
table.Columns.Add("ID");
table.Columns.Add("Author");
table.Columns.Add("Caption");
table.Columns.Add("Categories");
//then add rows
foreach (var array in myList.ReadFromFileBooks()) {
table.Rows.Add(array);
}
dataGridViewLibrary.DataSource = table;
}
I think your code it's too complex. SImply, if you want see all data in the table from the file, you can do this
if (!System.IO.File.Exists("file.txt"))
return;
dgvDataGridView.ColumnCount = 4;
dgvDataGridView.Columns[0].HeaderCell.Value = "ID";
dgvDataGridView.Columns[1].HeaderCell.Value = "Author";
dgvDataGridView.Columns[2].HeaderCell.Value = "Caption";
dgvDataGridView.Columns[3].HeaderCell.Value = "Categories";
using (System.IO.StreamReader sr = new System.IO.StreamReader("file.txt"))
while (sr.Peek() > -1)
dgvDataGridView.Rows.Add(sr.ReadLine().Split(','));
I am using C# to import a CSV file into my application
Currently I had a 1 field CSV file. It worked great but now I wanted to add a 3 field CSV file into the same application.
Once the data is stored into the List, I'm binding it to my DataGridView
Here is the relevent code I've written. If you see any issue(s) that aren't part of my problem but can be a problem, please feel free to shout them out. Im always looking to learn and improve my code.
BindingList<StringValue> data = new BindingList<StringValue>();
private void importExcelFile()
{
TextFieldParser parser = new TextFieldParser(fileName);
parser.TextFieldType = FieldType.Delimited;
parser.SetDelimiters(",");
while (!parser.EndOfData)
{
//Processing row
string[] fields = parser.ReadFields();
foreach (string field in fields)
{
StringValue s = new StringValue(field);
// Issue is here. It adds it to a single dimension array. What can I do to make it multi-dimension?
data.Add(s);
}
}
parser.Close();
}
private void OnBackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
importExcelFile();
}
private void OnBackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
dataGridView1.DataSource = data;
dataGridView1.Columns[1].Name = "URL";
dataGridView1.Columns[1].HeaderText = "URL";
dataGridView1.Columns[1].Width = 300;
dataGridView1.Columns[1].ReadOnly = true;
dataGridView1.AutoResizeColumns();
toolStripStatusLabel1.Text = dataGridView1.RowCount.ToString() + " Number Of Websites";
}
class StringValue
{
string day, time, url;
public StringValue(string s)
{
_value = s;
}
public StringValue(string[] s)
{
day = s[0];
time = s[1];
url = s[2];
}
public string Value { get { return _value; } set { _value = value; } }
string _value;
}
I think I should modify my StringValue class to hold the multiple fields that I'm importing from my CSV file. I'm not sure how to modify the Value part to return the data I need when I bind it to my dataGridView
Thank you for your input and help/
Why not juste put the csv into a datatable like so?
private DataTable GetDataTableFromCsv(string path)
{
DataTable dataTable = new DataTable();
String[] csv = File.ReadAllLines(path);
foreach (string csvrow in csv)
{
var fields = csvrow.Split(','); // csv delimiter
var row = dataTable.NewRow();
row.ItemArray = fields;
dataTable.Rows.Add(row);
}
return dataTable;
}
after that juste import the datatable into your datagridview.
In your entity (StringValue) you can add as many properties as you want, containing as many values as your want.
You can bind each column of your dataGridView by setting the columns DataPropertyName with the name of the property you are binding to.
For example, your entity has two properties:
class MyValues
{
public string FirstName {get;set;}
public string LastName {get;set;}
}
You add a collection of this to yuur data-collection, which you bind to your grid.
Your grid can be configures as:
dataGridView1.Columns[0].Name = "FirstName";
dataGridView1.Columns[0].HeaderText = "FirstName";
dataGridView1.Columns[0].DataPropertyName = "FirstName";
dataGridView1.Columns[1].Name = "LastName";
dataGridView1.Columns[1].HeaderText = "LastName";
dataGridView1.Columns[1].DataPropertyName = "LastName";
i am using a datagridview in that i am using a datagridviewcomboboxcolumn, comboboxcolumn is displaying text but the problem is i want to select the first item of comboboxcolumn by default how can i do this
DataGridViewComboBoxColumn dgvcb = (DataGridViewComboBoxColumn)grvPackingList.Columns["PackingUnits"];
Globals.G_ProductUtility G_Utility = new Globals.G_ProductUtility();
G_Utility.addUnittoComboDGV(dgvcb);
DataSet _ds = iRawMaterialsRequest.SelectBMR(bmr_ID, branch_ID, "PACKING");
grvPackingList.DataSource = _ds.Tables[0];
int i = 0;
foreach (DataRow dgvr in _ds.Tables[0].Rows)
{
grvPackingList.Rows[i].Cells["Units"].Value = dgvr["Units"].ToString();
i++;
}
The values available in the combobox can be accessed via items property
row.Cells[col.Name].Value = (row.Cells[col.Name] as DataGridViewComboBoxCell).Items[0];
the best way to set the value of a datagridViewComboBoxCell is:
DataTable dt = new DataTable();
dt.Columns.Add("Item");
dt.Columns.Add("Value");
dt.Rows.Add("Item1", "0");
dt.Rows.Add("Item1", "1");
dt.Rows.Add("Item1", "2");
dt.Rows.Add("Item1", "3");
DataGridViewComboBoxColumn cmb = new DataGridViewComboBoxColumn();
cmb.DefaultCellStyle.Font = new Font("Tahoma", 8, FontStyle.Bold);
cmb.DefaultCellStyle.ForeColor = Color.BlueViolet;
cmb.FlatStyle = FlatStyle.Flat;
cmb.Name = "ComboColumnSample";
cmb.HeaderText = "ComboColumnSample";
cmb.DisplayMember = "Item";
cmb.ValueMember = "Value";
DatagridView dvg=new DataGridView();
dvg.Columns.Add(cmb);
cmb.DataSource = dt;
for (int i = 0; i < dvg.Rows.Count; i++)
{
dvg.Rows[i].Cells["ComboColumnSample"].Value = (cmb.Items[0] as
DataRowView).Row[1].ToString();
}
It worked with me very well
If I had known about doing it in this event, it would have saved me days of digging and
trial and errors trying to get it to set to the correct index inside the CellEnter event.
Setting the index of the DataGridViewComboBox is the solution I have been looking for.....THANKS!!!
In reviewing all the issues other coders have been experiencing with trying to set
the index inside of a DataGridViewComboBoxCell and also after looking over your code,
all that anyone really needs is:
1. Establish the event method to be used for the "EditingControlShowing" event.
2. Define the method whereby it will:
a. Cast the event control to a ComboBox.
b. set the "SelectedIndex" to the value you want.
In this example I simply set it to "0", but you'd probably want to apply so real life logic here.
Here's the code I used:
private void InitEvents()
{
dgv4.EditingControlShowing += new DataGridViewEditingControlShowingEventHandler( dgv4EditingControlShowing );
}
private void dgv4EditingControlShowing( object sender, DataGridViewEditingControlShowingEventArgs e )
{
ComboBox ocmb = e.Control as ComboBox;
if ( ocmb != null )
{
ocmb.SelectedIndex = 0;
}
}
If DataGridViewComboBoxCell already exist:
DataTable dt = new DataTable();
dt.Columns.Add("Item");
dt.Columns.Add("Value");
dt.Rows.Add("Item 1", "0");
dt.Rows.Add("Item 2", "1");
dt.Rows.Add("Item 3", "2");
dt.Rows.Add("Item 4", "3");
for (int i = 0; i < dvg.Rows.Count; i++)
{
DataGridViewComboBoxCell comboCell = (DataGridViewComboBoxCell)dvg.Rows[i].Cells[1];
comboCell.DisplayMember = "Item";
comboCell.ValueMember = "Value";
comboCell.DataSource = dt;
};
I've had some real trouble with ComboBoxes in DataGridViews and did not find an elegant way to select the first value. However, here is what I ended up with:
public static void InitDGVComboBoxColumn<T>(DataGridViewComboBoxCell cbx, List<T> dataSource, String displayMember, String valueMember)
{
cbx.DisplayMember = displayMember;
cbx.ValueMember = valueMember;
cbx.DataSource = dataSource;
if (cbx.Value == null)
{
if(dataSource.Count > 0)
{
T m = (T)cbx.Items[0];
FieldInfo fi = m.GetType().GetField(valueMember, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public);
cbx.Value = fi.GetValue(m);
}
}
}
It basically sets the .Display and .ValueMember properties of the DataGridViewComboBoxCell and uses a List as DataSource. It then takes the first item, and uses reflection to get the value of the member that was used as ValueMember and sets the selected value via .Value
Use it like this:
public class Customer
{
private String name;
public String Name
{
get {return this.name; }
set {this.name = value; }
}
private int id;
public int Id
{
get {return this.id; }
set {this.id = value; }
}
}
public class CustomerCbx
{
private String display;
public String Display
{
get {return this.display; }
set {this.display = value; }
}
private Customer value;
public Customer Value
{
get {return this.value; }
set {this.value = value; }
}
}
public class Form{
private void Form_OnLoad(object sender, EventArgs e)
{
//init first row in the dgv
if (this.dgv.RowCount > 0)
{
DataGridViewRow row = this.dgv.Rows[0];
DataGridViewComboBoxCell cbx = (DataGridViewComboBoxCell)row.Cells[0];
Customer c1 = new Customer(){ Name = "Max Muster", ID=1 };
Customer c2 = new Customer(){ Name = "Peter Parker", ID=2 };
List<CustomerCbx> custList = new List<CustomerCbx>()
{
new CustomerCbx{ Display = c1.Name, Value = c1},
new CustomerCbx{ Display = c2.Name, Value = c2},
}
InitDGVComboBoxColumn<CustomerCbx>(cbx, custList, "display", "value");
}
}
}
}
It seems pretty hacky to me, but I couldn't find any better way so far (that also works with complex objects other than just Strings). Hope that will save the search for some others ;)
You need to set the Items for the new cell. This must be auto done by the column when creating a new row from the UI.
var cell = new DataGridViewComboBoxCell() { Value = "SomeText" };
cell.Items.AddRange(new String[]{"SomeText", "Abcd", "123"});
something different worked for me what i did is to simply set the value of dtataGridComboBox when ever new record is added bu user with 'userAddedRow' event. For the first row I used the code in constructor.
public partial class pt_drug : PatientDatabase1_3._5.basic_templet
{
public pt_drug()
{
InitializeComponent();
dataGridView_drugsDM.Rows[0].Cells[0].Value = "Tablet";
}
private void dataGridView_drugsDM_UserAddedRow(object sender, DataGridViewRowEventArgs e)
{
dataGridView_drugsDM.Rows[dataGridView_drugsDM.RowCount - 1].Cells[0].Value = "Tablet";
}
}
Here the solution I have found : select the cell you are interested in so you can cast it to a combobox.
this.Invoke((MethodInvoker)delegate
{
this.dataGridView1.CurrentCell = dataGridView1.Rows[yourRowindex].Cells[yourColumnIndex];
this.dataGridView1.BeginEdit(true);
ComboBox comboBox = (ComboBox)this.dataGridView1.EditingControl;
comboBox.SelectedIndex += 1;
});
I seem to be running around in circles and have been doing so in the last hours.
I want to populate a datagridview from an array of strings. I've read its not possible directly, and that I need to create a custom type that holds the string as a public property. So I made a class:
public class FileName
{
private string _value;
public FileName(string pValue)
{
_value = pValue;
}
public string Value
{
get
{
return _value;
}
set { _value = value; }
}
}
this is the container class, and it simply has a property with the value of the string. All I want now is that string to appear in the datagridview, when I bind its datasource to a List.
Also I have this method, BindGrid() which I want to fill the datagridview with. Here it is:
private void BindGrid()
{
gvFilesOnServer.AutoGenerateColumns = false;
//create the column programatically
DataGridViewTextBoxColumn colFileName = new DataGridViewTextBoxColumn();
DataGridViewCell cell = new DataGridViewTextBoxCell();
colFileName.CellTemplate = cell; colFileName.Name = "Value";
colFileName.HeaderText = "File Name";
colFileName.ValueType = typeof(FileName);
//add the column to the datagridview
gvFilesOnServer.Columns.Add(colFileName);
//fill the string array
string[] filelist = GetFileListOnWebServer();
//try making a List<FileName> from that array
List<FileName> filenamesList = new List<FileName>(filelist.Length);
for (int i = 0; i < filelist.Length; i++)
{
filenamesList.Add(new FileName(filelist[i].ToString()));
}
//try making a bindingsource
BindingSource bs = new BindingSource();
bs.DataSource = typeof(FileName);
foreach (FileName fn in filenamesList)
{
bs.Add(fn);
}
gvFilesOnServer.DataSource = bs;
}
Finally, the problem: the string array fills ok, the list is created ok, but I get an empty column in the datagridview. I also tried datasource= list<> directly, instead of = bindingsource, still nothing.
I would really appreciate an advice, this has been driving me crazy.
Use a BindingList and set the DataPropertyName-Property of the column.
Try the following:
...
private void BindGrid()
{
gvFilesOnServer.AutoGenerateColumns = false;
//create the column programatically
DataGridViewCell cell = new DataGridViewTextBoxCell();
DataGridViewTextBoxColumn colFileName = new DataGridViewTextBoxColumn()
{
CellTemplate = cell,
Name = "Value",
HeaderText = "File Name",
DataPropertyName = "Value" // Tell the column which property of FileName it should use
};
gvFilesOnServer.Columns.Add(colFileName);
var filelist = GetFileListOnWebServer().ToList();
var filenamesList = new BindingList<FileName>(filelist); // <-- BindingList
//Bind BindingList directly to the DataGrid, no need of BindingSource
gvFilesOnServer.DataSource = filenamesList
}
may be little late but useful for future. if you don't require to set custom properties of cell and only concern with header text and cell value then this code will help you
public class FileName
{
[DisplayName("File Name")]
public string FileName {get;set;}
[DisplayName("Value")]
public string Value {get;set;}
}
and then you can bind List as datasource as
private void BindGrid()
{
var filelist = GetFileListOnWebServer().ToList();
gvFilesOnServer.DataSource = filelist.ToArray();
}
for further information you can visit this page Bind List of Class objects as Datasource to DataGridView
hope this will help you.
I know this is old, but this hung me up for awhile. The properties of the object in your list must be actual "properties", not just public members.
public class FileName
{
public string ThisFieldWorks {get;set;}
public string ThisFieldDoesNot;
}
Instead of create the new Container class you can use a dataTable.
DataTable dt = new DataTable();
dt.Columns.Add("My first column Name");
dt.Rows.Add(new object[] { "Item 1" });
dt.Rows.Add(new object[] { "Item number 2" });
dt.Rows.Add(new object[] { "Item number three" });
myDataGridView.DataSource = dt;
More about this problem you can find here: http://psworld.pl/Programming/BindingListOfString
Using DataTable is valid as user927524 stated.
You can also do it by adding rows manually, which will not require to add a specific wrapping class:
List<string> filenamesList = ...;
foreach(string filename in filenamesList)
gvFilesOnServer.Rows.Add(new object[]{filename});
In any case, thanks user927524 for clearing this weird behavior!!