How to hide an excel column? - c#

I need to hide an excel column entirely. I used the below code but didn't work:
public void Hide (params string[] columns)
{
foreach(var column in columns)
{
Range range = (Range) oSheet.Columns[column, Type.Missing];
range.EntireColumn.Hidden = true;
}
}
What am I missing?

It turns out that hiding a span of rows and columns you specify couldn't be a heck of a lot easier. Here's how you do it, in two easy steps:
1) Name your worksheet:
private Worksheet _xlSheet;
2) Now, name a range, including the first row and column to hide and then the last row and column to hide, like so:
var hiddenRange = yourWorksheet.Range[_xlSheet.Cells[42, 1], _xlSheet.Cells[999, 13]];
hiddenRange.EntireRow.Hidden = true;
This assumes the first row you want to hide is 42, etc. Obviously you will want to change these hardcoded values.
As an example, here's some actual code, using constants and variables instead of hardcoded vals, which responds to a boolean whose value indicates whether the range should be hidden or not:
private bool _hide;
private int _curTopRow;
private static readonly int ITEMDESC_COL = 1;
private static readonly int TOTALS_COL = 16;
. . .
if (_hide)
{
var hiddenRange = _xlSheet.Range[_xlSheet.Cells[_curTopRow, ITEMDESC_COL], _xlSheet.Cells[_curTopRow+3, TOTALS_COL]];
hiddenRange.EntireRow.Hidden = true;
}
Note that you need to reference the Microsoft.Office.Interop.Excel assembly.

The above snippet is working .. sorry guys! The issue was that, my fellow colleague used to auto-fit all columns, right before saving the file, which will override my settings above. Yes, a function called CloseFile() that does two jobs, formats and then saves .. many responsibilities, eh?

Related

How to update data programmatically in DataGridView using c#

