How can I get Excel cell contents to right justify using C#? - c#

A portion of my dynamically-created spreadsheet looks like this:
At first, both currency values (the second and third rows in each block of four rows inside the bounded column) were (by default) offset a little from the right, as you can see the second currency value / third row is now.
Thus, the two currency rows were not quite aligning with the first (int) row and the last (%) row.
I want them all to hug the vertical border on the right side of the block, like the int and the % rows.
I experimented by adding this code for the first currency value / second row, to attempt to justify it, hoping it would justify right:
monthPurchasesCell.HorizontalAlignment = XlVAlign.xlVAlignJustify;
...but, as you can see in the screen shot snippet, it does the opposite (justifies left). There is no "xlVAlignJustifyRight" or so.
In context, the code to display the four rows in a month block is:
private void AddMonthData(int packages, decimal purchases, decimal avgPrice, double percent, int colToPopulate)
{
var monthPackagesCell = (Range)_xlSheet.Cells[_curDescriptionTopRow, colToPopulate];
monthPackagesCell.Value2 = packages.ToString("N0", CultureInfo.CurrentCulture);
var monthPurchasesCell = (Range)_xlSheet.Cells[_curDescriptionTopRow + 1, colToPopulate];
monthPurchasesCell.Value2 = purchases.ToString("C", CultureInfo.CurrentCulture);
monthPurchasesCell.HorizontalAlignment = XlVAlign.xlVAlignJustify;
var monthAvgPriceCell = (Range)_xlSheet.Cells[_curDescriptionTopRow + 2, colToPopulate];
monthAvgPriceCell.Value2 = avgPrice.ToString("C", CultureInfo.CurrentCulture);
var monthPercentOfTotalCell = (Range)_xlSheet.Cells[_curDescriptionTopRow + 3, colToPopulate];
monthPercentOfTotalCell.Value2 = percent.ToString("P", CultureInfo.CurrentCulture);
}
How can I justify the currency values to the right?

I think you have to use XlHAlign for horizontal alignments.

Related

How to sum only one textbox value and show result in label in c# [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 4 years ago.
Improve this question
The question could be duplicate but my problem is totally different.
I have a one textbox and one label.
Example: label text is already exist with number like 450 Now I want to add number in textbox and the textbox value should be sum in 450 + 30 = 480 where 30 is textbox value.
what I have tried:
lbl_TotalAmount.Text = lbl_TotalAmount.Text + txt_DeliveryCharges.Text;
The above Result is: 45030
Another Code I Have tried:
double total = Convert.ToDouble(lbl_TotalAmount.Text);
double charges = Convert.ToDouble(txt_DeliveryCharges.Text);
double sum = total + charges;
lbl_TotalAmount.Text = String.Format(sum.ToString("0.00"));
The above code is going to sum every value that I put in the textbox and also when I remove one word the number is sum every time.
Please give me best solution I tried many solution to solve this but unable to do this.
Sorry for bad English.
The above code is going to sum every value that I put in the textbox and also when I remove one word the number is sum every time.
That's most likely because you're calling your code inside the TextChanged or the KeyPress events of the textbox; this means that every time you modify anything in your textbox, your code will fire and make the sum.
Instead, add a button and put your code inside its Click event, or if you want the sum to respond to every keypress while respecting your original value, save your value in a variable and use it to calculate the sum.
'Declare a variable at form level
Dim originalValue as Double
'Code where you put your value in a label, put it also in a variable
lbl_TotalAmount.text = 450
originalValue = 450
'Modify your code to use the original value instead of the label
double charges = Convert.ToDouble(txt_DeliveryCharges.Text);
double sum = originalValue + charges;
lbl_TotalAmount.Text = String.Format(sum.ToString("0.00"));
Your strings need to be converted (parsed) to doubles (since they are representing monetary values), but you need to be sure that you're not trying to parse something that can't be converted. TryParse() evaluates to true (or false if the parse fails), so you can avoid a possible exception.
Additionally, you've stated in comments that you want this to update as the text box is updated, so you'll need a variable that is out of scope to keep the total separated from the calculation. I'm going to work from the assumption that this is a shopping cart, or something like that. In that case, a List<> would be an obvious way to store the values of the items in the cart.
Try this:
using System;
using System.Collections.Generic; //required for List<>
namespace WidowsFormsApplication
{
public class ShoppingCart
{
List<double> shoppingCart = new List<double>();
protected void AddItemToCart()
{
shoppingCart.Add(450);
}
protected void UpdateShoppingCart()
{
double total = 0;
foreach (double item in shoppingCart) //calculate total of shoppingCart
{
total += item;
}
if (Double.TryParse(txt_DeliveryCharges.Text, out double charges))
{
total += charges; //add charges without altering shoppingCart
lbl_TotalAmount.Text = String.Format("{0:0.00}", total);
}
}
}
}
lbl_TotalAmount.Text = lbl_TotalAmount.Text + txt_DeliveryCharges.Text;
lbl_TotalAmount.Text and txt_DeliveryCharges.Text are text fields. You cannot do arithmetic on text fields. You have to convert to number, do the arithmetic then convert back
var charge = Int32.Parse(txt_DeliveryCharges.Text);
var total = Int32.Parse(lbl_TotalAmount.Text);
var newTotal = charge + total;
lbl_TotalAmount.Text = newTotal.ToString();
what you are doing is string concatenation
Not a sum of two numbers, You have to convert your strings to int first
here is how you can do that
int x = 0, y = 0;
if (Int32.TryParse(lbl_TotalAmount.Text out x) && Int32.TryParse(txt_DeliveryCharges.Text, out y))
{
// you know that the parsing attempt
// was successful
lbl_TotalAmount.Text = x + y;
}
yourlabel.Text = ""+ (Int32.Parse(yourlabel.Text)+Int.Parse(your textbox.Text));
or
yourlabel.Text = ""+(Double.Parse(yourlabel.Text)+Double.Parse(yourtextbox.Text));
are you using a double? only need that for decimal numbers that are super precise. whole numbers, use int... if you're using it to do money you want to use Decimal, but it depends on the situation.

