I'm using EPPLUS to generate my pivot table (see this SO post). I have the following code
//group by fields
foreach (string row in _GroupByColumns)
{
ExcelPivotTableField field = pivotTable.Fields[row];
//field formating
field.Sort = eSortType.Ascending;
field.Outline = false;
field.Compact = false;
field.ShowAll = false;
field.SubtotalTop = false; //doesn't work, subtotals still there when excel is opened
//doesn't work, will result in "unreadable content" error when Excel is opened
//field.SubTotalFunctions = eSubTotalFunctions.None;
//add it to the pivot
pivotTable.RowFields.Add(field);
}
_GroupByColumns is a List<string> that contains my group by columns.
I thought field.SubtotalTop = false; would hide subtotals. It doesn't. field.SubTotalFunctions = eSubTotalFunctions.None; results in "invalid data" error when I open my Excel. What else can I try?
I know this is an old question, but I'm adding this answer in case anybody Googles here.
You need to set the SubTotalFunctions property after adding the field to the RowFields collection. This is because adding it to the collection changes the XML node that SubTotalFunctions makes adjustments to. This will work...
ExcelPivotTableField field = pivotTable.Fields[row];
pivotTable.RowFields.Add(field);//<-- ADD IT FIRST
//field formating
field.Sort = eSortType.Ascending;
field.Outline = false;
field.Compact = false;
field.ShowAll = false;
field.SubtotalTop = false;
field.SubTotalFunctions = eSubTotalFunctions.None;//<-- THIS WILL WORK NOW
Related
This is a more specific version of the question here.
I am able to generate a PivotTable using this code:
private void AddPivotTable()
{
pivotData = _xlSheet.Range["A1:K1600"];
pivotDestination = _xlSheet.Range["A1602", useDefault];
_xlBook.PivotTableWizard(
Excel.XlPivotTableSourceType.xlDatabase,
pivotData,
pivotDestination,
pivotTableName,
true,
true,
true,
true,
useDefault,
useDefault,
false,
false,
Excel.XlOrder.xlDownThenOver,
0,
useDefault,
useDefault
);
// Set variables used to manipulate the Pivot Table.
pivotTable = (Excel.PivotTable)_xlSheet.PivotTables(pivotTableName);
shortnamePivotField = (Excel.PivotField)pivotTable.PivotFields(2);
itemcodePivotField = (Excel.PivotField)pivotTable.PivotFields(3);
descriptionPivotField = (Excel.PivotField)pivotTable.PivotFields(4);
priceweekPivotField = (Excel.PivotField)pivotTable.PivotFields(5);
weekPivotField = (Excel.PivotField)pivotTable.PivotFields(6);
pricePivotField = (Excel.PivotField)pivotTable.PivotFields(7);
regionorderPivotField = (Excel.PivotField)pivotTable.PivotFields(10);
// Format the Pivot Table.
pivotTable.Format(Excel.XlPivotFormatType.xlReport2);
pivotTable.InGridDropZones = false;
pivotTable.SmallGrid = false;
pivotTable.ShowTableStyleRowStripes = true;
pivotTable.TableStyle2 = "PivotStyleLight1";
// Page Field
shortnamePivotField.Orientation = Excel.XlPivotFieldOrientation.xlPageField;
// Row Fields
descriptionPivotField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
itemcodePivotField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
// Data Fields
pricePivotField.Orientation = Excel.XlPivotFieldOrientation.xlDataField;
pricePivotField.Function = Excel.XlConsolidationFunction.xlSum;
}
What I want is to be able to create a PivotTable something like this:
...(which I generated using Excel manually), but as you can see here:
...trying to accomplish it with the code above is not working. What is needed to programmatically add a ReportFilter to my PivotTable?
UPDATE
I found a PivotFilter class, but my probes at testing it out:
// Pivot Filter
//shortnamePivotFilter.DataField = shortnamePivotField; <= DataField readonly
//shortnamePivotFilter.MemberPropertyField = shortnamePivotField; ""
//shortnamePivotFilter.PivotField = shortnamePivotField; ""
...all failed, because PivotFilter's most likely-seeming member properties (DataField, MemberPropertyField, and PivotField) are all readonly.
UPDATE 2
With this:
//shortnamePivotField.Orientation = Excel.XlPivotFieldOrientation.xlPageField;
. . .
shortnamePivotField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
(removing shortnamePivotField as a/the PageField and adding it as a ColumnField) I get this:
Closer, but no "Seeger" (Turn, turn, turn) yet.
UPDATE 3
There doesn't seem to be much rhyme, reason, or logic to how things are plopped into the PivotTable. I've got ShortName as a Category Field, Price as a Data Field, and both Description and ItemCode as Row Fields, yet "PRICE" appears as a label in the NW corner (why?) as well as in the ShortName columns (whichever ones are selected from the "CheckedListBox" associated with "SHORT NAME"), while Description and ItemCode are both filterable column headings (like SHORT NAME).
Okay, the Row Fields (Description and ItemCode) determine which rows display, and the Column field determines which Short Name values appear as columns (makes sense), but:
(a) Why is the "PRICE" label vagranting up there in Victoria, British Columbia?
-and:
(b) Why is there a duplicated "Total" row beneath each row? Since each description has its own row, having a Total for that Description simply takes up space without adding any value, eerily reminiscent of congressmen.
UPDATE 4
I recorded a macro and dragged "SHORT NAME" from the list in PivotTable Field List.Choose fields to add to report to the Report Filter box in the NW quadrant below it.
The macro recorded as:
Sub DragShortNameToReportFilter()
With ActiveSheet.PivotTables("Pivot Test").PivotFields("SHORT NAME")
.Orientation = xlPageField
.Position = 1
End With
ActiveWindow.SmallScroll Down:=-6
ActiveSheet.PivotTables("Pivot Test").PivotFields("SHORT NAME").CurrentPage = _
"(All)"
End Sub
...so I tried this C# code:
shortnamePivotField.Orientation = Excel.XlPivotFieldOrientation.xlColumnField;
shortnamePivotField.Position = 1;
shortnamePivotField.CurrentPage = "(All)";
...and this is the result:
So it worked pretty well as far as it went - but my Row Fields (Description and ItemCode) and Data Field (Price) are now gone or at best invisible/mute.
While the spreadsheet is being created, it now prompts me with, "Do you want to replace the contents of the destination cells in [Book1]Sheet1?" (I respond with "OK" but am not overly thrilled with it, not knowing what data I may be thereby replacing).
UPDATE 5
So I started from "scratch" and first removed all the contents of the boxes (Report Filter, Row Labels, Values) and then added them back with the Macro Recorder faithfully recording. It told me I did this:
With ActiveSheet.PivotTables("Pivot Test").PivotFields("SHORT NAME")
.Orientation = xlPageField
.Position = 1
End With
With ActiveSheet.PivotTables("Pivot Test").PivotFields("DESCRIPTION")
.Orientation = xlRowField
.Position = 1
End With
With ActiveSheet.PivotTables("Pivot Test").PivotFields("ITEM CODE")
.Orientation = xlRowField
.Position = 2
End With
ActiveSheet.PivotTables("Pivot Test").AddDataField ActiveSheet.PivotTables( _
"Pivot Test").PivotFields("PRICE"), "Sum of PRICE", xlSum
...which doesn't look like much more than I already have in code. I just added the Position values for the two RowFields so that code now looks like this:
// Row Fields
descriptionPivotField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
descriptionPivotField.Position = 1;
itemcodePivotField.Orientation = Excel.XlPivotFieldOrientation.xlRowField;
itemcodePivotField.Position = 2;
...but, while better, it's still not quite as nifty as the auto-generated PivotTable...
I'm trying to design a table that has 3 additional tables in the last cell. Like this.
I've managed to get the first nested table into row 4, but my second nested table is going into cell(1,1) of the first table.
var wordApplication = new Word.Application();
wordApplication.Visible = true;
var wordDocument = wordApplication.Documents.Add();
var docRange = wordDocument.Range();
docRange.Tables.Add(docRange, 4, 1);
var mainTable = wordDocument.Tables[1];
mainTable.set_Style("Table Grid");
mainTable.Borders.Enable = 0;
mainTable.PreferredWidthType = Word.WdPreferredWidthType.wdPreferredWidthPercent;
mainTable.PreferredWidth = 100;
docRange.Collapse(Word.WdCollapseDirection.wdCollapseStart);
var phoneRange = mainTable.Cell(4, 1).Range;
phoneRange.Collapse(Word.WdCollapseDirection.wdCollapseStart);
phoneRange.Tables.Add(phoneRange, 3, 2);
var phoneTable = mainTable.Cell(4, 1).Tables[1];
phoneTable.set_Style("Table Grid");
phoneTable.Borders.Enable = 0;
phoneTable.AutoFitBehavior(Word.WdAutoFitBehavior.wdAutoFitContent);
phoneTable.Rows.RelativeHorizontalPosition = Word.WdRelativeHorizontalPosition.wdRelativeHorizontalPositionMargin;
phoneRange.Collapse(Word.WdCollapseDirection.wdCollapseEnd);
I've tried collapsing the range, adding in a paragraph then collapsing the range again. No luck. I found this post and many similar ones, but I must be missing something.
Thanks for your time.
It usually helps in situation like these to add a line in your code: phoneRange.Select(); and having code execution end with that. Take a look at where the Range actually is. Now you can test using the keyboard where the Range needs to be in order to insert the next table successfully.
Since you say phoneRange selects outside the third row, rather than working with phoneRange try setting a new Range object to phoneTable.Range then collapse it to its end-point.
I have a datagridview, and I am populating it from a datatable which in turn retrieves it's data from a webservice query (against SalesForce cloud system).
Essentially we want to show the results of attempting to remove attachments from SalesForce cases which have been put on there by the users, currently we query a SalesForce XML webservice called case and we want to add the capability to also query a second new SalesForce object called credit case.
It has been working fine getting its data from an object called cases, and displaying them in a Windows Forms datagridview control.
Now we want to add another object (let's call it creditCases), so I have the query all setup, have added another task object with the fields and datatypes and so on.
Once the dataset is populated we set the data source of the datagridview using gvTaskCases.DataSource = dtCases;
But of course I now have a second datasource (with a different number of columns) that I want to add to the table.
If I do this with my new datatable (gvTaskCases.DataSource = dtcreditCases) how do I stop it replacing the data from the existing datatable?
CODE:
gvTaskCases.DataSource = null;
dtCases.Rows.Clear();
foreach (task_cases item in cases)
{
DataRow drCases = dtCases.NewRow();
// Then add the new row to the collection.
drCases["Case ID"] = item.c_Id;
drCases["Case Number"] = item.c_Number;
drCases["Case Topic"] = item.c_Topic;
drCases["Case SubTopic"] = item.c_Subtopic;
drCases["Account Number"] = item.c_CustomerNumber;
drCases["Additional Info"] = item.c_AdditionalInfo;
drCases["Closed Date"] = Convert.ToDateTime(item.c_ClosedDate).ToString("dd/MM/yyyy");
drCases["Attachment"] = item.c_Attachment;
drCases["Content Type"] = item.c_ContentType;
drCases["Detach Status"] = item.c_Status;
drCases["Document Type"] = item.c_DocumentType;
drCases["Imaging Directory"] = item.c_ImagingDSXDirectory;
drCases["Imaging Document"] = item.c_ImagingDocument;
dtCases.Rows.Add(drCases);
}
gvTaskCases.DataSource = dtCases;
gvTaskCases.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.EnableResizing;
gvTaskCases.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
foreach (task_creditcases item in creditCases)
{
DataRow drCases = dtCases.NewRow();
// Then add the new row to the collection.
drCases["Case ID"] = item.c_Id;
drCases["Case Number"] = item.c_Name; // SalesForece Credit Case Object CASE NUMBER;
drCases["Account Number"] = item.c_Account__c;
drCases["Closed Date"] = Convert.ToDateTime(item.c_Closed_Date__c).ToString("dd/MM/yyyy");
drCases["Attachment"] = item.c_Imaging_Document_Attached__c;
drCases["Detach Status"] = item.c_Status__c;
drCases["Document Type"] = item.c_Document_Type__c;
drCases["Imaging Directory"] = item.c_Directories__c;
drCases["Imaging Document"] = item.c_Imaging_Document;
dtCases.Rows.Add(drCases);
}
// add the new records:
// Adjust size & hide columns that aren't needed
gvTaskCases.Columns[0].Visible = false;
gvTaskCases.Columns[11].Visible = false;
gvTaskCases.Columns[12].Visible = false;
gvTaskCases.Columns[13].Visible = false;
You can use the Merge method of the DataTable.
((DataTable) gvTaskCases.DataSource).Merge(dtcreditCases);
Another approach is just keep your old DataTable, you have to use a little LINQ to merge the dataTables like this:
gvTaskCases.DataSource = (dtCases.Columns.Count > dtcreditCases.Columns.Count ?
dtCases.AsEnumerable().Concat(dtcreditCases.AsEnumerable()) :
dtcreditCases.AsEnumerable().Concat(dtCases.AsEnumerable())).CopyToDataTable();
This code cause double record...
i checked my insert code for all tables and it works fine...
and this is insert code:
StoreDO store = new StoreDO();
List<BrandDO> brandList = new BrandBL().SelectBrands();
StoreBL storeBL = new StoreBL();
store.StoreName = txtStoreName.Text;
store.StorePhone = txtStorePhone.Text;
store.StoreAddress = txtStoreAddress.Text;
store.CityID = int.Parse(ddlCity.SelectedValue);
store.CountyID = int.Parse(ddlCounty.SelectedValue);
store.IsActive = chkIsActive.Checked;
int storeID = storeBL.InsertStore(store);
ContentPlaceHolder contentPlaceHolder = (ContentPlaceHolder)Master.FindControl("ContentPlaceHolder1");
for (int i = 0; i < brandList.Count; i++) {
string brandName = brandList[i].BrandName.ToString() + brandList[i].BrandID.ToString();
StoreBrandBL storeBrandBL = new StoreBrandBL();
CheckBox chkBrand = (CheckBox)contentPlaceHolder.FindControl(brandName);
if (chkBrand != null) {
if (chkBrand.Checked) {
StoreBrandDO storeBrandDO = new StoreBrandDO();
storeBrandDO.StoreID = storeID;
storeBrandDO.BrandID = brandList[i].BrandID;
storeBrandDO.IsActive = true;
storeBrandBL.InsertStoreBrand(storeBrandDO);
}
}
}
Duplicating rows in your database should be avoided in the code and protected against in the database.
As hwcverwe said you can use table constraints but you should also try to set the primary key correctly for each table.
If you are using surrogate keys on all tables (such as the StoreID and BrandID I see in your code) then you will have to use unique table constraints to prevent duplicate data. Configuring your database correctly will also show up the problem areas in your code as the database will throw an exception when an insert fails.
EDIT: In response to your comment your question title is incorrect if you are asking about CheckBox controls.
Looking at the code it appears you are trying to find a checkbox control in a ContentPlaceholder but you do not show the code which creates the checkboxes.
I have a winform app that fills a lot of its dropdomn fields fram a maintenance table at runtime. Each Form has a Private void FillMaintFields()
I have run into a strange error where setting the column visibility on 1 form works but on another gives me an index out of range error!
Here is the abriged method on the offending form -->
private void FillMaintFields()
{
var myMCPTableMaint = new TableMaint();
// Index 27 is Diabetic Teaching Topics
var myDataSet = myMCPTableMaint.GetMaintItem(27);
var myDataTable = myDataSet.Tables[0];
// Diabetic TeachingTopics dropdown
chkcboDiabeticTeachingTopics.Properties.DataSource = myDataTable;
chkcboDiabeticTeachingTopics.Properties.DisplayMember = "ItemDescription";
chkcboDiabeticTeachingTopics.Properties.ValueMember = "ItemID";
// Index 26 is Diabetic Teaching
myDataSet = myMCPTableMaint.GetMaintItem(26);
myDataTable = myDataSet.Tables[0];
lkuDiabeticTeaching.Properties.DataSource = myDataTable;
lkuDiabeticTeaching.Properties.PopulateColumns();
lkuDiabeticTeaching.Properties.DisplayMember = "ItemDescription";
lkuDiabeticTeaching.Properties.ValueMember = "ItemID";
lkuDiabeticTeaching.Properties.Columns[0].Visible = false;
lkuDiabeticTeaching.Properties.Columns[1].Visible = false;
lkuDiabeticTeaching.Properties.Columns[3].Visible = false;
lkuDiabeticTeaching.Properties.Columns[4].Visible = false;
}
Now here is the working function on a sister form -->
private void FillMaintFields()
{
var myMCPTableMaint = new TableMaint();
// Index 4 is Minimum Contact Schedule
var myDataSet = myMCPTableMaint.GetMaintItem(4);
var myDataTable = myDataSet.Tables[0];
lkuMinContactSchedule.Properties.DataSource = myDataTable;
lkuMinContactSchedule.Properties.PopulateColumns();
lkuMinContactSchedule.Properties.DisplayMember = "ItemDescription";
lkuMinContactSchedule.Properties.ValueMember = "ItemID";
lkuMinContactSchedule.Properties.Columns[0].Visible = false;
lkuMinContactSchedule.Properties.Columns[1].Visible = false;
lkuMinContactSchedule.Properties.Columns[3].Visible = false;
lkuMinContactSchedule.Properties.Columns[4].Visible = false;
// Index 5 is Release of Information Updated Annually
myDataSet = myMCPTableMaint.GetMaintItem(5);
myDataTable = myDataSet.Tables[0];
lkuReleaseInfoUpdateAnnually.Properties.DataSource = myDataTable;
lkuReleaseInfoUpdateAnnually.Properties.PopulateColumns();
lkuReleaseInfoUpdateAnnually.Properties.DisplayMember = "ItemDescription";
lkuReleaseInfoUpdateAnnually.Properties.ValueMember = "ItemID";
lkuReleaseInfoUpdateAnnually.Properties.Columns[0].Visible = false;
lkuReleaseInfoUpdateAnnually.Properties.Columns[1].Visible = false;
lkuReleaseInfoUpdateAnnually.Properties.Columns[3].Visible = false;
lkuReleaseInfoUpdateAnnually.Properties.Columns[4].Visible = false;}
They are all using the same method in the DAL and accessing the EXACT same table which has a structure of -->
|ItemID | CategoryID | ItemDescription | OrderID | Active|
I am at a loss here as to why it would work in 1 spot and not another. If I comment out the Columns[] portion in the offending Form it returns the correct data with NO errors but, of course ALL columns visible.
Ideas? Thanks!
EDIT 1
Based on some comments and concerns:
The error appears on the first line that tries to access the Columns[]. Wherever and whatever column that may be on the offending Form.
If I debug and look at myDataTable it shows the correct columnms and correct data.
Is the error happening on the "lkuReleaseInfoUpdateAnnually" or the "lkuMinContactSchedule"? Which control is that exactly? It seems the error is on the control side of things, seems like your control in the second form doesn't have all the columns you're expecting it to have.
EDIT: You seem to be confusing the Columns in the dataTable with the columns on your control(s). I'm not sure which control you're using, but doing:
lkuReleaseInfoUpdateAnnually.Properties.Columns[0]
does NOT mean you're indexing into the DataTable. You're indexing into the columns of your control, which may or may not be there.
Create a minimal code that still reproduces a problem. Debug that code; or, if that doesn't help, post it here. The above code doesn't really tell us anything: it's too large, too specific to your problem. We don't know how your data looks, we've got to take your word for the table structure – although C# seems to disagree.
All in all, any help anyone could offer is just fuzzy guesswork.
I have some ideas on how to better specify bugs and their origin. Something you should do, is to watch "lkuDiabeticTeaching.Properties.Columns.Count" value, if, it's less than 1 means, you do not have any columns, and probably because no population occurred.
The only thing I can see is that the first set of code is missing a call to PopulateForms() (it is included in the second set). Could that be it?
Well, I figured it out. Kinda. For some reason I need to call lkuDiabeticTeaching.Properties.ForceInitialize(); after setting the data source on the offending form.
I can only guess that because I have nested forms that somehow this was trying to fire before the control was initialized.
It now looks like this -->
// Index 26 is Diabetic Teaching
harDataSet = myHARTableMaint.GetMaintItem(26);
harDataTable = harDataSet.Tables[0];
lkuDiabeticTeaching.Properties.DataSource = harDataTable;
lkuDiabeticTeaching.Properties.ForceInitialize();
lkuDiabeticTeaching.Properties.PopulateColumns();
lkuDiabeticTeaching.Properties.DisplayMember = "ItemDescription";
lkuDiabeticTeaching.Properties.ValueMember = "ItemID";
if(lkuDiabeticTeaching.Properties.Columns.Count > 0)
{
lkuDiabeticTeaching.Properties.Columns[0].Visible = false;
lkuDiabeticTeaching.Properties.Columns[1].Visible = false;
lkuDiabeticTeaching.Properties.Columns[3].Visible = false;
lkuDiabeticTeaching.Properties.Columns[4].Visible = false;
}
Thanks to all who gave of there time.