Tag Array c# winforms - c#

The code below lets me show emails received in a listview on when the selected index is changed displays the body of the selected email in a RTB. The problem is i changed the code to work with a data grid view and now the Tag part wont work
void SomeFunc() // This line added by Jon
{
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
ListViewItem itmp = new ListViewItem(email.From);
ListViewItem.ListViewSubItem itms1 =
new ListViewItem.ListViewSubItem(itmp, email.Subject);
ListViewItem.ListViewSubItem itms2 =
new ListViewItem.ListViewSubItem(itmp, email.FromName);
itmp.SubItems.Add(itms1);
itmp.SubItems.Add(itms2);
listView1.Items.Add(itmp).Tag = i;
richTextBox1.Text = email.Body;
}
// Save the email to an XML file
bundle.SaveXml("email.xml");
}
private void listView1_SelectionChanged(object sender, EventArgs e)
{
if (listView1.SelectedCells.Count > 0)
{
// bundle is now accessible in your event handler:
richTextBox1.Text = bundle.GetEmail((int)listView1.SelectedCells[0].Tag).Body;
}
}
Code for data grid view
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
string[] row = new string[] { email.From, email.Subject, email.FromName };
object[] rows = new object[] { row };
foreach (string[] rowArray in rows)
{
dataGridView1.Rows.Add(rowArray);
}
} // This line added by Jon

i have created earlier the code for datagrid view but you already done it so i haven't posted in your last question but i think , you should give a try to the below code.
// i am creating a new object here but , you can have a single object on the form
DataGridView dgv = new DataGridView();
private DataTable EmailSource { get; set; }
dgv.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
dgv.SelectionChanged+=new EventHandler(dgv_SelectionChanged);
Chilkat.MessageSet msgSet = imap.Search("ALL", true);
if (msgSet != null)
{
bundle = imap.FetchBundle(msgSet);
CreateDataTable();
if (bundle != null && dt!=null)
{
Chilkat.Email email;
int i;
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
if(email!=null)
{
DataRow drow = EmailSource.NewRow();
drow["Id"] = i.ToString();
drow["From"] = email.FromName;
drow["Subject"] = email.Subject;
drow["DateRecived"] = email.DateRecived;
// i am adding email body also
drow["Body"] =email.Body;
EmailSource.Rows.Add(drow);
}
}
// Save the email to an XML file
bundle.SaveXml("email.xml");
dgv.DataSource= EmailSource;
// Hiding Body from the grid
dgv.Columns["Body"].Visible =false;
}
}
// this event handler will show the last selected email.
void dgv_SelectionChanged(object sender, EventArgs e)
{
DataGridViewSelectedRowCollection rows = dgv.SelectedRows;
if (rows != null)
{
// get the last selected row
DataRow drow = rows[rows.Count - 1].DataBoundItem as DataRow;
if (drow != null)
{
richTextBox1.Text = drow["Body"];
}
}
}
private void CreateDataTable()
{
EmailSource = new DataTable();
EmailSource.Columns.Add("Id");
EmailSource.Columns.Add("From");
EmailSource.Columns.Add("Subject");
EmailSource.Columns.Add("DateRecived");
EmailSource.Columns.Add("Body");
}

You are adding rows using listView1.Rows.Add(rowArray) in both the code listings. Is that a typo or you named the GridView like that.
Basically, you are storing the index of the email in the "Tag" property.
listView1.Items.Add(itmp).Tag = i;
You need to make sure that you do the same while adding items to the GridView too.

The DataGridView does not have an "Items" collection. To make it work, you need to bind the DataGridView to a collection of objects. Something like this should get you started:
List<Email> emails = new List<Email>();
for (i = 0; i < bundle.MessageCount; i++)
{
email = bundle.GetEmail(i);
emails.Add(email);
}
dataGridView.ItemsSource = emails;
You should not need to store the row index for each item in a "Tag" object - you can can get the selected index like this:
int selectedIndex = dataGridView.SelectedCells[0].RowIndex;

Related

DataGridView won't show correctly after loading some data