X scale gets messed up when adding series with different numbers of data points to chart [duplicate]

I try to draw Chart via C# with table as picture.
However, as you can see A4 data in date: 7 and 8/6 should stay with same 7 and 8/6 X-Axis, abnormal here all of them left to 5 & 6/6 X-Axis. Could you help me to fix it.
for (int i = 0; i < 14; i++)
{
string productname = dataGridView1.Rows[i].Cells[0].Value.ToString();
string datetime = dataGridView1.Rows[i].Cells[2].Value.ToString();
int para = Convert.ToInt16(dataGridView1.Rows[i].Cells[1].Value);
if (chart_dashboard.Series.IndexOf(productname) != -1)
{
chart_dashboard.Series[productname].Points.AddXY(datetime, para);
chart_dashboard.ChartAreas[0].AxisX.Interval = 1;
}
else
{
chart_dashboard.Series.Add(productname);
chart_dashboard.Series[productname].Points.AddXY(datetime, para);
chart_dashboard.ChartAreas[0].AxisX.Interval = 1;
}
}
A common mistake.
string datetime = dataGridView1.Rows[i].Cells[2].Value.ToString();
This is wrong! If you add the x-values as strings they all are added as 0 and the Series can't align them to the proper slots on the X-Axis. So they get added from left to right sequentially..
Instead simply add the x-values as the DateTimes they are supposed to be!
So if the Cells contain DateTime values use:
DateTime datetime = (DateTime) dataGridView1.Rows[i].Cells[2].Value;
If they don't, convert them to DateTime
DateTime datetime = Convert.ToDateTime(dataGridView1.Rows[i].Cells[2].Value);
To control the x-values type set the XValueType for each series:
chart_dashboard.Series[yourSeries].XValueType = ChartValueType.DateTime;
To control the way the axis labels are displayed set their formatting:
chart_dashboard[ChartAreas[0].AxisX.LabelStyle.Format = someDateTimeFormatString;
To create a string like "Week 1" you would
set the XValueType to int16
add the x-value as the week numbers
format it like ..axis.LabelStyle.Format = "Week #0";
To extract the number from your data split by space and Convert.ToInt16 !
If one really needs to insert sparse x-values as strings one would have to insert a dummy DataPoint at each gap in a series.
Creating a dummy DataPoint is simple:
DataPoint dp = new DataPoint() { IsEmpty = true};
But knowing where the gaps are in advance is the challenge! The 'best' way is to go over the data and filling in the before adding the points. Or go over it later and instead of adding, inserting the dummys at the gaps. Both is a lot more trouble than getting the data right in the first place!

how can i calculated values after Worksheet.Calculate()?

i tried Trial version of Gembox.SpreadSheet.
when i Get Cells[,].value by for() or Foreach().
so i think after Calculate() & get Cell[].value, but that way just take same time,too.
it take re-Calculate when i Get Cell[].value.
workSheet.Calcuate(); <- after this, values are Calculated, am i right?
for( int i =0; i <worksheet.GetUsedCellRange(true).LastRowIndex+1;++i)
{
~~~~for Iteration~~~
var value = workSheet.Cells[i,j].Value; <- re-Calcuate value(?)
}
so here is a Question.
Can i Get calculated values? or you guys know pre-Calculate function or Get more Speed?
Unfortunate, I'm not sure what exactly you're asking, can you please try reformulating your question a bit so that it's easier to understand it?
Nevertheless, here is some information which I hope you'll find useful.
To iterate through all cells, you should use one of the following:
1.
foreach (ExcelRow row in workSheet.Rows)
{
foreach (ExcelCell cell in row.AllocatedCells)
{
var value = cell.Value;
// ...
}
}
2.
for (CellRangeEnumerator enumerator = workSheet.Cells.GetReadEnumerator(); enumerator.MoveNext(); )
{
ExcelCell cell = enumerator.Current;
var value = cell.Value;
// ...
}
3.
for (int r = 0, rCount = workSheet.Rows.Count; r < rCount; ++r)
{
for (int c = 0, cCount = workSheet.CalculateMaxUsedColumns(); c < cCount; ++c)
{
var value = workSheet.Cells[r, c].Value;
// ...
}
}
I believe all of them will have pretty much the same performances.
However, depending on the spreadsheet's content this last one could end up a bit slower. This is because it does not exclusively iterate only through allocated cells.
So for instance, let say you have a spreadsheet which has 2 rows. The first row is empty, it has no data, and the second row has 3 cells. Now if you use 1. or 2. approach then you will iterate only through those 3 cells in the second row, but if you use 3. approach then you will iterate through 3 cells in the first row (which previously were not allocated and now they are because we accessed them) and then through 3 cells in the second row.
Now regarding the calculation, note that when you save the file with some Excel application it will save the last calculated formula values in it. In this case you don't have to call Calculate method because you already have the required values in cells.
You should call Calculate method when you need to update, re-calculate the formulas in your spreadsheet, for instance after you have added or modified some cell values.
Last, regarding your question again it is hard to understand it, but nevertheless:
Can i Get calculated values?
Yes, that line of code var value = workSheet.Cells[i,j].Value; should give you the calculated value because you used Calculate method before it. However, if you have formulas that are currently not supported by GemBox.Spreadsheet's calculation engine then it will not be able to calculate the value. You can find a list of currently supported Excel formula functions here.
or you guys know pre-Calculate function or Get more Speed?
I don't know what "pre-Calculate function" means and for speed please refer to first part of this answer.

How can I get this PivotTable to display the values I want it to, in the location I want them to be?

After much gnashing of teeth, &c, I was able to achieve a modicum of success with generating a PivotTable. It now sports both a "row filter" (on the Descriptions) and a "column filter" (on the "month year" columns), like so:
This is accomplished with the following code:
var pch = _xlBook.PivotCaches();
Range sourceData = _xlBook.Worksheets["PivotData"].Range["A1:G318"]; // TODO: Make range dynamic
PivotCache pc = pch.Create(XlPivotTableSourceType.xlDatabase, sourceData);
PivotTable pvt = pc.CreatePivotTable(_xlPivotTableSheet.Range["A8"], "PivotTable");
pvt.PivotFields("Description").Orientation = XlPivotFieldOrientation.xlRowField;
pvt.PivotFields("MonthYr").Orientation = XlPivotFieldOrientation.xlColumnField;
The source data ("PivotData") looks like this:
What the PivotTable should look like, when all is said and coded, is this:
What do I need to do to achieve this look (this data, and in these locations)? I reckon part of it is has to do with the assignments of more XlPivotFieldOrientation values to more PivotFields, but don't know just what they should be.
And first but possibly least (but still important), "Row Labels" should say "Description" and "Column Labels" should say "Month"
UPDATE
I am trying to add, piece by piece, the code needed to make the various columns display. I tried this:
pvt.AddDataField(pvt.PivotFields("TotalQty"), "Total Packages", XlConsolidationFunction.xlSum).NumberFormat = "###,##0";
...hoping that the data from the source data's "TotalQty" column would display in a column headed "Total Packages"
It does indeed display, but the label "Total Packages", appears in an odd/out-of-the-way place:
How can I get the "Total Packages" label to display where it does in the "model" screenshot?
UPDATE 2
Hambone mentioned my TODO in his answer; I got back to it and made that dynamic this way:
int rowsUsed = _xlBook.Worksheets["PivotData"].UsedRange.Rows.Count;
int colsUsed = _xlBook.Worksheets["PivotData"].UsedRange.Columns.Count;
string colsUsedAsAlpha = GetExcelColumnName(colsUsed);
string endRange = string.Format("{0}{1}", colsUsedAsAlpha, rowsUsed);
Range sourceData = _xlBook.Worksheets["PivotData"].Range[string.Format("A1:{0}",
endRange)];
// Pass "1", get "A", etc.; from http://stackoverflow.com/questions/181596/how-
to-convert-a-column-number-eg-127-into-an-excel-column-eg-aa
public static string GetExcelColumnName(int columnNumber)
{
int dividend = columnNumber;
string columnName = String.Empty;
while (dividend > 0)
{
var modulo = (dividend - 1) % 26;
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
dividend = (dividend - modulo) / 26;
}
return columnName;
}
BTW, I can't find my bronze badges.
A couple of things... you didn't ask this specifically, but in your code you had a "TODO" as making the range dynamic. A really nice way to do this is to convert your range to a table. Once you do this, you can pass the table instead of the range. The table, as you probably know from previous posts would be:
ListObject tab = _xlPivotTableSheet.ListObjects["Table1"];
PivotCache pc = pch.Create(XlPivotTableSourceType.xlDatabase, tab);
If you do this, boundaries don't matter -- the table goes all as one data source.
Back to your issue at hand. You added your data fields okay:
pvt.AddDataField(pvt.PivotFields("TotalQty"), "Total Packages",
XlConsolidationFunction.xlSum);
pvt.AddDataField(pvt.PivotFields("TotalSales"), "Total Purchases",
XlConsolidationFunction.xlSum);
The calculated field is a bit more tricky. I didn't quite understand the calculation for "% of total," but for illustration purposes this is how you would do average price:
PivotField avg = pvt.CalculatedFields().Add("Average Price", "=TotalSales/TotalQty", true);
avg.Orientation = XlPivotFieldOrientation.xlDataField;
And you're right -- the orientation is not what you expect. This setting is done at the pivot table level -- it's either rows or columns. To get the view you're looking for you would change it from the default columns to rows:
pvt.DataPivotField.Orientation = XlPivotFieldOrientation.xlRowField;
Once you do this, I think the pivot table will look more the way you expect.

How can I get Excel cells to "right-size" to their content?

I want the Excel spreadsheet cells I populate with C# to expand or contract so that all their content displays without manually adjusting the width of the cells - displaying at "just enough" width to display the data - no more, no less.
I tried this:
_xlSheet = (MSExcel.Excel.Worksheet)_xlSheets.Item[1];
_xlSheet.Columns.AutoFit();
_xlSheet.Rows.AutoFit();
...but it does nothing in my current project (it works fine in a small POC sandbox app that contains no ranges). Speaking of ranges, the reason this doesn't work might have something to do with my having created cell ranges like so:
var rowRngMemberName = _xlSheet.Range[_xlSheet.Cells[1, 1], _xlSheet.Cells[1, 6]];
rowRngMemberName.Merge(Type.Missing);
rowRngMemberName.Font.Bold = true;
rowRngMemberName.Font.Italic = true;
rowRngMemberName.Font.Size = 20;
rowRngMemberName.Value2 = shortName;
...and then adding "normal"/generic single-cell values after that.
In other words, I have values that span multiple columns - several rows of that. Then below that, I revert to "one cell, one value" mode.
Is this the problem?
If so, how can I resolve it?
Is it possible to have independent sections of a spreadsheet whose formatting (autofitting) isn't affected by other parts of the sheet?
UPDATE
As for getting multiple rows to accommodate a value, I'm using this code:
private void AddDescription(String desc)
{
int curDescriptionBottomRow = curDescriptionTopRow + 3;
var range =
_xlSheet.Range[_xlSheet.Cells[curDescriptionTopRow, 1], _xlSheet.Cells[curDescriptionBottomRow, 1]];
range.Merge();
range.Font.Bold = true;
range.VerticalAlignment = XlVAlign.xlVAlignCenter;
range.Value2 = desc;
}
...and here's what it accomplishes:
AutoFit is what is needed, after all, but the key is to call it at the right time - after all other manipulation has been done. Otherwise, subsequent manipulation can lose the autofittedness.
If I get what you are asking correctly you are looking to wrap text... at least thats the official term for it...
xlWorkSheet.Range["A4:A4"].Cells.WrapText = true;
Here is the documentation: https://msdn.microsoft.com/en-us/library/office/ff821514.aspx

Categories

Resources