In my dataGridView cells values are 0's and 1's. I have to set 0 to A and 1 to P by using following code for this operation.
foreach (DataGridViewRow row in dataGridView1.Rows)
{
int d = Convert.ToInt32(row.Cells[0].Value);
if (d == 0)
row.Cells[0].Value = "A";
else
row.Cells[0].Value = "P";
}
but it gives error, error is like
System.Exception: A is not a valid value for Int32. -> System.FormatException: Input string was not in a correct
format.
at System.Number.StringToNumber(String str, NumberStyles options NumberBuffer& number, NumberFormatinfo info, Boolean parseDecimal) at System.Number.Parselnt32(String s, NumberStyles style, NumberFormatinfo info) ... continue
If I set the numerical value in above program it update successfully but if I set string value like "A" or "P" it gives above error.
Please give me the solutions.
In the future, to avoid this unnecessary back and forth inquisition, it would behoove you to include all the pertinent information in your question. Example in this case, the code that adds the data to the grid would benefit YOU by removing any question as to “how” the code is doing this. If others wanted to help you, then they are going to have to “guess” how this is done. If others (who you are asking help from) have to do a bunch of guessing and code writing to reproduce YOUR question… then most are going to move on.
I highly recommend that you take a look at the SO section on… How to create a Minimal, Reproducible Example ...I can not stress how helpful this “process” can be for YOU. Often times, the process of creating the “reproducible” example that you want to post here “reveals” the problem you are having. Posting a “complete reproducible example` will help you since the other people helping you don’t have to guess or write a bunch of code. Without question, you will get more and better answers to your questions if you do this simple thing.
As seen from the back and forth questions and answers, it seems to me that we are getting nowhere. Given your last comment, I am guessing you may be looking at this from the point of view of the DataGridView your comment…
”I have recently changed the column type in string by using code "dataGridView1.Columns[ 1 ].ValueType = typeof(string);". I have also
confirm to print the column type by using code
"Console.WriteLine(dataGridView1.Columns[1 ].ValueType);" before and
after execution of the code "dataGridView1.Columns[1 ].ValueType =
typeof(string);"”
Changing the “ValueType” IN THE GRID is fine, however, you need to keep in mind, that the “underlying” data source won’t necessarily respect/conform to the “GRIDS” value type. In fact in most cases, as this one… it WON’T. You can test this by doing the following steps:
1) Load the data into the grid such that the column we want to change is a “numeric” column.
2) Change that column to a string value type as your posted code does in your comment.
3) Type an “A” into the column you just changed to a string type then press the “Enter” key…
I am betting you will get a DataError exception.
It is true, your code changes the column type to a string IN THE GRID, but the underlying data source is still an int. Hence the DataError. The DataGridView simply displays the data that is in the data source. You can change the column types, format and order in the GRID, however, the underlying data source “usually” will NOT change. This is why, in your case, you need to “change” the column type in the data source, not the grid.
There are numerous ways to achieve this, however, IMHO I am betting the “easiest” way to do this would be to change the column type and possibly the values also “when you get the data from the data base.” I am aware this may not be an option at times and you are forced to make the changes you are asking for. But if you can do this directly from the data base, I recommend it.
Therefore, lets break down what I can gather you are asking. For starters, I assume you are getting the data from a data base and the data is returned in a DataTable. One of the columns in this DataTable is of some “numeric type” (‘intorDouble`) and it ONLY contains values of zeros (0s) and ones (1s). Is what you want, is to “change” the values in that column to “As” and “Ps” such that all zeros (0s) become “As” and ones (1s) become “Ps.” I hope I have this correct.
This appears straight forward, and I assume there are numerous ways to do this, however, I am confident you can NOT simply “change” a columns data “type” in an existing DataTable. Therefore, it seems obvious that your code is going to have to “ADD” this column to the existing DataTable. Something like…
originalDataTable.Columns.Add("A/P", typeof(string));
Then “after” the column as been added, loop through all the rows in the DataTable and set the values for the new “A/P” column. I am aware that this creates an extra column, however, it would be a simple task to remove or simply not display the column of 0s and 1s. Given this, a method Add_A_P_TextColumn(DataTable dt, string colName) … that takes a DataTable we want to add the column to and a string name to identify the column that contains the 0s, and 1s… may come in handy and look something like…
private void Add_A_P_TextColumn(DataTable dt, string colName) {
dt.Columns.Add("A/P", typeof(string));
foreach (DataRow row in dt.Rows) {
row["A/P"] = (int)row[colName] == 0 ? "A" : "P";
}
}
This should add the column as described and it is your choice to either remove the column of 0s and 1s or not. To demonstrate a complete and reproducible example, the complete code below demonstrates using the above method. To start, drop a DataGridView and a Button onto a form like below.
When the form loads, the code gets a column of random 0s and 1s for test data. This would be the original data your code gets from the data base. This is what the picture shows. When the user clicks the button, the Add_A_P_TextColumn method is called to add the "A/P" column.
DataTable OriginalTable;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
OriginalTable = GetOriginalTable();
dataGridView1.DataSource = OriginalTable;
}
private DataTable GetOriginalTable() {
DataTable dt = new DataTable();
dt.Columns.Add("0/1", typeof(int));
Random rand = new Random();
for (int i = 0; i < 15; i++) {
dt.Rows.Add(rand.Next(2));
}
return dt;
}
private void button1_Click(object sender, EventArgs e) {
Add_A_P_TextColumn(OriginalTable, "0/1");
}
I hope this clears some things up.
you need to iterate over Cells as well:
foreach (DataGridViewRow row in dataGridView1.Rows)
{
foreach(DataGridViewCell cell in row.Cells)
{
int d = Convert.ToInt32(cell.Value);
if (d == 0)
cell.Value = "A";
else
cell.Value = "P";
}
}

Using AddRow() in Output Buffer when C# transform in SSIS needs synchronous?

