Workflow for Collection.Add() - c#

DataTable.Rows.Add() adds a row to the data table. However, how does it handle the underlying array?
When adding a single row at a time, does it rebuild the entire array with each row added?
Or is it able to simply modify the existing array without any hit on performance?
I am wondering if it’s better to determine the size of the array before filling it with data, or if somehow the data table is able to modify the collection without (behind the scenes) copying and moving things.
It’s my understanding that to adjust an array you have to redefine it and move previously existing data into the new structure.
My question is what is the work flow for the Collection.Add() method?

Take a look using software like DotPeek:
DataTable.Rows.Add(DataRow row)
{
this.table.AddRow(row, -1);
}
which calls:
DataTable.AddRow(DataRow row, int proposedID)
{
this.InsertRow(row, proposedID, -1);
}
which calls:
DataTable.InsertRow(DataRow row, int proposedID, int pos)
{
this.InsertRow(row, (long) proposedID, pos, true);
}
which calls:
DataTable.InsertRow(DataRow row, long proposedID, int pos, bool fireEvent)
{
Exception deferredException = (Exception) null;
if (row == null)
throw ExceptionBuilder.ArgumentNull("row");
if (row.Table != this)
throw ExceptionBuilder.RowAlreadyInOtherCollection();
if (row.rowID != -1L)
throw ExceptionBuilder.RowAlreadyInTheCollection();
row.BeginEdit();
int proposedRecord = row.tempRecord;
row.tempRecord = -1;
if (proposedID == -1L)
proposedID = this.nextRowID;
bool flag;
if (flag = this.nextRowID <= proposedID)
this.nextRowID = checked (proposedID + 1L);
try
{
try
{
row.rowID = proposedID;
this.SetNewRecordWorker(row, proposedRecord, DataRowAction.Add, false, false, pos, fireEvent, out deferredException);
}
catch
{
if (flag && this.nextRowID == proposedID + 1L)
this.nextRowID = proposedID;
row.rowID = -1L;
row.tempRecord = proposedRecord;
throw;
}
if (deferredException != null)
throw deferredException;
if (!this.EnforceConstraints || this.inLoad)
return;
int count = this.columnCollection.Count;
for (int index = 0; index < count; ++index)
{
DataColumn dataColumn = this.columnCollection[index];
if (dataColumn.Computed)
dataColumn.CheckColumnConstraint(row, DataRowAction.Add);
}
}
finally
{
row.ResetLastChangedColumn();
}
}
which calls:
DataTable.SetNewRecordWorker(DataRow row, int proposedRecord, DataRowAction action, bool isInMerge, bool suppressEnsurePropertyChanged, int position, bool fireEvent, out Exception deferredException)
{
deferredException = (Exception) null;
if (row.tempRecord != proposedRecord)
{
if (!this.inDataLoad)
{
row.CheckInTable();
this.CheckNotModifying(row);
}
if (proposedRecord == row.newRecord)
{
if (!isInMerge)
return;
this.RaiseRowChanged((DataRowChangeEventArgs) null, row, action);
return;
}
else
row.tempRecord = proposedRecord;
}
DataRowChangeEventArgs args = (DataRowChangeEventArgs) null;
try
{
row._action = action;
args = this.RaiseRowChanging((DataRowChangeEventArgs) null, row, action, fireEvent);
}
catch
{
row.tempRecord = -1;
throw;
}
finally
{
row._action = DataRowAction.Nothing;
}
row.tempRecord = -1;
int record = row.newRecord;
int num = proposedRecord != -1 ? proposedRecord : (row.RowState != DataRowState.Unchanged ? row.oldRecord : -1);
if (action == DataRowAction.Add)
{
if (position == -1)
this.Rows.ArrayAdd(row);
else
this.Rows.ArrayInsert(row, position);
}
List<DataRow> cachedRows = (List<DataRow>) null;
if ((action == DataRowAction.Delete || action == DataRowAction.Change) && (this.dependentColumns != null && this.dependentColumns.Count > 0))
{
cachedRows = new List<DataRow>();
for (int index = 0; index < this.ParentRelations.Count; ++index)
{
DataRelation relation = this.ParentRelations[index];
if (relation.ChildTable == row.Table)
cachedRows.InsertRange(cachedRows.Count, (IEnumerable<DataRow>) row.GetParentRows(relation));
}
for (int index = 0; index < this.ChildRelations.Count; ++index)
{
DataRelation relation = this.ChildRelations[index];
if (relation.ParentTable == row.Table)
cachedRows.InsertRange(cachedRows.Count, (IEnumerable<DataRow>) row.GetChildRows(relation));
}
}
if (!suppressEnsurePropertyChanged && !row.HasPropertyChanged && (row.newRecord != proposedRecord && -1 != proposedRecord) && -1 != row.newRecord)
{
row.LastChangedColumn = (DataColumn) null;
row.LastChangedColumn = (DataColumn) null;
}
if (this.LiveIndexes.Count != 0)
{
if (-1 == record && -1 != proposedRecord && (-1 != row.oldRecord && proposedRecord != row.oldRecord))
record = row.oldRecord;
DataViewRowState recordState1 = row.GetRecordState(record);
DataViewRowState recordState2 = row.GetRecordState(num);
row.newRecord = proposedRecord;
if (proposedRecord != -1)
this.recordManager[proposedRecord] = row;
DataViewRowState recordState3 = row.GetRecordState(record);
DataViewRowState recordState4 = row.GetRecordState(num);
this.RecordStateChanged(record, recordState1, recordState3, num, recordState2, recordState4);
}
else
{
row.newRecord = proposedRecord;
if (proposedRecord != -1)
this.recordManager[proposedRecord] = row;
}
row.ResetLastChangedColumn();
if (-1 != record && record != row.oldRecord && (record != row.tempRecord && record != row.newRecord) && row == this.recordManager[record])
this.FreeRecord(ref record);
if (row.RowState == DataRowState.Detached && row.rowID != -1L)
this.RemoveRow(row, false);
if (this.dependentColumns != null)
{
if (this.dependentColumns.Count > 0)
{
try
{
this.EvaluateExpressions(row, action, cachedRows);
}
catch (Exception ex)
{
if (action != DataRowAction.Add)
throw ex;
deferredException = ex;
}
}
}
try
{
if (!fireEvent)
return;
this.RaiseRowChanged(args, row, action);
}
catch (Exception ex)
{
if (!ADP.IsCatchableExceptionType(ex))
throw;
else
ExceptionBuilder.TraceExceptionWithoutRethrow(ex);
}
}
which calls one of those:
DataRowCollection.ArrayAdd(DataRow row)
{
row.RBTreeNodeId = this.list.Add(row);
}
DataRowCollection.ArrayInsert(DataRow row, int pos)
{
row.RBTreeNodeId = this.list.Insert(pos, row);
}
this.list is of type DataRowCollection.DataRowTree, derived from RBTree<DataRow>.
private sealed class DataRowTree : RBTree<DataRow>
RBTree<DataRow> and RBTreeNodeId allows us to conclude that a Red-Black tree is being used!

