I'm trying to set a percent format when I create a cell, this is my code.
new Data.CellData
{
UserEnteredValue = new Data.ExtendedValue
{
FormulaValue = "=(B2/C2)-1"
},
EffectiveFormat = new Data.CellFormat
{
NumberFormat = new Data.NumberFormat
{
Pattern = "00.0%",
Type = "NUMBER"
}
}
}
Current value shown is "-0.2488570834" and I need this "-24.88%". What I'm missing ?
Thanks in advance.
Try following the Number format examples provided in the document:
I've also found a sample code to test this (converting format to your sample):
var ss = SpreadsheetApp.getActiveSpreadsheet();
var range = ss.getActiveRange();
var rows = range.getNumRows();
var cols = range.getNumColumns();
for(var row = 1; row <= rows; row++) {
for(var col = 1; col <= cols; col++) {
var cell = range.getCell(row, col);
var value = cell.getValue();
if(typeof(value) == 'number') {
cell.setNumberFormat("##.#%");
}
}
}
Result:
The code sample is for Apps script but the implementation to C# would be the same. Change Pattern = "00.0%", to Pattern = "##.#%",.
Hope this helps.
Related
I am using FlaUI to automate my WPF app. I have a datagrid control from DevExpress. I want to access any individual row and all the columns of that row and edit it using FlaUI. The DevExpress forum has the following sample available but this is for UIA library.How can I rewrite this using FlaUI libraries?
AutomationElement gridElem = AutomationElement.RootElement.FindFirst(TreeScope.Descendants, new PropertyCondition(AutomationElement.LocalizedControlTypeProperty, "datagrid"));
GridPattern gridPattern = (GridPattern)gridElem.GetCurrentPattern(GridPattern.Pattern);
int rowCount = gridPattern.Current.RowCount;
List<object> values = new List<object>();
for (int i = 0; i < rowCount; i++) {
AutomationElement item = gridPattern.GetItem(i, 0);
ValuePattern valuePattern = (ValuePattern)item.GetCurrentPattern(ValuePattern.Pattern);
values.Add(valuePattern.Current.Value);
Very new to FlaUI & automation.
Finally with some help from DevExpress Support, I was able to achieve my intentions. Here is the piece of code that works well :)
public void CreateNewViewGrid(Grid grid)
{
var pattern = grid.Patterns.Grid;
var rowCount = pattern.Pattern.RowCount;
var colCount = pattern.Pattern.ColumnCount;
var values = new List<object>();
List<string> columnNames = new List<string>();
columnNames.Add("Vessel Id");
columnNames.Add("Voyage Id");
columnNames.Add("Load Date");
columnNames.Add("Dis Date");
columnNames.Add("Vessel Name");
columnNames.Add("Status");
for (int i = 0; i < rowCount; i++)
{
var item = pattern.Pattern.GetItem(i, 0);
var item2 = pattern.Pattern.GetItem(i, 1);
var value = (item2.Patterns.Value.Pattern.Value).ToString();
values.Add((value));
foreach (var data in columnNames)
{
if (value == data)
{
var itemStatus = item.AsGridCell();
itemStatus.Click();
}
}
}
//Console.WriteLine(string.Join(", ", values));
//return values;
}
before this, finding element using FlaUI is necessary
Grid(reference from FlaUI.Core.AutomationElements)
private Grid grid=>windows.FindFirstDescendant(cf=>cf.ByAutomationID("dataGrid").AsGrid();
Ive been working at this for hours and cant seem to figure out how to correctly display the data in a table
using (TextFieldParser csvParser = new TextFieldParser(path)) {
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
csvParser.ReadLine();
int pointX = 30;
int pointY = 40;
while (!csvParser.EndOfData) {
string[] fields = csvParser.ReadFields();
int rowNums = fields.Length;
int index = 0;
for(index = 0; index < rowNums;index++) {
string Name = fields[index];
TextBox n = new TextBox();
n.Text = Name;
n.Location = new Point(pointX, pointY);
panel2.Controls.Add(n);
panel2.Show();
pointY += 20;
if(index != 0) {
pointX += 100;
}
}
}
}
Whats happening so far is im grabbing a csv file stored in the path variable and reading it the output is accessible through fields[] This works fine then I am trying to create textbox to put the data into based on rows however what i currently have comes out look like this
Program Display
I would like to display the column names and rows correctly in order here is an example image of what it looks like in notepad
Notepad Display
In notepad you will see each new line is a row and every , dictates a new entry in the row and i wanna display it this way in my program but in textbox
Also note that not all csv files that this program will be opening are short most will be large files with thousands or rows or more so theres no way that it could be simply putting fields[0] hard coded
You are much better off using a DataGridView to display this type of data in a table format.
From the toolbox add the DataGridView control to your form. You will need to build a DataTable that will bind to your DataGridview.
Below is what you can use(I commented out where you are skipping the header in your CSV file, and am using that line to get the column headers to be used in the datagrid)
var dt = new DataTable();
var lineNo = 0;
using (var csvParser = new TextFieldParser(path))
{
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
//csvParser.ReadLine();
while (!csvParser.EndOfData)
{
var fields = csvParser.ReadFields();
var rowNums = fields.Length;
var row = dt.NewRow();
lineNo += 1;
int index = 0;
for (index = 0; index < rowNums; index++)
{
if (lineNo==1)
{
dt.Columns.Add(fields[index]);
}
else
{
row[index] = fields[index];
}
}
if (lineNo == 1) continue;
dt.Rows.Add(row);
dt.AcceptChanges();
}
}
dataGridView1.DataSource = dt;
I think the controls are overlapping, so you can not see them. That they are overlapping like chairs is the problem. You are not resetting your coordinates.
Here an improvement:
using (TextFieldParser csvParser = new TextFieldParser(path)) {
csvParser.CommentTokens = new string[] { "#" };
csvParser.SetDelimiters(new string[] { "," });
csvParser.HasFieldsEnclosedInQuotes = true;
csvParser.ReadLine();
int offsetX = 30;
int offsetY = 40;
int counter;
while (!csvParser.EndOfData) {
int pointerY = ++counter * offsetY; // first counter increments by one, then counter times offsetY occurs
int pointerX;
string[] fields = csvParser.ReadFields();
int rowNums = fields.Length;
for(int index = 0; index < rowNums;index++) {
pointerX = (index + 1) * offsetX;
string name = fields[index];
TextBox n = new TextBox() { Text = name, Location = new Point(pointerX, pointerY) };
panel2.Controls.Add(n);
panel2.Show(); // should be unnecessary
}
}
}
I am using EPPlus.
The excel I am uploading has column headers in row number 2 . And from row 4 onward it has the data which may vary up to 2k records.
The way I am doing it , it takes a lot of time for reading 2k records and putting to a list .
using (var excel = new ExcelPackage(hpf.InputStream))
{
var ws = excel.Workbook.Worksheets["Sheet1"];
//Read the file into memory
for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
if (!ws.Cells[rw, 1, rw, 24].All(c => c.Value == null))
{
int headerRow = 2;
GroupMembershipUploadInput gm = new GroupMembershipUploadInput();
for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++)
{
var s = ws.Cells[rw, col].Value;
if (ws.Cells[headerRow, col].Value.ToString().Equals("Existing Constituent Master Id"))
{
gm.cnst_mstr_id = (ws.Cells[rw, col].Value ?? (Object)"").ToString();
}
else if (ws.Cells[headerRow, col].Value.ToString().Equals("Prefix of the constituent(Mr, Mrs etc)"))
{
gm.cnst_prefix_nm = (ws.Cells[rw, col].Value ?? (Object)"").ToString();
}
}
lgl.GroupMembershipUploadInputList.Add(gm);
}
}
GroupMembershipUploadInputList is the list of objects of type GroupMembershipUploadInput that I am adding the excel values to after reading from the cell wise.
Can it be done faster ? What am I missing here ?
Please help to improve the performance.
You are making a lot iterations there, for each row, you visit each column twice. I assume that you only need those two values per row and if so the following code would reduce time drastically:
using (var excel = new ExcelPackage(hpf.InputStream))
{
var ws = excel.Workbook.Worksheets["Sheet1"];
int headerRow = 2;
// hold the colum index based on the value in the header
int col_cnst_mstr_id = 2;
int col_cnst_prefix_nm = 4;
// loop once over the columns to fetch the column index
for (int col = ws.Dimension.Start.Column; col <= ws.Dimension.End.Column; col++)
{
if ("Existing Constituent Master Id".Equals(ws.Cells[headerRow, col].Value))
{
col_cnst_mstr_id = col;
}
if ("Prefix of the constituent(Mr, Mrs etc)".Equals(ws.Cells[headerRow, col].Value))
{
col_cnst_prefix_nm = col;
}
}
//Read the file into memory
// loop over all rows
for (int rw = 4; rw <= ws.Dimension.End.Row; rw++)
{
// check if both values are not null
if (ws.Cells[rw, col_cnst_mstr_id].Value != null &&
ws.Cells[rw, col_cnst_prefix_nm].Value != null)
{
// the correct cell will be selcted based on the column index
var gm = new GroupMembershipUploadInput
{
cnst_mstr_id = (string) ws.Cells[rw, col_cnst_mstr_id].Value ?? String.Empty,
cnst_prefix_nm = (string) ws.Cells[rw, col_cnst_prefix_nm].Value ?? String.Empty
};
lgl.GroupMembershipUploadInputList.Add(gm);
}
}
}
I removed the inner column loop and moved it to the start of the method. There it is used to just get the columnindex for each field you're interested in. The expensive null check can now also be reduced. To fetch the value, all that is now needed is a simple index lookup in the row.
I'm creating a dotnet high chart by using the code:
object[,] data1 = new object[Dt.Rows.Count, 2];
for (int i = 0; i < Dt.Rows.Count; i++)
{
data1[i, 0] = Dt.Rows[i]["IncDate"];
data1[i, 1] = Dt.Rows[i]["IncCost"];
}
object[,] data2 = new object[Dt2.Rows.Count, 2];
for (int i = 0; i < Dt2.Rows.Count; i++)
{
data2[i, 0] = Dt2.Rows[i]["ExpDate"];
data2[i, 1] = Dt2.Rows[i]["ExpCost"];
}
Highcharts chart = new Highcharts("graph")
.SetTitle(new Title { Text = "Money Analysis" })
.SetXAxis(new XAxis { Type = AxisTypes.Datetime })
.SetYAxis(new YAxis { Title = new YAxisTitle { Text = "Amount (£)" } })
.SetSeries(new[]
{
new Series { Name = "Incomings", Color = Color.LimeGreen, Data = new Data(data1) },
new Series { Name = "Expenditures", Color = Color.Red, Data = new Data(data2) }
})
which outputs:
I was wondering how I'm able to make the red line continue along the current cost until the end of the graph (the last date for the incoming.) And also do the same for the green line if the expenditures have a later date than the last incomings date. Hopefully people know what I mean. Thanks in advance
So, no - the chart won't do that for you automatically, but we can do it ourselves easy enough.
1) retrieve the final y value of your data
2) retrieve the final x value that you want it to extend until
3) add a new point to the data with those x and y values.
Example function:
function extendData(series, axis) {
var ext = axis.getExtremes();
var x = ext.dataMax;
var y = series.data[series.data.length -1].y;
series.addPoint({'x':x, 'y':y, marker: { enabled: true }});
}
Working example:
http://jsfiddle.net/jlbriggs/omtugbvo/
And just to show an example using any number of series:
http://jsfiddle.net/jlbriggs/omtugbvo/3/
Example image:
I have a datatable that I want to extract certain information from (only certain rows and only certain columns). I'm trying to use the code below, but I'm getting an index out of range error when I run it, and I'm not sure if what I'm doing is the best way to get only certain data from a datatable to a datagridview. Any ideas?
currentRow = 0;
int dataGridRow = 0;
foreach (DataRow row in resultsDT.Rows)
{
string value = resultsDT.Rows[currentRow]["HighLow"].ToString();
if (value.Equals("High") | value.Equals("Low"))
{
dataGridView2.Rows[dataGridRow].Cells["colHighLow"].Value = resultsDT.Rows[currentRow]["HighLow"];
dataGridView2.Rows[dataGridRow].Cells["colDifference"].Value = resultsDT.Rows[currentRow]["Difference"];
dataGridView2.Rows[dataGridRow].Cells["colMbrSep"].Value = resultsDT.Rows[currentRow]["MBRSEP"];
dataGridView2.Rows[dataGridRow].Cells["colLocation"].Value = resultsDT.Rows[currentRow]["LOCATION"];
dataGridView2.Rows[dataGridRow].Cells["colDistrict"].Value = resultsDT.Rows[currentRow]["DIST"];
dataGridView2.Rows[dataGridRow].Cells["colAddress"].Value = resultsDT.Rows[currentRow]["ADDR1"];
dataGridView2.Rows[dataGridRow].Cells["colMeter"].Value = resultsDT.Rows[currentRow]["METER"];
dataGridView2.Rows[dataGridRow].Cells["colKWh"].Value = resultsDT.Rows[currentRow]["KWH"];
dataGridRow++;
}
currentRow++;
}
I can only guess what you need is
currentRow = 0;
int dataGridRow = 0;
foreach (DataRow row in resultsDT.Rows)
{
string value = resultsDT.Rows[currentRow]["HighLow"].ToString();
if (value.Equals("High") | value.Equals("Low"))
{
//THIS LINE
dataGridView2.Rows.Add();
dataGridView2.Rows[dataGridRow].Cells["colHighLow"].Value = resultsDT.Rows[currentRow]["HighLow"];
dataGridView2.Rows[dataGridRow].Cells["colDifference"].Value = resultsDT.Rows[currentRow]["Difference"];
dataGridView2.Rows[dataGridRow].Cells["colMbrSep"].Value = resultsDT.Rows[currentRow]["MBRSEP"];
dataGridView2.Rows[dataGridRow].Cells["colLocation"].Value = resultsDT.Rows[currentRow]["LOCATION"];
dataGridView2.Rows[dataGridRow].Cells["colDistrict"].Value = resultsDT.Rows[currentRow]["DIST"];
dataGridView2.Rows[dataGridRow].Cells["colAddress"].Value = resultsDT.Rows[currentRow]["ADDR1"];
dataGridView2.Rows[dataGridRow].Cells["colMeter"].Value = resultsDT.Rows[currentRow]["METER"];
dataGridView2.Rows[dataGridRow].Cells["colKWh"].Value = resultsDT.Rows[currentRow]["KWH"];
dataGridRow++;
}
currentRow++;
}