First off I'm quite new to both SSIS and C#, so apologies for any rookie mistakes. I am trying to muddle my way through splitting one column by a specific delimiter from an input file that will have a variable length header, and a footer.
For example, Input0Buffer has one column. The actual data is always preceded by a row starting with the phrase "STARTDATA", and is bracketed with a row starting with "ENDDATA".
The one input column contains 5 bits of data separated by | . Two of these columns I don't care about.
Basically the input file looks like this:
junkrow
headerstuff
morejunk
STARTDATA
ID1|rubbish|stuff|apple|cheese
ID2|badger|junk|pear|yoghurt
So far I have tried to get some row-by-row logic going in the C# transformer, which I think I am happy with - but I can't work out how to get it to output my split data. Code is below.
bool passedSOD;
bool passedEOD;
public void ProcessRow(Input0Buffer data)
{
string Col1, Col2, Col3;
if (data.Column0.StartsWith("ENDDATA"))
{
passedEOD = true;
}
if (passedSOD && !passedEOD)
{
var SplitData = data.Column0.Split('|');
Col1 = SplitData[0];
Col2 = SplitData[3];
Col3 = SplitData[4];
//error about Output0Buffer not existing in context
Output0Buffer.Addrow();
Output0Buffer.prodid = Col1;
Output0Buffer.fruit = Col2;
Output0Buffer.dairy = Col3;
}
if (data.Column0.StartsWith("STARTDATA"))
{
passedSOD = true;
}
}
If I change the output to asynchronous it stops the error about Output0Buffer not existing in the current context, and it runs, but gives me 0 rows output - presumably because I need it to be synchronous to work through each row as I've set this up?
Any help much appreciated.
you can shorten your code by just checking if the row contains a '|'
if(Row.Column0.Contains("|")
{
string[] cols = Row.Column0.Split('|');
Output0Buffer.AddRow();
Output0Buffer.prodid = cols[0];
Output0Buffer.fruit = cols[3];
Output0Buffer.dairy = cols[4];
}
Like Bill said. Make sure this is a transformation component and not a destination. Your options are source, transformation, and destination.
You also might want this as a different output as well. Otherwise, you will need to conditionally split out the "extra" rows.
Thanks both for for answering - it is a transformation, and thank you for the shorter way, however the header and footer are not well formatted and may contain junk characters also, so I daren't risk looking for | in rows. But I will definitely store that away for processing a better formatted file next time.
I got a reply outside this forum so I thought I should answer my own question in case any one else has a similar problem.
Note that:
it's a transform
the Output is be set to SynchronousInputID = None in the Inputs and Outputs section of the Script Transformation Editor
my input is just called Input, and contains one column called RawData
my output is called GenOutput, and has three columns
although the input file only really has 5 fields, there is a trailing | at the end of each row so this counts as 6
Setting the synchronous to None means that Output0Buffer is now recognised in context.
The code that works for me is:
bool passedSOD;
bool passedEOD;
public override void_InputProcessInputRow(InputBuffer Row)
{
if (Row.RawData.Contains("ENDDATA"))
{
passedEOD = true;
GenOutputBuffer.SetEndOfRowset();
}
//IF WE HAVE NOT PASSED THE END OF DATA, BUT HAVE PASSED THE START OF DATA, SPLIT THE ROW
if (passedSOD && !passedEOD)
{
var SplitData = Row.RawData.Split('|');
//ONLY PROCESS IF THE ROW CONTAINS THE RIGHT NUMBER OF ELEMENTS I.E. EXPECTED NUMBER OF DELIMITERS
if (SplitData.Length == 6)
{
GenOutputBuffer.AddRow();
GenOutputBuffer.prodid = SplitData[0];
GenOutputBuffer.fruit = SplitData[3];
GenOutputBuffer.dairy = SplitData[4];
}
//SILENTLY DROPPING ROWS THAT DO NOT HAVE RIGHT NUMBER OF ELEMENTS FOR NOW - COULD IMPROVE THIS LATER
}
if (Row.RawData.Contains("STARTDATA"))
{
passedSOD = true;
}
}
Now I've just got to work out how to convert one of the other fields from string to decimal, but decimal null and allow it to output a null if someone has dumped "N.A" in that field :D

Winform datagridview numeric sorting [duplicate]

This question is closely related to these two (this and this) but I don't think they give a satisfying answer.
I have a DataGridView (i.e. a table) with several columns (DataGridViewTextBoxColumn) of different data types: string, integers and floats. When I click on their respective header, each should be sorted according to their type: string alphabetically and numerical values numerically. I have, simply put, the following code:
private System.Windows.Forms.DataGridView grid;
private System.Windows.Forms.DataGridViewTextBoxColumn stringColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn doubleColumn;
private System.Windows.Forms.DataGridViewTextBoxColumn intColumn;
stringColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
doubleColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
intColumn = new System.Windows.Forms.DataGridViewTextBoxColumn();
grid.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
stringColumn,
doubleColumn,
intColumn});
However, since the default representation is string, the numerical values also get sorted alphabetically, for example like this:
1, 11, 2, 3, 42, 5
Apparently, as an easy way of getting around this, according some threads (e.g. here and here), the following should work immediately solve the problem:
doubleColumn.ValueType = typeof(double);
intColumn.ValueType = typeof(int);
However, this solution simply doesn't work in my project: values are still sorted alphabetically. So the question is: why not? In the Debugger, I could see that the value type actually changed to (in the double case) System.Double, so something is happening at least. But how can I make sure that it actually sorts it accordingly, without writing my own sorter?
You can handle the event SortCompare to change how the sorting is done, like this:
private void dataGridView1_SortCompare(object sender, DataGridViewSortCompareEventArgs e) {
//Suppose your interested column has index 1
if (e.Column.Index == 1){
e.SortResult = int.Parse(e.CellValue1.ToString()).CompareTo(int.Parse(e.CellValue2.ToString()));
e.Handled = true;//pass by the default sorting
}
}
NOTE: The above code supposes your cell values are convertible to int.
You said your DataGridView doesn't have DataSource assigned, that means you Add the rows manually, so I think you should use numeric values instead of string for your cells. That would make the sorting work as you want.
If you are using a DataTable then you have to set the DataType on the DataColumn. Setting ValueType on the DataGridViewTextBoxColumn won't help.
You can set it when creating it:
table.Columns.Add("Number", typeof(int));
Changing column from string to int32 might be helpful:
for (int i = 0; i < tableDataGridView.Rows.Count; i++) {
DateTime dt = Convert.ToDateTime(tableDataGridView.Rows[i].Cells[9].Value.ToString());
DateTime dtnow = DateTime.Now;
TimeSpan ts = dtnow.Subtract(dt);
tableDataGridView.Rows[i].Cells[1].Value = Convert.ToInt32( ts.Days.ToString());
}
tableDataGridView.Sort(tableDataGridView.Columns[1], ListSortDirection.Descending);
For me, it works. I hope it will help.
Setting your column ValueType to typeof(int) will work, just remember to make sure you put integers into that column. If the rest of your data contains strings, it can be easy to forget to convert your number from a string to an int.
https://www.youtube.com/watch?v=kKeTRPSLxX8 watch this video, it helps a lot
Copying the code from that video:
Private Sub dgvDailySales_SortCompare(sender As Object, e As DataGridViewSortCompareEventArgs) Handles dgvDailySales.SortCompare
Try
Dim dval1, dval2 As Double
If Not Double.TryParse(e.CellValue1.ToString, dval1) Then Return
If Not Double.TryParse(e.CellValue2.ToString, dval2) Then Return
If dval1 = dval2 Then
e.SortResult = 0
ElseIf dval2 > dval1 Then
e.SortResult = -1
ElseIf dval1 > dval2 Then
e.SortResult = 1
End If
e.Handled = True
Catch ex As Exception
MsgBox(ex.Message, vbCritical)
End Try
End Sub

