On a windows form I have two unbound data grid view columns each with their own header and I am trying read a csv file in a datatable and bind it to the grid.
Only I don't know the logic involved. I don't know how to bind the data to the 2 data grid view columns. There is a lot of samples out there of how to bind csv data to a grid view but they deal with headers that get read from inside a file and not unbound ones except for this but that's with asp. Display data on grid view column programmatically
Here is the data from the csv file.
Address,76 Douglas St Wakecorn
Property name,Wakecorn University
Building,C Block
Room,C2.18
Here is the code for the class that reads it.
public class Setting
{
private DataTable _dt { get; set; }
public DataTable ProcessSettingFileCMD(string filePath)
{
if (_dt == null)
{
populateControlWithCSVData(filePath);
}
}
private void populateControlWithCSVData(string filePath)
{
_dt = new DataTable();
string[] lines = File.ReadAllLines(filePath);
if(lines.Length > 0)
{
for(int row = 1; row < lines.Length; row++)
{
string[] dataWords = lines[row].Split(',');
DataRow dr = _dt.NewRow();
foreach (string word in lines)
{
dr[word] = dataWords[row++];
}
_dt.Rows.Add(dr);
}
}
}
}
Here is the form
private void mnuOpen_Click(object sender, EventArgs e)
{
openFD.InitialDirectory = "C:\\";
openFD.ShowDialog();
_dt = _objSetting.ProcessSettingFileCMD(openFD.FileName);
if (_dt.Rows.Count > 0)
{
gvSettings.DataSource = _dt;
}
}
The error being returned is here on dr[word] = dataWords[row++];
System.ArgumentException: 'Column 'Address,76 Douglas St Wakecorn'
does not belong to table .
As per the guidance and options provided I have taken out the columns made in the designer and instead instanced them when reading a CSV file.
Also I have used a CsvFileReader child class to bind it to a string list and then to a data table. Highly useful! http://www.blackbeltcoder.com/Articles/files/reading-and-writing-csv-files-in-c
Here is the rewritten code.
Settings Form.
public partial class frmSettings : Form
{
protected string FileName;
protected bool Modified;
Setting _objSetting = new Setting();
OpenFileDialog openFD = new OpenFileDialog();
DataTable _dt = new DataTable();
public frmSettings()
{
InitializeComponent();
}
private void mnuOpen_Click(object sender, EventArgs e)
{
Cursor = Cursors.WaitCursor;
try
{
openFD.Title = "Open a CSV File";
if (SaveIfModified())
{
if (openFD.ShowDialog(this) == DialogResult.OK)
{
_dt = _objSetting.ProcessSettingFileCMD(openFD.FileName);
if (_dt.Rows.Count > 0)
{
gvSettings.DataSource = _dt;
}
}
}
FileName = openFD.FileName;
Modified = false;
}
catch (Exception ex)
{
Debug.WriteLine(String.Format("Error reading from {0}.\r\n\r\n{1}", FileName, ex.Message));
}
finally
{
Cursor = Cursors.Default;
}
}
}
Here is the Settings class again.
public class Setting
{
private DataTable _dt;
DataColumn _dclColumnDescription = new DataColumn("Description", typeof(string));
DataColumn _dclColumnData = new DataColumn("Data", typeof(string));
public DataTable ProcessSettingFileCMD(string filePath)
{
if (_dt == null)
{
populateControlWithCSVData(filePath);
}
}
private void populateControlWithCSVData(string filePath)
{
_dt = new DataTable();
List<string> columns = new List<string>();
using (var reader = new CsvFileReader(filePath))
{
_dt.Columns.Add(_dclColumnDescription);
_dt.Columns.Add(_dclColumnData);
while (reader.ReadRow(columns))
{
_dt.Rows.Add(columns.ToArray());
}
}
}
}
Related
the SS of my current App
I set all the codes to retrieve the information from the SQL table , now i only need to convert the retrieved image URL to Image in the DataGridView
here is the codes am using now :
namespace LamasoDemo
{
public partial class FormOrders : Form
{
public FormOrders()
{
InitializeComponent();
FillGridView();
}
void FillGridView()
{
List<Products> productsList = new List<Products>();
Products products = new Products();
productsList = products.GetProducts();
dataGridViewProducts.DataSource = productsList;
}
and on the class here is the codes :
public class Products
{
public string? Image { get; set; }
string connectionString = "Data Source=AHMEDBABAJAN;Initial Catalog=Lamaso1;Integrated Security=True;Trust Server Certificate=true";
public List<Products> GetProducts()
{
List<Products> ProductsList = new List<Products>();
SqlConnection con = new SqlConnection(connectionString);
string selectSQL = "select Image Status From GetProductsData";
con.Open();
SqlCommand cmd = new SqlCommand(selectSQL, con);
SqlDataReader dr = cmd.ExecuteReader();
if (dr != null)
{
while (dr.Read())
{
Products Products = new Products();
Products.Image = dr["Image"].ToString();
ProductsList.Add(Products);
}
}
return ProductsList;
}
Anyone have any idea on how to show the image ? from URL
The easiest solution is using an unbound DataGridViewImageColumn, then you can handle CellFormatting event and load the image.
In the following example, I've handled the CellFormatting event, considering the following points:
The code loads images lazily, once requested in CellFormattings.
It stores image in the cell value, to avoid loading it again.
To try the code, create a Form, drop a DataGridView on it and use the following code:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
httpClient.DefaultRequestHeaders.TryAddWithoutValidation(
"User-Agent", "Mozilla/5.0 (Windows NT 6.2; " +
"WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
//Load data
var data = GetData();
//Set up dataGridView
dgv1.RowTemplate.Height = 100;
dgv1.DataSource = data;
dgv1.Columns.Add(new DataGridViewImageColumn()
{
Name = "ImageColumn",
HeaderText = "Image",
ImageLayout = DataGridViewImageCellLayout.Zoom,
Width = 150
});
dgv1.CellFormatting += dgv1_CellFormatting;
}
private async void dgv1_CellFormatting(object sender,
DataGridViewCellFormattingEventArgs e)
{
if (e.RowIndex >= 0 && e.RowIndex < dgv1.NewRowIndex &&
dgv1.Columns[e.ColumnIndex].Name == "ImageColumn")
{
var item = (DataRowView)dgv1.Rows[e.RowIndex].DataBoundItem;
var uri = item.Row.Field<string>("ImageUri");
if (e.Value == null || e.Value == DBNull.Value)
{
dgv1.Rows[e.RowIndex]
.Cells["ImageColumn"].Value = await DownloadImage(uri);
}
}
}
DataTable GetData()
{
var data = new DataTable();
data.Columns.Add("Name", typeof(string));
data.Columns.Add("ImageUri", typeof(string));
data.Rows.Add("Lorem", $"https://picsum.photos/300/200?1");
data.Rows.Add("Ipsum", $"https://picsum.photos/300/200?2");
data.Rows.Add("Dolor", $"https://picsum.photos/300/200?3");
data.Rows.Add("Sit", $"https://picsum.photos/300/200?4");
data.Rows.Add("Amet", $"https://picsum.photos/300/200?5");
return data;
}
HttpClient httpClient = new HttpClient();
async Task<Image> DownloadImage(string uri)
{
return Image.FromStream(await httpClient.GetStreamAsync(uri));
}
Run the code and see the result.
You should also take care of disposing the images:
protected override void OnFormClosing(FormClosingEventArgs e)
{
base.OnFormClosing(e);
if (!e.Cancel)
{
DisposeImages();
}
}
void DisposeImages()
{
foreach (DataGridViewRow row in dgv1.Rows)
{
if (!row.IsNewRow)
{
var value = row.Cells["ImageColumn"].Value;
row.Cells["ImageColumn"].Value = null;
if (value is Image)
((Image)value).Dispose();
}
}
}
You may also want to modify the code and handle cases when the image could not be downloaded.
How to show the csv data in datagridview(windows tool) when button2 is clicked?
public class CsvImport
{
public static DataTable NewDataTable(string fileName, string delimiters, bool firstRowContainsFieldNames = true)
{
DataTable result = new DataTable();
using (TextFieldParser tfp = new TextFieldParser(fileName))
{
tfp.SetDelimiters(delimiters);
// Get Some Column Names
if (!tfp.EndOfData)
{
string[] fields = tfp.ReadFields();
for (int i = 0; i < fields.Count(); i++)
{
if (firstRowContainsFieldNames)
result.Columns.Add(fields[i]);
else
result.Columns.Add("Col" + i);
}
// If first line is data then add it
if (!firstRowContainsFieldNames)
result.Rows.Add(fields);
}
// Get Remaining Rows
while (!tfp.EndOfData)
result.Rows.Add(tfp.ReadFields());
}
return result;
}
}
private void button2_Click(object sender, EventArgs e)
{
datagridview1. result;
}
You should set the datatable containing the output data as an itemssource for the datagrid.
The answer would be datagridview1.ItemsSource=result.You can just call the function returning the datatable result.
DataGridViewImageColumn do not display all records.
I have a datagridview that is to display all records.
But this is not happening!
Only those records that have a picture in a field (say - "Photo").
And those records that do not have the image is not displayed.
Why is this happening?
That I have not tried all else fails.
Try this:
Load += delegate
{
foreach (var column in dataGridView1.Columns)
{
if (column is DataGridViewImageColumn)
(column as DataGridViewImageColumn).DefaultCellStyle.NullValue = null;
}
};
and this:
var column1 = new DataGridViewImageColumn();
column1.DefaultCellStyle.NullValue = null;
column1.CellTemplate = new DataGridViewEmptyImageCell();
private class DataGridViewEmptyImageCell : DataGridViewImageCell
{
public override object DefaultNewRowValue { get { return null; } }
}
Insert after InitializeComponent() and in private void dataGridView1_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e);
Add code about this theme:
Class Connection have this method:
public void FillDataGridView(DataGridView dataGridView, string query="")
{
try
{
command = new MySqlCommand(query, connection); //Создаём запрос для поиска
adapter = new MySqlDataAdapter(command); //Выполняем команду
//Для отображения в таблице
DataTable table = new DataTable(); //Создаём таблицу
adapter.Fill(table); //Вставляем данные при выполнении команды в таблицу
dataGridView.DataSource = table; //подключаем заполненную таблицу и отображаем
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Code in Form which have DataGridView:
private void TestFormTwo_Load(object sender, EventArgs e)
{
FillDataGridView("");
}
public void FillDataGridView(string valueToSearch)
{
//получаем запрос на отображение данных с поиском
string nameTable = "info";
string[] nameFieldsAll = {"id_info", "full_name", "passport_id", "age", "address", "phone", "photo"};
string[] nameFieldsAS = {"ИД","ФИО","Серия и номер паспорта","Возраст","Адрес","Телефон","Фото"};
string[] numericFields = {"id_info","age"};
string query = connection.GetQueryShowSearch(nameTable, nameFieldsAll, nameFieldsAS, numericFields, valueToSearch);
//заполняем данные таблицы на основе запроса
connection.FillDataGridView(dataGridView1, query);
settings.GetSettingDisplayTable(dataGridView1, 100);
settings.GetViewImageInCellTable(dataGridView1, 6);
}
As I checked datagridview shows rows with imageColumn even if image is null and if cell style is set to null.
If you have debugged your code and you are sure that those rows are really in datasource of your dataGrid then there has to be some bug in your code or something in your datagridview properties is set incorrectly.
Please, post some more code (runnable preferred) so we can check it out.
So I'm accessing a DB through a stored procedure and am able to pull the data I wanted into a popup box. The problem now is that no matter what row I click on, the SAME data keeps populating my fields. How the heck can I choose a particular row, and have that specific row's data pulled from the DB? Thanks for any help
Form1
public partial class DSC_Mon : Form
{
DSCU_SvcConsumer.MTCaller Caller;
DataSet dsZA;
DataSet dsOut;
public DSC_Mon()
{
InitializeComponent();
Caller = new DSCU_SvcConsumer.MTCaller();
dsZA = new DataSet();
dsOut = new DataSet();
}
private void DSC_Mon_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
private void LoadData()
{
if (!dsZA.Tables.Contains("Query"))
{
DataTable dtZA = dsZA.Tables.Add("Query");
dtZA.Columns.Add("str");
dtZA.Rows.Add(string.Format(#"exec MON_GetStatus"));
}
//dtZA.Rows.Add(string.Format(#"select * from am_company"));
dsOut.Clear();
dsOut.Merge(Caller.CallRequest("ZuluAction", dsZA));
if (gridEXMon.DataSource == null)
{
gridEXMon.DataSource = dsOut;
gridEXMon.DataMember = "Table";
}
//gridEXMon.RetrieveStructure();
}
private void timer1_Tick(object sender, EventArgs e)
{
timer1.Enabled = false;
LoadData();
timer1.Enabled = true;
}
private void gridEXMon_DoubleClick(object sender, EventArgs e)
{
ReportInfo report = new ReportInfo();
report.ShowDialog();
}
}
I replaced the private void gridEXMon_DoubleClick with:
private void gridEXMon_RowDoubleClick(object sender, Janus.Windows.GridEX.RowActionEventArgs e)
{
if (e.Row.RowIndex < 0)
return;
int rowIndex = Convert.ToInt32(e.Row.RowIndex);
ReportInfo report = new ReportInfo(rowIndex);
report.ShowDialog();
}
Popup Dialog
public partial class ReportInfo : Form
{
public ReportInfo()
{
InitializeComponent();
DSCU_SvcConsumer.MTCaller caller = new DSCU_SvcConsumer.MTCaller();
DataSet dsZA = new DataSet();
DataSet dsOut = new DataSet();
if (!dsZA.Tables.Contains("Query"))
{
DataTable dtZA = dsZA.Tables.Add("Query");
dtZA.Columns.Add("str");
dtZA.Rows.Add(string.Format(#"MON_ReportInfo"));
}
dsOut.Clear();
dsOut.Merge(caller.CallRequest("ZuluAction", dsZA));
DataTable dt = dsOut.Tables["Table"];
DataRow dr = dt.Rows[0];
if (dt != null)
{
systemNameTextBox.Text = dr["System"].ToString();
contactName1TextBox.Text = dr["Manager"].ToString();
functionNameTextBox.Text = dr["Function"].ToString();
durationMSTextBox.Text = dr["Speed"].ToString();
}
}
I then sent the rowIndex to the popup:
DataTable dt = dsOut.Tables["Table"];
DataRow dr = dt.Rows[rowIndex];
systemNameTextBox.Text = dr["System"].ToString();
contactName1TextBox.Text = dr["Manager"].ToString();
functionNameTextBox.Text = dr["Function"].ToString();
durationMSTextBox.Text = dr["Speed"].ToString();
}
Better to get the data from the grid to save the extra call to the database in your ReportInfo class.
Here is the code:
private void gridEXMon_DoubleClick(object sender, EventArgs e)
{
if (e.Row.RowIndex < 0)
return;
ReportInfo report = new ReportInfo();
String System = Convert.ToInt32(e.Row.Cells["System"].Value);
String Manager = Convert.ToString(e.Row.Cells["Manager"].Value);
String Function = Convert.ToDecimal(e.Row.Cells["Function"].Value);
String Speed = Convert.ToInt32(e.Row.Cells["Speed"].Value);
report.ShowDialog(System, Manager, Function, Speed);
}
Then your ReportInfo class ctor should be:
public partial class ReportInfo : Form
{
public ReportInfo(String System, String Manager, String Function, String Speed)
{
InitializeComponent();
systemNameTextBox.Text = System;
contactName1TextBox.Text = Manager;
functionNameTextBox.Text = Function;
durationMSTextBox.Text = Speed;
}
}
Have you tried with:
gridEXMon.DataSource = dsOut.Tables[0];
// next line is not required if you've already defined proper grid structure
gridEXMon.RetrieveStructure();
Janus has also his own forum available here. You can find there a lot of useful information. For browsing I will use IE. Janus forum works good only with IE...
Edited:
How ReportInfo class can know what record have you selected? Especially that you have fallowing code:
DataTable dt = dsOut.Tables["Table"];
DataRow dr = dt.Rows[0]; // always first record is taken!
Probably you should define ctor with row index:
public ReportInfo(int rowIndex)
{
...
DataTable dt = dsOut.Tables["Table"];
DataRow dr = dt.Rows[rowIndex];
....
}
How can i get multiple selected rows in gridview using c# code & that selected rows i have to display in another form which also have gridview
public partial class WindowForm: Form
{
private DataTable dataTable = new DataTable();
//This will contain all the selected rows.
private List<DataGridViewRow> selectedRows = new List<DataGridViewRow>();
public WindowForm()
{
InitializeComponent();
dataTable .Columns.Add("Column1");
dataTable .Columns.Add("Column2");
dataTable .Columns.Add("Column3");
for (int i = 0; i < 30; i++)
{
dataTable .Rows.Add(i, "Row" + i.ToString(), "Item" + i.ToString());
}
dataGridView1.DataSource = dataTable ;
//This will select full row of a grid
dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
//This will allow multi selection
dataGridView1.MultiSelect = true;
dataGridView1.CurrentCellChanged += new EventHandler(dataGridView1_CurrentCellChanged);
dataGridView1.CellBeginEdit += new DataGridViewCellCancelEventHandler(dataGridView1_CellBeginEdit);
}
void dataGridView1_CellBeginEdit(object sender, DataGridViewCellCancelEventArgs e)
{
PerformSelection(dataGridView1, selectedRows);
}
void dataGridView1_CurrentCellChanged(object sender, EventArgs e)
{
if (selectedRows.Contains(dataGridView1.CurrentRow))
{
selectedRows.Remove(dataGridView1.CurrentRow);
}
else
{
selectedRows.Add(dataGridView1.CurrentRow);
}
PerformSelection(this.dataGridView1, selectedRows);
}
private void PerformSelection(DataGridView dgv, List<DataGridViewRow> selectedRowsCollection)
{
foreach (DataGridViewRow dgvRow in dgv.Rows)
{
if (selectedRowsCollection.Contains(dgvRow))
{
dgvRow.Selected = true;
}
else
{
dgvRow.Selected = false;
}
}
}
}