Related

Invalid Data in Excel File. Index was outside the bounds of the array.C#

Cant find answer in any of the suggestions.I am trying to upload an excel file to the postgre Db.
Here is the C# code :
public static List<Common.Transactions.TransactionDetail> GetTransactionDetails(string path)
{
if (!File.Exists(path))
{
return null;
}
var transactionDetails = new List<Common.Transactions.TransactionDetail>();
foreach (var sheet in Workbook.Worksheets(path))
{
int officeId = 0;
foreach (var row in sheet.Rows.Skip(1))
{
var td = new Common.Transactions.TransactionDetail
{
GlAccountId = Core.GlAccounts.GetGlAcccountId(row.Cells[1]?.Text),
AccountNumberId = Deposit.AccountHolders.GetAccountNumberId(row.Cells[2]?.Text),
ShareAccountId = Core.ShareAccounts.GetShareAccountId(row.Cells[3]?.Text),
LoanId = Loan.LoanAccounts.GetLoanId(row.Cells[4]?.Text),
Debit = row.Cells[5]?.Text.ToDecimal(),
Credit = row.Cells[6]?.Text.ToDecimal(),
StatementReference = row.Cells[7]?.Text
};
if (row.Cells[7] != null)
{
td.OfficeId = Office.Offices.GetOfficeIdByCode(row.Cells[7]?.Text);
officeId = Office.Offices.GetOfficeIdByCode(row.Cells[7]?.Text);
}
if (td.AccountNumberId == 0)
{
td.AccountNumberId = null;
}
if (td.LoanId == 0)
{
td.LoanId = null;
}
if (td.ShareAccountId == 0)
{
td.ShareAccountId = null;
}
if (row.Cells[0] != null)
{
td.AccountName = row.Cells[0].Text;
}
if (row.Cells[1] != null && string.IsNullOrWhiteSpace(td.AccountName))
{
td.AccountName = row.Cells[1].Text;
}
if (row.Cells[2] != null && string.IsNullOrWhiteSpace(td.AccountName))
{
td.AccountName = row.Cells[2].Text;
}
if (row.Cells[3] != null && string.IsNullOrWhiteSpace(td.AccountName))
{
td.AccountName = row.Cells[3].Text;
}
#region OfficeId
if (td.AccountNumberId != null)
{
officeId = Deposit.AccountHolders.GetAccountOfficeId(td.AccountNumberId.ToLong());
}
if (td.LoanId != null)
{
officeId = Loan.LoanGrant.GetAccountOfficeId(td.LoanId.ToLong());
}
if (td.ShareAccountId != null)
{
officeId = Core.ShareAccounts.GetAccountOfficeId(td.ShareAccountId.ToLong());
}
#endregion
td.OfficeId = officeId != 0 ? officeId : SessionHelper.GetOfficeId();
td.OfficeCode = Office.Offices.GetOfficeCode(officeId);
transactionDetails.Add(td);
}
}
foreach (var detail in transactionDetails)
{
if (detail.Debit.ToDecimal() > 0 && detail.Credit > 0)
{
throw new TransactionDetailException(
$#"Invalid transaction. Either debit or credit should be null for '{detail.AccountName}'.");
}
if (detail.AccountNumberId > 0)
{
if (detail.Debit.ToDecimal() > 0)
{
if (detail.Debit > Deposit.AccountHolders.GetDepositAccountBalance(detail.AccountNumberId.ToLong()))
{
throw new TransactionDetailException(
$#"Insufficient balance in account '{detail.AccountName}'.");
}
}
detail.GlAccountId = Deposit.AccountHolders.GetGlAccountId(detail.AccountNumberId);
}
if (detail.ShareAccountId > 0)
{
if (detail.Debit.ToDecimal() > 0)
{
if (detail.Debit > Core.ShareAccounts.GetShareBalance(detail.ShareAccountId.ToLong()))
{
throw new TransactionDetailException(
$#"Insufficient balance in account '{detail.AccountName}'.");
}
}
detail.GlAccountId = Core.ShareAccounts.GetGlAccountId(detail.ShareAccountId.ToLong());
}
if (detail.LoanId > 0)
{
if (detail.Credit.ToDecimal() > 0)
{
if (detail.Credit > Loan.LoanAccounts.GetLoanCollectionBalance(detail.LoanId.ToLong(), Core.DateConversion.GetCurrentServerDate()))
{
throw new TransactionDetailException(
$#"Insufficient balance in account '{detail.AccountName}'.");
}
}
detail.GlAccountId = Loan.LoanGrant.GetLoanTransactionGLAccountId(detail.LoanId.ToLong());
}
detail.AuditUserId = Common.Helpers.SessionHelper.GetUserId();
detail.AccountNumberId = detail.AccountNumberId <= 0 ? null : detail.AccountNumberId;
detail.LoanId = detail.LoanId <= 0 ? null : detail.LoanId;
detail.ShareAccountId = detail.ShareAccountId <= 0 ? null : detail.ShareAccountId;
detail.EnableDeleteButton = true;
if (detail.GlAccountId == 0)
{
throw new TransactionDetailException($#"{detail.AccountName} is not a valid account.");
}
}
return transactionDetails;
}
}
I get error Index was outside the bounds of array.Invalid excel data.
My excel data
Gl Account Deposit A/C Share A/C Loan A/C Debit Credit Statement Reference
Loss Recovery Fund 0 1000 uploaded from excel
Risk Coverage Fund 0 1106 uploaded from excel
Ok solved it..The problem was with my excel data.
I was looking for row[7] which didnt exist.Had to add one column to the
excel file and it worked.
The exception was here in the code :
if (row.Cells[7] != null)
{
td.OfficeId = Office.Offices.GetOfficeIdByCode(row.Cells[7]?.Text);
officeId = Office.Offices.GetOfficeIdByCode(row.Cells[7]?.Text);
}
Thanks #LocEngineer Sir for your time.

how to bind multiple Node in RadTreeView

Question:
How do i bind multiple Nodes in RadTreeView
This is my code:
if (lblCategory != null && lblCategory.Text != string.Empty && rtCategory != null)
{
string[] tree = lblCategory.Text.Split(',');
for (int i = 0; i < tree.Length; i++)
{
foreach (RadTreeNode t in rtCategory.Nodes)
{
if (t.Value == tree[i])
{
t.Selected = true;
}
}
}
rtCategory.ExpandAllNodes();
}
if (lblCategory != null && lblCategory.Text != string.Empty && rtCategory != null)
{
string[] tree = lblCategory.Text.Split(',');
for (int i = 0; i < tree.Length; i++)
{
foreach (RadTreeNode t in rtCategory.GetAllNodes())
{
if (t.Value == tree[i])
{
t.Selected = true;
}
}
}
rtCategory.ExpandAllNodes();
}
Use GetAllNodes() instead of Node in foreach condition

WPF C# - DataGrid select item on user keypress

I made this function to select the item on DataGrid on user keypress. If the user key is "A" it will select the first item where username starts with letter "A". If the user key is again "A" it will select the next item where username starts with letter "A" and so on. The function works great, but what I want is when there are no more items where username starts with "A" to start over (select the first item), it currently remains on the last item where username start with letter "A".
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
break;
}
}
lastKey = e.Key;
}
Update (with solution):
Inspired by Danielle's idea, I have changed my code like below, works like a charm.
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
Func<object, bool> itemCompareMethod = (item) =>
{
Account account = item as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
return true;
}
return false;
};
lastFoundIndex = FindDataGridRecordWithinRange(dataGrid, lastFoundIndex, dataGrid.Items.Count, itemCompareMethod);
if (lastFoundIndex == -1)
{
lastFoundIndex = FindDataGridRecordWithinRange(dataGrid, 0, dataGrid.Items.Count, itemCompareMethod);
}
if (lastFoundIndex != -1)
{
dataGrid.ScrollIntoView(dataGrid.Items[lastFoundIndex]);
dataGrid.SelectedIndex = lastFoundIndex;
}
if (lastFoundIndex == -1)
{
lastFoundIndex = 0;
dataGrid.SelectedItem = null;
}
lastKey = e.Key;
}
private static int FindDataGridRecordWithinRange(DataGrid dataGrid, int min, int max, Func<object, bool> itemCompareMethod)
{
for (int i = min; i < max; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
if (itemCompareMethod(dataGrid.Items[i]))
{
return i;
}
}
return -1;
}
The solution you wound up with is needlessly complex and checks rows it doesn't need to check. The two static variables to maintain state are not needed either. Try this instead:
public void MainGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if (dataGrid.Items.Count == 0 || e.Key < Key.A || e.Key > Key.Z)
{
return;
}
Func<object, bool> doesItemStartWithChar = (item) =>
{
Account account = item as Account;
return account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.InvariantCulture);
};
int currentIndex = dataGrid.SelectedIndex;
int foundIndex = currentIndex;
// Search in following rows
foundIndex = FindMatchingItemInRange(dataGrid, currentIndex, dataGrid.Items.Count - 1, doesItemStartWithChar);
// If not found, search again in the previous rows
if (foundIndex == -1)
{
foundIndex = FindMatchingItemInRange(dataGrid, 0, currentIndex - 1, doesItemStartWithChar);
}
if (foundIndex > -1) // Found
{
dataGrid.ScrollIntoView(dataGrid.Items[foundIndex]);
dataGrid.SelectedIndex = foundIndex;
}
}
private static int FindMatchingItemInRange(DataGrid dataGrid, int min, int max, Func<object, bool> doesItemStartWithChar)
{
for (int i = min; i <= max; i++)
{
if (dataGrid.SelectedIndex == i) // Skip the current selection
{
continue;
}
if (doesItemStartWithChar(dataGrid.Items[i])) // If current item matches the string, return index
{
return i;
}
}
return -1;
}
Regarding your comment, just add this check:
if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
{
return;
}
You could extract your for-loop into a separate method that determines if another item was found.
public int FindRecordWithinRange(DataGrid dataGrid, int min, int max)
{
for (int i = min; i < max; i++)
{
if (dataGrid.SelectedIndex == i)
continue;
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
return i;
}
}
return -1;
}
And call into it using something like this:
lastFoundIndex = FindRecordWithinRange(dataGrid, lastFoundIndex, dataGrid.Items.Count);
if (lastFoundIndex == -1)
lastFoundIndex = FindRecordWithinRange(dataGrid, 0, dataGrid.Items.Count);
if (lastFoundIndex == -1)
dataGrid.SelectedItem = null;
This would basically attempt to search the list from the beginning and would also handle the case where no items were found by clearing out the selection. You might also want to scroll to the beginning in this case, handling at this point is dependent on what you want to do.
Another thing you might want to do here is extract your ScrollIntoView and Selection logic and handle that after the index has been determined.
if i change my function like below, it will stay 2 times on the last item for letter "A" before going to the first item with letter "A" (assuming the user key is still "A").
private static Key lastKey;
private static int lastFoundIndex = 0;
public static void AccountsDataGrid_SearchByKey(object sender, KeyEventArgs e)
{
DataGrid dataGrid = sender as DataGrid;
if ((dataGrid.Items.Count == 0) && !(e.Key >= Key.A && e.Key <= Key.Z))
{
return;
}
if ((lastKey != e.Key) || (lastFoundIndex == dataGrid.Items.Count - 1))
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if ((lastFoundIndex > 0) && (lastFoundIndex == i))
{
lastFoundIndex = 0;
}
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
break;
}
}
lastKey = e.Key;
}
Your code says that to start searching again from the beginning, the lastFoundIndex should be equal to dataGrid.Items.Count - 1 (supposing the same key was pressed again).
But your last found Account may be not at the end of the Items collection, so that the lastFoundIndex was not set to dataGrid.Items.Count - 1 when the previous key was pressed. In this case your condition to start over again is not fulfilled.
Try changing the last-found checking and the "for" loop like this:
bool found = false;
bool lastFound = true;
if (lastKey != e.Key || lastFound)
{
lastFoundIndex = 0;
}
for (int i = lastFoundIndex; i < dataGrid.Items.Count; i++)
{
if (dataGrid.SelectedIndex == i)
{
continue;
}
Account account = dataGrid.Items[i] as Account;
if (account.Username.StartsWith(e.Key.ToString(), true, CultureInfo.CurrentCulture))
{
if (!found)
{
dataGrid.ScrollIntoView(account);
dataGrid.SelectedItem = account;
lastFoundIndex = i;
found = true;
}
else
{
lastFound = false;
break;
}
}
}
Basically it will try to find one more item to see if it was the last match or not.