I need to format a string as a phone number in a radgrid winform cell

Sounds silly simply, right?
I can format the input, but I have a database that is returning the value as a string. No matter what I do if it is stored in the database as 1234567890 I get 1234567890 back. Everything in the database is stored as strictly string numeric data, meaning that there are no letters or special characters, but it is a varchar(10) field.
I have created a GridViewMaskBox column and set it to Numeric, then in the formatting event changed the data to numeric like this:
GridViewMaskBoxColumn maskBoxColumn = new GridViewMaskBoxColumn();
maskBoxColumn.Name = "Phone";
maskBoxColumn.FieldName = "cellphone_number";
maskBoxColumn.HeaderText = "Phone";
maskBoxColumn.MaskType = MaskType.Numeric;
maskBoxColumn.Mask = "(000) 000-0000";
maskBoxColumn.TextAlignment = ContentAlignment.MiddleCenter;
maskBoxColumn.ReadOnly = false;
radGridView1.MasterTemplate.Columns.Add(maskBoxColumn);
Then in the CellFormatting event:
if (e.Column.Name=="cellPhone")
{
long cellInfo =Convert.ToInt64(e.CellElement.Value);
e.CellElement.Value = cellInfo;
}
I even tried just for testing purpose:
if (e.Column.Name=="cellPhone")
{
long cellInfo =Convert.ToInt64(e.CellElement.Value);
long number = 1234567890;
e.CellElement.Value = number;
}
and the cell still shows 123456789 instead of (123) 456-7890
I have tried creating a standard text column and using every variation of:
radGridView1.Columns["cellPhone"].FormatString = "{0:(###) ###-####}";
then again in the formatting event changing from string to a int64.
I have verified in the debugger that it is indeed hitting the event and changing the data type correctly.
I am ready to make small animal sacrifices but fear that will not actually help and may hinder any good karma I have built up.
Please help. I have spent hours on what should have been childs play.
Joe
Update: I can do the below which seems to work, but actually replaces the text in the grid with the "()" in the numbers which screws the database update on edit:
if (e.CellElement.Value.ToString().Length==10)
{
BigInteger bi = new BigInteger();
bool worked = BigInteger.TryParse(e.CellElement.Value.ToString(),out bi);
string numberAsText = bi.ToString("###-###-####");
e.CellElement.Value = numberAsText.ToString();}
I think I am chasing my tail...
UPDATE:
I have now added a new (non databound) column called cellMasked and I have the following single codeline in the CellFormating event for the databound cellphone column:
e.Row.Cells["cellMasked"].Value = Convert.ToUInt64(e.CellElement.Value).ToString("###-###-####");
Still working on it but it feels like a step in the right direction.
Hold! Don't kill no animals :).
First, I want to start by explaining that the CellFormatting event is used for appearance modifications as the grid uses UI virtualization for its cells. So, setting the Value is not something you should do there, however, setting the CellElement.Text is something you might want. I.e you can change the text to anything you want and this is what you should do in your case.
In regards to the Columns' Mask and MaskType properties, they are responsible for the editor of the cells (when you open it for edit).
Here is a small example I put for you:
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
AddGrid();
DataTable table = new DataTable();
table.Columns.Add("cellphone_number");
table.Rows.Add("1234567890");
table.Rows.Add("3214567890");
table.Rows.Add("9874567890");
radGridView1.AutoGenerateColumns = false;
radGridView1.AutoSizeColumnsMode = GridViewAutoSizeColumnsMode.Fill;
radGridView1.DataSource = table;
GridViewMaskBoxColumn maskBoxColumn = new GridViewMaskBoxColumn();
maskBoxColumn.Name = "Phone";
maskBoxColumn.FieldName = "cellphone_number";
maskBoxColumn.HeaderText = "Phone";
maskBoxColumn.MaskType = MaskType.Standard;
maskBoxColumn.Mask = "(999) 000-0000";
radGridView1.MasterTemplate.Columns.Add(maskBoxColumn);
radGridView1.CellFormatting += radGridView1_CellFormatting;
}
void radGridView1_CellFormatting(object sender, Telerik.WinControls.UI.CellFormattingEventArgs e)
{
if (e.Column.Name == "Phone")
{
e.CellElement.Text = Convert.ToUInt64(e.CellElement.Value).ToString("(###)-###-####");
}
}