I load data from SQLite to DataGridView. DataGridView doesn't show correctly. I have tried to use follow methods: Refresh, Paint, Update, Invalidate DataGridView.
If I minimize and maximize my program, then DataGridView shows correctly.
I execute it in the MainForm.
private void thicknessComboBox_TextChanged(object sender, EventArgs e)
{
List<string> tm1Deflection = database.ExecuteSelectQuery(connectionString, tm1ListCommand, parameters);
List<string> tension = database.ExecuteSelectQuery(connectionString, tensionListCommand, parameters);
var rowHeaders = new string[] { "TM-1 READING", "SPOKE TENSION (KGF)" };
var rows = new List<string[]> { tm1Deflection.ToArray(), tension.ToArray() };
formControl.SetDataGridViewValues(conversionTableGridView, tm1Deflection.Count, rowHeaders, rows); // This string filling DataGridView
}
Filling DataGridView locates in another class:
public void SetDataGridViewValues(DataGridView dataGridView, int columnCount, string[] rowHeaders, List<string[]> rows)
{
dataGridView.ColumnCount = columnCount;
dataGridView.RowHeadersWidth = 165;
int columnsWidth = (dataGridView.Width - dataGridView.RowHeadersWidth) / dataGridView.ColumnCount;
for (var i = 0; i < columnCount; i++)
{
dataGridView.Columns[i].Name = "";
dataGridView.Columns[i].Width = columnsWidth;
}
dataGridView.Rows.Clear();
if (rows.Count != rowHeaders.Length)
{
MessageBox.Show("Number of row headers must be equal number of rows!", Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Warning);
}
else
{
for (var i = 0; i < rows.Count; i++)
{
dataGridView.Rows.Add(rows[i]);
dataGridView.Rows[i].HeaderCell.Value = rowHeaders[i];
}
}
}
Example with DataTable:
DataTable table = new DataTable();
table.Columns.Add("Column1", typeof(int));
table.Rows.Add(1);
conversionTableGridView.DataSource = table;
Error:
I have clicked on first cell:

Adding new entry to DataGridView via BindingSource

Good day,
I'm writing a PasswordManager at the moment and am stuck with adding new rows to my DataGridView.
You can see my code over here: PassMangaer
The Engine/NewEntry.cs has the code for creating a new entry and adding it to the BindingSource.
After that, the PassManger/frmAddNewEntry.cs adds it to the DataGridView on the main Form and refreshed the DataGridView.
Actually it just replaced the current row with the new one and does not, as it is supposed to, add a new row.
What am I missing here?
your problem in frmAddNewEntry, line 18 , when your create BindingSource Bs = new BindingSource(). btnAddEntry_Click works with empty Bs.
My suggestion:
PassManager. Remove line 18
public void addNewEntry(BindingSource bs, int id, string hoster)
private void btnAddEntry_Click(object sender, EventArgs e)
{
string hoster = textBox1.Text;
ne.addNewEntry(mainForm.Bs, 1, hoster);
mainForm.RefreshDGV();
this.Close();
}
dont recommend to use, but that one would be fast hot fix for your last comment:
public void LoadData(DataGridView grid)
{
DataTable dataTable = new DataTable();
foreach (DataGridViewColumn col in grid.Columns)
{
dataTable.Columns.Add(new DataColumn(col.Name));
}
string file = "mygrid.bin";
using (BinaryReader bw = new BinaryReader(File.Open(file, FileMode.Open)))
{
int n = bw.ReadInt32();
int m = bw.ReadInt32();
for (int i = 0; i < m; ++i)
{
dataTable.Rows.Add();
for (int j = 0; j < n; ++j)
{
if (bw.ReadBoolean())
{
dataTable.Rows[i][j] = bw.ReadString();
dataTable.Rows[i][j] = Base64Decode(dataTable.Rows[i][j].ToString());
}
else bw.ReadBoolean();
}
}
}
grid.DataSource = dataTable;
}

iterate through a datatable of rows using `Next` and `Previous` buttons