Handle merged cells in Epplus Excel conversion to HTML

I'm using Epplus to render an Excel spreadsheet into HTML. So far it's going very, very well, except for one thing... spanning merged cells. I just can't seem to get the logic right. I thought I would throw it out there to see how the community would deal with it. Here is my code so far.
public String ParseExcelStamps(String FileName)
{
FileInfo theFile = new FileInfo(FileName);
String html = "";
using (ExcelPackage xlPackage = new ExcelPackage(theFile))
{
var workbook = xlPackage.Workbook;
if (workbook != null)
{
for (int j = 1; j <= workbook.Worksheets.Count; j++)
{
Tab tab = new Tab();
html+= "<table style='border-collapse: collapse;font-family:arial;'><tbody>";
var worksheet = workbook.Worksheets[j];
tab.Title = worksheet.Name;
if (worksheet.Dimension == null) { continue; }
int rowCount = 0;
int maxColumnNumber = worksheet.Dimension.End.Column;
var convertedRecords = new List<List<string>>(worksheet.Dimension.End.Row);
var excelRows = worksheet.Cells.GroupBy(c => c.Start.Row).ToList();
excelRows.ForEach(r =>
{
rowCount++;
html += String.Format("<tr>");
var currentRecord = new List<string>(maxColumnNumber);
var cells = r.OrderBy(cell => cell.Start.Column).ToList();
Double rowHeight = worksheet.Row(rowCount).Height;
for (int i = 1; i <= maxColumnNumber; i++)
{
var currentCell = cells.Where(c => c.Start.Column == i).FirstOrDefault();
//look aheads for colspan and rowspan
ExcelRangeBase previousCellAbove = null;
ExcelRangeBase previousCell = null;
ExcelRangeBase nextCell = null;
ExcelRangeBase nextCellBelow = null;
try { previousCellAbove = worksheet.Cells[rowCount-1, i]; }catch (Exception) { }
try { previousCell = worksheet.Cells[rowCount, (i - 1)]; }catch (Exception) { }
try { nextCell = worksheet.Cells[rowCount, (i + 1)]; }catch (Exception) { }
try { nextCellBelow = worksheet.Cells[rowCount+1, i]; }catch (Exception) { }
if ((previousCell != null) && (previousCell.Merge) && (currentCell != null) && (currentCell.Merge)){continue;}
if ((previousCellAbove != null) && (previousCellAbove.Merge) && (currentCell != null)) {continue; }
if (currentCell == null)
{
html += String.Format("<td>{0}</td>", String.Empty);
}
else
{
int colSpan = 1;
int rowSpan = 1;
if ((nextCell != null) && (nextCell.Merge) && (currentCell.Merge)) {
colSpan = 2;
// Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCell.Address));
}
if ((nextCellBelow != null) && (nextCellBelow.Merge) && (currentCell.Merge)) {
Console.WriteLine(String.Format("{0} - {1}", currentCell.Address, nextCellBelow.Address));
}
html += String.Format("<td colspan={0} rowspan={1}>{2}</td>", colSpan, rowSpan, currentCell.Value);
}
}
html += String.Format("</tr>");
});
html += "</tbody></table>";
}//worksheet loop
}
}
return html;
}
As far as I can tell this is exactly what you need. What you were missing was the MergedCells property on the worksheet which lists all merged cells in the sheet.
My code handles row spans, column spans, and both at the same time. I did some testing with a spreadsheet that included both row, column and row/column spanning. In all cases they worked perfectly.
Code
int colSpan = 1;
int rowSpan = 1;
//check if this is the start of a merged cell
ExcelAddress cellAddress = new ExcelAddress(currentCell.Address);
var mCellsResult = (from c in worksheet.MergedCells
let addr = new ExcelAddress(c)
where cellAddress.Start.Row >= addr.Start.Row &&
cellAddress.End.Row <= addr.End.Row &&
cellAddress.Start.Column >= addr.Start.Column &&
cellAddress.End.Column <= addr.End.Column
select addr);
if (mCellsResult.Count() >0)
{
var mCells = mCellsResult.First();
//if the cell and the merged cell do not share a common start address then skip this cell as it's already been covered by a previous item
if (mCells.Start.Address != cellAddress.Start.Address)
continue;
if(mCells.Start.Column != mCells.End.Column) {
colSpan += mCells.End.Column - mCells.Start.Column;
}
if (mCells.Start.Row != mCells.End.Row)
{
rowSpan += mCells.End.Row - mCells.Start.Row;
}
}
//load up data
html += String.Format("<td colspan={0} rowspan={1}>{2}</td>", colSpan, rowSpan, currentCell.Value);

