Issue with merging cells in OfficeOpenXml worksheet - c#

As you can see in the picture, ShiftLeaders row is merged, however, from the 4th to 7th row the values are dynamic(If there are more data more rows will be filled). Because of that, I can't be sure what row to assign on setters and merge those two rows. The current way is displaying the table correctly, the problem is with setters and operators rows which can't be merged. Any help is appreciated!
Shift Leaders is ok:
ws.Cells["A3:C3"].Value = "Shift Leaders";
ws.Cells["A3:C3"].Merge = true;
Setters row is not merging:
ws.Cells[largestLeaders + 4, 2].Value = "Setters";
ws.Cells[largestLeaders + 4, 2].Merge = true;
As well as Operators row:
ws.Cells[largestSetters + 4 + largestLeaders + 2, 2].Value = "Operators";
ws.Cells[largestSetters + 4 + largestLeaders + 2, 2].Merge = true;

it looks like you are using single cell instead of cell range. try with range:
int n = largestLeaders + 4;
string range = $"A{n}:C{n}";
ws.Cells[range].Value = "Setters";
ws.Cells[range].Merge = true;

Related

Simplest way to populate matrix with differing values in x and y?

I have a 3x3 matrix that I want to populate (may grow to 3x4 or 3x5 but not larger). Very simple with a dual for loop except that each row has a unique formula and each column has a unique column within the formula.
I started trying to create for loops, case statements, but ended up just brute force updating each cell.
Then I thought maybe some master crafter has some ideas. Is there any way to make this simpler:
myWorksheet.Cells[1, 1].Formula = "=ROUND(AVERAGE(B$2:B$" + counter + "), 3)";
myWorksheet.Cells[1, 2].Formula = "=ROUND(AVERAGE(C$2:C$" + counter + "), 3)";
myWorksheet.Cells[1, 3].Formula = "=ROUND(AVERAGE(D$2:D$" + counter + "), 3)";
myWorksheet.Cells[2, 1].Formula = "=MAX(B$2:B$" + counter + ")";
myWorksheet.Cells[2, 2].Formula = "=MAX(C$2:C$" + counter + ")";
myWorksheet.Cells[2, 3].Formula = "=MAX(D$2:D$" + counter + ")";
myWorksheet.Cells[3, 1].Formula = "=STDEV(B$2:B$" + counter + ")";
myWorksheet.Cells[3, 2].Formula = "=STDEV(C$2:C$" + counter + ")";
myWorksheet.Cells[3, 3].Formula = "=STDEV(D$2:D$" + counter + ")";
Your formula has three portions, the function name, the argument, and the closing. You can make a method that will create the formula to insert based on the cell's row and column coordinates.
public static string RenderFormula(int row, int column, int counter)
{
var stringBuilder = new StringBuilder();
stringBuilder.Append("=");
// part 1 - the function name
var methodName = row switch
{
1 => "ROUND(AVERAGE(",
2 => "MAX(",
3 => "STDEV(",
_ => throw new ArgumentException(nameof(row))
};
stringBuilder.Append(methodName);
// part 2 - the argument
char rangeColumnLetter = (char)('A' + column);
var range = $"{rangeColumnLetter}$2:{rangeColumnLetter}${counter}";
stringBuilder.Append(range);
// part 3 - the closing
var methodEnding = row switch
{
1 => "), 3)",
2 or 3 => ")",
_ => throw new ArgumentException(nameof(row))
};
stringBuilder.Append(methodEnding);
return stringBuilder.ToString();
}
In part one, you know which excel function to use based on the row number.
In part two, you add the column number to a capital "A" to get the new range column letter. This means that (column 1 + "A" = "B"). Add the value of counter into it.
In part three, you need to close the function's parentheses. Row 1 formulas have two closing parentheses with another argument in the middle, so account for it.
This uses StringBuilder to avoid a lot of wasteful concatenations.
Then just call the method to find out what the formula to insert is.
Console.WriteLine(RenderFormula(1, 1, 50));
Console.WriteLine(RenderFormula(2, 2, 50));
Console.WriteLine(RenderFormula(3, 3, 50));
// =ROUND(AVERAGE(B$2:B$50), 3)
// =MAX(C$2:C$50)
// =STDEV(D$2:D$50)

Minitab Automation and Skipping Columns