I would like to iterate through a datatable of rows using Next and Previous buttons.
My form has the following:
[Ticket Ref]
[Short Description]
[Next Step]
[Last Updated]
Through the life of a case, you might get multiple updates. Therefore I may have 5 rows in the database relating to a particular Ticket Reference. Comments and Last Updated will obviously be different.
When the form loads it will display the last record in the database into the text boxes i.e the last row from the query. I would then like to click Previous and see the previous rows. But if i click on Next I expect it to loop through. i.e go to the next record. So if im on record 1, then it needs to go to 2.
I have tried counting the clicks but this isnt very helpful as when the form first loads count will be 0 and if i click Previous then i will get a Row out of position -1 error.
My previous button looks like this:
protected void btnPrevious_Click1(object sender, EventArgs e)
{
DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
DataTable dt = new DataTable();
dt = eobj.GetTicketUpdates(txtSupportRef.Text);
int i = 0;
if (i < dt.Rows[0].Table.Rows.Count - 1 || i != 0)
{
i--;
txtShortDesc.Text = dt.Rows[0].Table.Rows[i]["ShortDesc"].ToString();
txtNextStep.Text = dt.Rows[0].Table.Rows[i]["NextStep"].ToString();
txtLastUpdated.Text = dt.Rows[0].Table.Rows[i]["LastUpdated"].ToString();
}
else
{
//no records to see more.
}
}
My next button looks like this:
protected void btnNext_Click1(object sender, EventArgs e)
{
DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
DataTable dt = new DataTable();
dt = eobj.GetTicketUpdates(txtSupportRef.Text);
int i = 0;
if (i < dt.Rows[0].Table.Rows.Count - 1)
{
i++;
txtShortDesc.Text = dt.Rows[0].Table.Rows[i]["ShortDesc"].ToString();
txtNextStep.Text = dt.Rows[0].Table.Rows[i]["NextStep"].ToString();
txtLastUpdated.Text = dt.Rows[0].Table.Rows[i]["LastUpdated"].ToString();
}
else
{
//no records to see more.
}
}
Also the user will have the ability to load different ticket references into the form. So i need the ability to quickly iterate based on the loaded ticket.
If you need more info please ask.
Your solution will work if you properly manage the index wrap-around.
You just need to reset the index to 0 when it hits the end of the data set, and set it to DataTable.Rows.Count - 1 when it goes back from the beginning.
INITIALIZE
DataTable dt;
protected override void Page_Load
{
// querying each load gets expensive; consider alternative patterns?
dt = GetData(txtSupportRef.Text);
if (!IsPostBack)
{
int i = 0;
ViewState["recordIndex"] = i;
PopulateForm(i);
}
}
CREATE REUSABLE FUNCTIONS - THEY SAVE YOU MILLION$
protected DataTable GetData(string supportRef)
{
DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter eobj = new DAL.TicketsDataSetTableAdapters.TicketDetailsTableAdapter();
return eobj.GetTicketUpdates(supportRef);
}
protected void PopulateForm(int i)
{
ViewState["recordIndex"] = i
System.Data.DataRow row = dt.Rows[0].Table.Rows[i];
txtShortDesc.Text = row["ShortDesc"].ToString();
txtNextStep.Text = row["NextStep"].ToString();
txtLastUpdated.Text = row["LastUpdated"].ToString();
}
PREVIOUS BUTTON
protected void btnPrevious_Click1(object sender, EventArgs e)
{
int i = (int)ViewState["recordIndex"];
i = i <= 0 ? dt.Rows[0].Table.Rows.Count - 1 : i-1;
PopulateForm(i);
}
NEXT BUTTON
protected void btnNext_Click1(object sender, EventArgs e)
{
int i = (int)ViewState["recordIndex"];
i = i >= dt.Rows[0].Table.Rows.Count - 1 ? 0 : i+1;
PopulateForm(i);
}
Here is a JavaScript example that illustrates the algorithm and shows how much more responsive it is when doing this client side instead. It is applicable to C# also
var startWith = 1; // or 0, etc.
var pageNo = startWith;
var recordCount = 5;
var records = [];
for(var i = 0; i < recordCount; i++)
{
records.push({TicketRef: "000-00-"+ i, ShortDescription: ['BLUE SCREEN','VIRUS INFECTION','NEW HARDWARE','SOFTWARE UPGRADE','SPILLED SODA ON KEYBOARD','BROKEN CD-ROM'][Math.random()*6|0], NextStep: ['ESCALATE','RESOLVE','RETURN','CLOSE','INVESTIGATE','TRANSFER'][Math.random()*6|0], LastUpdated: ((Math.random()*12|0)+1).toString() + " hours ago" });
}
renderPageNo = function() {
$("h1").text(pageNo);
$("input:text").each(function(){this.value=records[pageNo-startWith][$(this).data("field")];});
}
prev = function() {
if (pageNo > startWith) pageNo--
else pageNo = recordCount;
renderPageNo(pageNo);
}
next = function() {
if (pageNo < recordCount) pageNo++
else pageNo = startWith;
renderPageNo(pageNo);
}
renderPageNo();
$(".btn").eq(0).on("click", prev).end().eq(1).on("click", next);
*
{
font-family: 'Segoe UI';
}
label
{
width: 200px;
display:block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1></h1>
<label>Ticket Ref<input type='text' data-field="TicketRef"/></label>
<label>Short Description<input type='text' data-field="ShortDescription"/></label>
<label>Next Step<input type='text' data-field="NextStep"/></label>
<label>LastUpdated<input type='text' data-field="LastUpdated"/></label>
<input class='btn' type='button' value='PREV' />
<input class='btn' type='button' value='NEXT' />
I would provide an index in your database table, which you can then load into the datatable together with the rest of the data. Then you can use that index to go forward and backwards with no hustle by extracting row details based on the index:
// store your current row index in a ViewState when first loading the data
ViewState["currentIndex"] = (int)row["RowIndex"];
//When going forward increment your rowIndex to find out the new Row Index
int currentRowIndex = (int) ViewState["currentIndex"];
currentRowIndex++; // ++ to go next -- to go previous
//Get the current row based on rowindex
DataRow row = myDataTable.Select("ID=" + currentRowIndex);
// then use the row data and assign to your textboxes
So for example a unique identity key, which is auto incremented by 1 in your database table will help to solve the problem.
Let me break it down a bit further:
Lets assume you fetch your database data on the page Load event:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
// Code to Fetch database data and assign it to a datatable
// Save DataTable in a ViewState["currentTable"]
// Get Last Row and assign field values to textboxes
// Get Last Row index value and assign it to ViewState["currentRowIndex"]
}
}
protected void cmdMoveNext_Click(){
// in this function you going to get your current row index from the ViewState[currentRowIndex]
int currentIndex = (int)ViewState["currentRowIndex"];
currentIndex++; // set next row index (currentIndex=currentIndex+1)
// declare a datatable and assing viewstate["currentTable"] to it
DataTable myTable = (DataTable)ViewState["currentTable"];
// Find the DataRow at the new index
DataRow row = (DataRow) myTable.Select("search by index code");
// Use the new row values to assign to textboxes
// Save the new row index in ViewState
}
I have done the same thing but much simpler and without using additional indexers.
Here is what I have done:
public OnLoad(...)
{
if(!Page.IsPostBack)
{
BuidNavigationList();
}
LoadNavigation();
}
private List<string> NavigationList
{
get
{
if (ViewState["NavigationList"] != null)
{
return (List<string>)ViewState["NavigationList"];
}
return null;
}
set
{
ViewState["NavigationList"] = value;
}
}
private void BuidNavigationList()
{
// ds get
if (ds.Tables.Count == 1)
{
DataTable dataTable = ds.Tables[0];
if (dataTable.Columns.Contains("YourSwitchColumn"))
{
NavigationList = new List<string>(dataTable.Rows.Cast<DataRow>().Select(r => r["YourSwitchColumn"]).Cast<String>());
}
}
}
private string YourCurrentSwitchColumnValue
{
get
{
return Request["YourSwitchColumn"].ToString();
}
}
private void LoadNavigation()
{
if(this.NavigationList == null)
{
lblPrevious.Enabled = false;
lblNext.Enabled = false;
}
int navigationListIndex = NavigationList.IndexOf(YourCurrentSwitchColumnValue);
if (navigationListIndex == 0)
{
lblPrevious.Enabled = false;
lblNext.Enabled = true;
lblNext.Value = NavigationList[navigationListIndex + 1];
}
else if (navigationListIndex > 0 && navigationListIndex < NavigationList.Count - 1)
{
lblPrevious.Enabled = true;
lblNext.Enabled = true;
lblPrevious.Value = NavigationList[NavigationListIndex - 1];
lblNext.Value = NavigationList[NavigationListIndex + 1];
}
else if (navigationListIndex == NavigationList.Count - 1)
{
lblPrevious.Enabled = true;
lblNext.Enabled = false;
lblPrevious.Value = NavigationList[NavigationListIndex - 1];
}
}
public void lblNext_OnClick(object sender, ...)
{
Request.Redirect("SamePage.aspx?YourSwitchColumn=" + valueFrom_lblNext);
}
Note this is a demo code you should implement on your needs