Calculate number of cells with a specific value

I'm creating a program for test management that has a stats function, which calculates the number of bugs that have been fixed, not fixed or N/A.
The test cases are all listed on a DataGridView, where the 1st column is for the test cases, the 2nd one is for the results (the column I'd like to work with) and the latter is just for comments.
Here's a bit of my code to show what I'm talking about
private int Passed() // This method is supposed to count how many test cases have passed
{
int passed = 0;
if (/*what condition should I put here?*/) {
passed++;
}
return passed;
}
//Is this the best way to display the percentage in real time?
private void Refresh_Tick(object sender, EventArgs e)
{
Display2.Text = Passed().ToString();
}
The "Results" column cells have each a combobox with its items being "FIXED", "N/A" and "NOT FIXED".
Please, I'd like to know how I can programmatically access those cells' value and then use them as a condition to count how many bugs have been fixed.
Iterating through all the rows in the gridview should get you the answer.
int countFixed=0;
int countUnFixed=0;
for(int i=0;i<dgv.RowCount;i++)
{
if((string)dgv.Rows[i].Cells[1].Value == "Fixed") //try referring to cells by column names and not the index
countFixed++;
else if((string)dgv.Rows[i].Cells[1].Value == "Not Fixed")
countUnFixed++;
}

Categories

Resources