My main code is below:
Mtb.Application MtbApp = new Mtb.Application();
MtbApp.UserInterface.Visible = true;
MtbApp.UserInterface.DisplayAlerts = false;
Mtb.Project MtbProj = MtbApp.ActiveProject;
Mtb.Columns MtbColumns;
Mtb.Column MtbColumn1;
Double[] data1;
Hashtable htSingleColumn;
List<double> listSingleColumn;
int i = 1 ;
foreach (DictionaryEntry de in htDataTable)
{
htSingleColumn = (Hashtable)de.Value;
listSingleColumn = (List<double>)htSingleColumn["listSingleData"];
data1 = listSingleColumn.ToArray();
MtbColumns = MtbProj.ActiveWorksheet.Columns;
MtbColumn1 = MtbColumns.Add(null, null, i);
MtbColumn1.SetData(data1);
// strLowlim and strUpplim have no influence on this issue here
strCommand = "Capa C" + i+" 1;" + ((strLowlim == "NA") ? "" : (" Lspec " + strLowlim + ";")) +((strUpplim == "NA") ? "" : (" Uspec " + strUpplim + ";"))+ " Pooled; AMR; UnBiased; OBiased; Toler 6; Within; Percent; CStat.";
// The program is crashing here as a result of the columns not being created sequentially
MtbProj.ExecuteCommand(strCommand);
Mtb.Graph MtbGraph = MtbProj.Commands.Item(i).Outputs.Item(1).Graph;
MtbGraph.SaveAs("C:\\MyGraph" + DateTime.Now.ToString("yyyy-MM-dd HHmmss"), true, Mtb.MtbGraphFileTypes.GFPNGHighColor);
i++;
}
MtbApp.Quit();
When running this code (with the crashing section commented out), I get the following output:
It should look like this:
I am really puzzled about this result. The variable i is right, but what is affecting the column number?
I can't find much information on the Web about Minitab. I just read the start guide here.
This line is the problem.
MtbColumn1 = MtbColumns.Add(null, null, i);
The third parameter Quantity specifies the number of columns to add. On the first iteration of the loop, you add i = 1 column, but on the second iteration of the loop you add i = 2 columns. Each iteration of the loop will add an additional i columns, when what you really want is to add one column each time.
Change the line to:
MtbColumn1 = MtbColumns.Add();

Formula in Excel - Logarithmic Average

I need to implement this equation:
In c# it is pretty straightforward:
static double LogarithmicSummed(IReadOnlyList<double> values)
{
double outVal = 0;
for (int i = 0; i < values.Count; i++)
{
outVal = outVal + Math.Pow(10, values[i] / 10);
}
return 10 * Math.Log10(outVal);
}
I need to verify the data in an excel sheet where I print out the data programmatically. That is the raw data, my c# calculations on the raw data AND the excel formual that should match my c# calculations. I just do not know how to write the formula in excel.
I know the rows and columns where the data are and they are next to each other. So for example, if I needed the arithmetic average, ie:
I could print out for each row:
// If row = 1, startColumn = A, endColumn = D, noOfColumn = 4. This would print: =SUM(A1:D1)/4
mean[row] = #"=SUM(" + startColumn + row + ":" + endColumn + row + ")/" + noOfColumns;
What would I print out to match the first formula I wrote? Or what would I need to write in Excel?
without VBA:
Put your data in A1 through A10 and in B1 enter:
=10^(A1/10)
and copy down. Then in another cell enter:
=10*LOG10(SUM(B1:B10))
You can avoid the "helper" column (column B) by using:
=10*LOG10(SUMPRODUCT(10^((A1:A10)/10)))
If that's how you enter your formulas, then why not use the literal form of the sum? Ie use a for loop over the columns and fill in:
10*log(10^(A1/10)+10^(A2/10)+10^(A3/10)+10^(A4/10))

Convert text data into multidimensional array in C#:

I have a following string, with line breaks in a textfile:
Card No. Seq Account 1 Account 2 Account 3 Account 4 Customer Name Expiry Status
0100000184998 1 2500855884500 - - /NIRMAL PRADHAN 1302 Cold
0100000186936 1 - - - /RITA SHRESTHA 1302 Cold
0100000238562 1 2500211214500 - - /HARRY SHARMA 1301 Cold
0100000270755 0 1820823730100 - - /EXPRESS ACCOUNT 9999 Cold
0100000272629 0 1820833290100 - - - /ROMA MAHARJAN 1208 Cold
0100000272637 0 2510171014500 - - /NITIN KUMAR SHRESTHA 1208 Cold
0100000272645 0 1800505550100 - - - /DR HARI BHATTA 1208 Cold
Here,
Card No., Seq has fixed digits.
Account 1, Account 2, Account 3, Account 4 can have fixed digit
number or - or null.
Customer Name can have First Name, Last Name, Middle Name etc.
My desired result is:
array[0][0] = "0100000184998"
array[0][1] = "1"
array[0][2] = "2500855884500"
array[0][3] = " "
array[0][4] = "-"
array[0][6] = "NIRMAL PRADHAN "
array[1][0] = "0100000186936"
array[1][1] = "1"
array[1][3] = " "
array[1][4] = "-"
Here, What I tried is:
var sourceFile = txtProcessingFile.Text;
string contents = System.IO.File.ReadAllText(sourceFile);
var newarr = contents.Split(new char[]{ '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
.Select (x =>
x.Split(new char[]{ ' ' }, StringSplitOptions.RemoveEmptyEntries).ToArray()
).ToArray();
DataTable dt = new DataTable("NewDataTable");
dt.Columns.Add("CardNo");
dt.Columns.Add("SNo");
dt.Columns.Add("Account1");
and so on...
for (int row = 0; row < newarr.Length; row++)
{
for (int col = 0; col < newarr[col].Length; col++)
{
dt.Rows.Add(newarr[row]);
row++;
}
}
This works fine if data field is not empty and Customer name is only the first name or delimited.
But, here what I am trying to get is:
First Name, Middle Name or Last Name must be stored in the same
array element.
Account Number in the array element must left blank if it is blank.
How is it possible to store it correctly on the datatable ?
I suggest that you learn to use the TextFieldParser class. Yes, it's in the Microsoft.VisualBasic namespace, but you can use it from C#. That class lets you easily parse text files that have fixed field widths. See the article How to: Read From Fixed-width Text Files in Visual Basic for an example. Again, the sample is in Visual Basic, but it should be very easy to convert to C#.
If you are willing to make the compromise of not making a difference between - and null values in the account values, you may try this:
var sourceFile = txtProcessingFile.Text;
string[] contents = System.IO.File.ReadAllLines(sourceFile);
DataTable dt = new DataTable("NewDataTable");
dt.Columns.Add("CardNo");
dt.Columns.Add("SNo");
dt.Columns.Add("Account1");
dt.Columns.Add("Account2");
dt.Columns.Add("Account3");
dt.Columns.Add("Account4");
dt.Columns.Add("CustomerName");
dt.Columns.Add("Expiry");
dt.Columns.Add("Status");
for (int row = 2; row < contents.Length; row++)
{
var newRow = dt.NewRow();
var regEx = new Regex(#"([\w]*)");
var matches = regEx.Matches(contents[row].ToString())
.Cast<Match>()
.Where(m => !String.IsNullOrEmpty(m.Value))
.ToList();
var numbers = matches.Where(m => Regex.IsMatch(m.Value, #"^\d+$")).ToList();
var names = matches.Where(m => !Regex.IsMatch(m.Value, #"^\d+$")).ToList();
for (int i = 0; i < numbers.Count() - 1; i++)
{
newRow[i] = numbers.Skip(i).First();
}
newRow[newRow.ItemArray.Length - 2] = numbers.Last();
newRow[newRow.ItemArray.Length - 1] = names.Last();
newRow[newRow.ItemArray.Length - 3] = names.Take(names.Count() - 1).Aggregate<Match, string>("", (a, b) => a += " " + b.Value);
dt.Rows.Add(newRow);
}
To get around the names with a single space in them, you could try splitting on a double-space instead of a single space:
x.Split(new string[]{ " " }
This still won't fix the issue with columns that have no value in them. It appears that your text file has everything in a specific position. Seq is in position 16, Account 1 is in position 20, etc.
Once your lines are stored in newarr, you may just want to use String.Substring() with .Trim() to get the value in each column.

Count of text in RichtextBox (Line and Column)

I'm working on a code editor and I just want to know how to do codes in counting Lines and Columns in richtextbox. Particularly something like this one in actual code editor:
Let's just say count will transfer in a ListBox.
Is there a fast way I can do it?
You can do this :
//This to get lines number.
int index = richTextBox.SelectionStart;
int li = richTextBox.GetLineFromCharIndex(index);
// This to get columns number.
int firstChar = richTextBox.GetFirstCharIndexFromLine(li);
int col = index - firstChar;
Good luck!
This will do it, you just have to call the code inside a timer:
int line = 1 + richTextBox1.GetLineFromCharIndex(richTextBox1.GetFirstCharIndexOfCurrentLine());
int column = 1 + richTextBox1.SelectionStart - richTextBox1.GetFirstCharIndexOfCurrentLine();
label1.Text = "line: " + line.ToString() + ", column: " + column.ToString();

Categories

Resources