Assigning values from a cell to another

int rowsCount = 0;
//This checks to see that both textbox for items and subitems do not gain focus at the same time
if (textBoxSubItems.Text != string.Empty)
txtItems.Enabled = false;
else
txtItems.Enabled = true;
if (comboBoxItems.SelectedItem != null)
{
int idx = dataGridViewTimesheet.Rows.Add();
DataGridViewRow row = dataGridViewTimesheet.Rows[idx];
row.Cells["items"].Value = comboBoxItems.SelectedItem.ToString() + "-" + textBoxSubItems.Text;
row.Cells["fromTime"].Value = DateTime.Now.ToLongTimeString();
row.Cells["toTime"].Value = null;
row.Cells["duration"].Value = null;
row.Cells["subTotal"].Value = null;
// row.Cells["comments"].Value = "1";
}
else
MessageBox.Show("Please select an item");
string strGetColumnValue;
if (dataGridViewTimesheet.Rows.Count != 0)
rowsCount = dataGridViewTimesheet.Rows.Count;
else
MessageBox.Show("No row in the datagridview");
while (dataGridViewTimesheet.Rows.Count > 0)
{
try
{
if (dataGridViewTimesheet.CurrentRow != null)
for (int counter = 0; counter < dataGridViewTimesheet.Columns.Count; counter++)
{
if (dataGridViewTimesheet.Columns[counter].Index == 3)
{
strGetColumnValue = dataGridViewTimesheet.Rows[rowsCount].Cells[counter].Value.ToString();
dataGridViewTimesheet.Rows[rowsCount - 1].Cells[3].Value = strGetColumnValue;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
Please i have 6 columns in a datagridview, the rows are added dynamically. What i want is when rows are more than one in the datagridview it should assign the value of the second column on the current(the last row created) row to the third column of the previous row. How do I achieve this.
Try this kind of thing
int count =1;
foreach (DataGridRow row in dataGridViewTimesheet.Rows)
{
if (count % 2 == 0)
{
string secondColumn = dataGridViewTimesheet.Rows[count -1].Cells[1].ToString();
dataGridViewTimesheet.Rows[count].Cells[2].Value = secondColumn;
}
count++;
}

Categories

Resources