Overlapping in listview c#

Good day, I have a list view that looks like this.
My problem is that the name of the items are overlapping, that name is from the database, do i have to set something in the properties for it not to overlap?
form_load code
private void FormAdhocReport_Load(object sender, EventArgs e)
{
LoadReport();
ToolBar(sRights);
}
LoadReport code:
private void LoadReport()
{
dsReports.Clear();
this.listReports.Items.Clear();
adhoc.AccountRowID = CurrentUserNameRowID;
string sRetXMLValue = adhoc.get_sp_Reports_View_Owner();
string XMLDOC = sRetXMLValue;
ReadXMLData(XMLDOC);
ListReportData();
//int count = listReports.Items.Count;
}
ListReportDataCode:
private void ListReportData()
{
try
{
// Get the table from the data set
DataTable dtable = dsReports.Tables[0];
// Clear the ListView control
this.listReports.Items.Clear();
// Display items in the ListView control
for (int i = 0; i < dtable.Rows.Count; i++)
{
DataRow drow = dtable.Rows[i];
if (drow.RowState != DataRowState.Deleted)
{
// Define the list items
ListViewItem lvi = new ListViewItem(drow["ReportName"].ToString());
lvi.ImageIndex = 0;
lvi.SubItems.Add(drow["RowID"].ToString());
listReports.Items.Add(lvi);
}
}
}
catch { }
}
Don't mind this codes: string sRetXMLValue = adhoc.get_sp_Reports_View_Owner();
string XMLDOC = sRetXMLValue;
ReadXMLData(XMLDOC); because they're just for getting the data in the database.
Thanks in advance for your help.

How to read from a GridView

Solution, for at least a specific cell: GridView1.Rows[i].Cells[j].Text;
I've build a simple CSV-Fileupload. After the user uploaded the file he should be able to evaluate the data. When the fileupload was successful the data gets loaded into the GridView1, with this code: (Problem below the code)
string[] readCSV = File.ReadAllLines(lblFilePath.Text);
DataTable dt = new DataTable();
bool bSplitMe = false;
foreach (var rLine in readCSV)
{
if (bSplitMe)
{
string[] aSplittedLine = rLine.Split(";".ToCharArray());
try
{
dt.Rows.Add(aSplittedLine);
}
catch(System.Exception)
{
txtBoxFileOut.Text = rLine;
break;
}
}
else
{
if (rLine.ToLower().StartsWith("definedtestid;"))
{
bSplitMe = true;
string[] aSplittedLine = rLine.Split(";".ToCharArray());
foreach (var rCol in aSplittedLine)
{
dt.Columns.Add(rCol);
}
}
else
{
txtBoxFileOut.Text += rLine.ToString() + "\n";
}
}
}
dt.Columns.Remove("Column1");
for (int i = 0; i < dt.Rows.Count; i++)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
if (string.IsNullOrEmpty(dt.Rows[i][j].ToString()))
{
dt.Rows[i][j] = "0";
}
}
}
GridView1.DataSource = dt;
GridView1.DataBind();
After this the user should be able to select a row and display the data from that row in a chart.
Problem: I'm not able to read data from the cells I want, or to read from a "hardcoded" cell.
protected void GridView1_SelectedIndexChanged(object sender, EventArgs e) {
GridViewRow row = GridView1.SelectedRow;
txtOutputfield.Text = row.Cells[2].Text;
}
Please check your cell index. Is it correct? For example: the third column will have index "2" not "3"
And, if you use a control to store the data, you need to find that control:
txtOutputfield.Text =
row.Cells[2].FindControl('placeyourcontrolnamehere').Text;
For a specific Cell this worked fine
txtOutputfield.Text = GridView1.Rows[i].Cells[j].Text;

Categories