I am using VS2013 Ultimate, with Office 2013 (PowerPoint, Excel and Word all installed). I am coding in C#.
I am creating a PowerPoint presentation using C#. So far, I have managed to accomplish everything that I have wanted to do. However, I am having problems attempting to create a chart. My understanding is that Excel is used to manage the data (in a worksheet). I have the following code, which will produce a chart with two series in a PowerPoint slide. The problem is that 'sometimes' the chart does not get added to the slide. It gets added, the worksheet appears and the data is modified and the chart disappears from the slide! I also notice 2 instances of Excel firing up but I cannot understand why. Can anyone shed any light on this please? Thanks.
public void CreateChart(PPT.Slide slide)
{
slide.Layout = PPT.PpSlideLayout.ppLayoutBlank;
var chart = slide.Shapes.AddChart(XlChartType.xlLine, 10f, 10f, 900f, 400f).Chart;
var workbook = (EXCEL.Workbook)chart.ChartData.Workbook;
workbook.Windows.Application.Visible = true;
var dataSheet = (EXCEL.Worksheet)workbook.Worksheets[1];
dataSheet.Cells.ClearContents();
dataSheet.Cells.Range["A1"].Value2 = "Bananas";
dataSheet.Cells.Range["A2"].Value2 = "Apples";
dataSheet.Cells.Range["A3"].Value2 = "Pears";
dataSheet.Cells.Range["A4"].Value2 = "Oranges";
dataSheet.Cells.Range["B1"].Value2 = "1000";
dataSheet.Cells.Range["B2"].Value2 = "2500";
dataSheet.Cells.Range["B3"].Value2 = "4000";
dataSheet.Cells.Range["B4"].Value2 = "3000";
var sc = (PPT.SeriesCollection)chart.SeriesCollection();
do
{
var seriesToDelete = sc.Item(1);
seriesToDelete.Delete();
}
while (sc.Count != 0);
var series1 = sc.NewSeries();
series1.Name = "Pauls Series";
series1.XValues = "'Sheet1'!$A$1:$A$2";
series1.Values = "'Sheet1'!$B$1:$B$2";
series1.ChartType = XlChartType.xlLine;
var series2 = sc.NewSeries();
series2.Name = "Seans Series";
series2.XValues = "'Sheet1'!$A$1:$A$2";
series2.Values = "'Sheet1'!$B$3:$B$4";
series2.ChartType = XlChartType.xlLine;
chart.HasTitle = true;
chart.ChartTitle.Font.Italic = true;
chart.ChartTitle.Text = "My First Chart!";
chart.ChartTitle.Font.Size = 12;
chart.ChartTitle.Font.Color = Color.Black.ToArgb();
chart.ChartTitle.Format.Line.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
chart.ChartTitle.Format.Line.ForeColor.RGB = Color.Black.ToArgb();
chart.HasLegend = true;
chart.Legend.Font.Italic = true;
chart.Legend.Font.Size = 10;
chart.Refresh();
}
so, putting a chart.refresh() within the Do{} block has resolved my problems! How odd!?!
Related
from Excel File
from PDF Export From Excel
This Code export Pie Chart
//Pie Chart
var pieChart = worksheet.Charts.Add(ChartType.Pie, "A27", "G45");
pieChart.SelectData(worksheet.Cells.GetSubrange("G2:G6"), true, true);
pieChart.DataLabels.LabelContainsValue = true;
pieChart.DataLabels.LabelContainsPercentage = true;
pieChart.DataLabels.ShowLeaderLines = true;
pieChart.DataLabels.Separator = ", ";
pieChart.Legend.IsVisible = true;
pieChart.Legend.Position = ChartLegendPosition.Bottom;
var printOptions = worksheet.PrintOptions;
printOptions.FitWorksheetWidthToPages = 1;
printOptions.FitWorksheetHeightToPages = 1;
workbook.Save(ms, SaveOptions.PdfDefault);`enter code here`
How do I set HeaderAddress to two cells of a clustered bar chart in EPPlus? I have the below data from my database output, where first column is as you can see merged cells.
I am looking for the following layout of the data
Please take note that the images are from a replica of the data, but generated inside Excel.
What I've tried so far is basically
ExcelChartSerie s = chart.Series.Add(axis.Address, xAxis.Address);
s.HeaderAddress = new ExcelAddress(startRow + r, GetColumnNumberByName(startColumn), startRow + 1, GetColumnNumberByName(startColumn) + 1);
where I more or less select the current row and two columns. This gives me "Address must be a row, column or single cell", but in order to get this to work, I must select multiple cells, no?
Epplus does not have the ability to set it. it is not so difficult but it requires XML manipulation. Kind of ugly but it gets the job done. Not knowing your code I made up a quick unit test that demos. It has to match to the right chart type so if it is not BarClustered let me know:
[TestMethod]
public void Chart_Meged_Header_Test()
{
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[]
{
new DataColumn("Col1", typeof (string)),
new DataColumn("Col2", typeof (int))
});
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow();
row[0] = $"item {(i%2 == 0 ? "A" : "B")}";
row[1] = i * 10;
datatable.Rows.Add(row);
}
//Create a test file
var fileInfo = new FileInfo(#"c:\temp\Chart_Meged_Header_Test.xlsx");
if (fileInfo.Exists)
fileInfo.Delete();
using (var pck = new ExcelPackage(fileInfo))
{
var workbook = pck.Workbook;
var worksheet = workbook.Worksheets.Add("Sheet1");
worksheet.Cells["B1"].LoadFromDataTable(datatable, true);
worksheet.Column(4).Style.Numberformat.Format = "m/d/yyyy";
var chart = worksheet.Drawings.AddChart("chart test", eChartType.BarClustered);
var serie = chart.Series.Add(worksheet.Cells["C2:C11"], worksheet.Cells["B2:B11"]);
chart.SetPosition(0, 0, 3, 0);
chart.SetSize(120);
//Add merged headers
worksheet.Cells["A2"].Value = "Group 1";
worksheet.Cells["A2:A6"].Merge = true;
worksheet.Cells["A7"].Value = "Group 2";
worksheet.Cells["A7:A11"].Merge = true;
//Get reference to the worksheet xml for proper namespace
var chartXml = chart.ChartXml;
var nsm = new XmlNamespaceManager(chartXml.NameTable);
var nsuri = chartXml.DocumentElement.NamespaceURI;
nsm.AddNamespace("c", nsuri);
//Get the Series ref and its cat
var serNode = chartXml.SelectSingleNode("c:chartSpace/c:chart/c:plotArea/c:barChart/c:ser", nsm);
var catNode = serNode.SelectSingleNode("c:cat", nsm);
//Get Y axis reference to replace with multi level node
var numRefNode = catNode.SelectSingleNode("c:numRef", nsm);
var multiLvlStrRefNode = chartXml.CreateNode(XmlNodeType.Element, "c:multiLvlStrRef", nsuri);
//Set the proper cell reference and replace the node
var fNode = chartXml.CreateElement("c:f", nsuri);
fNode.InnerXml = numRefNode.SelectSingleNode("c:f", nsm).InnerXml;
fNode.InnerXml = fNode.InnerXml.Replace("$B$2", "$A$2");
multiLvlStrRefNode.AppendChild(fNode);
catNode.ReplaceChild(multiLvlStrRefNode, numRefNode);
//Set the multi level flag
var noMultiLvlLblNode = chartXml.CreateElement("c:noMultiLvlLbl", nsuri);
var att = chartXml.CreateAttribute("val");
att.Value = "0";
noMultiLvlLblNode.Attributes.Append(att);
var catAxNode = chartXml.SelectSingleNode("c:chartSpace/c:chart/c:plotArea/c:catAx", nsm);
catAxNode.AppendChild(noMultiLvlLblNode);
pck.Save();
}
}
Gives this as the output:
In c#, Rich text content are saved to database in below format
< b>Hello< /b>.
I need to export this to MS Excel sheet as Hello (with bold letters)
When ever i try to export the content in excel , its not showing in rich text. Kindly help me . Thanks,
var workbook = new HSSFWorkbook();
var sheet = workbook.CreateSheet("");
int rowNumber = 1;
NPOI.SS.UserModel.IFont font = workbook.CreateFont();
font.Boldweight = (short)(NPOI.SS.UserModel.FontBoldWeight.BOLD);
font.FontHeight = 210;
font.FontName = "Calibri";
NPOI.SS.UserModel.ICellStyle headerCell = workbook.CreateCellStyle();
headerCell.FillBackgroundColor = NPOI.SS.UserModel.IndexedColors.GREY_25_PERCENT.Index;
headerCell.FillForegroundColor = NPOI.SS.UserModel.IndexedColors.GREY_25_PERCENT.Index;
headerCell.FillPattern = NPOI.SS.UserModel.FillPatternType.SOLID_FOREGROUND;
headerCell.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.CENTER;
headerCell.WrapText = true;
headerCell.SetFont(font);
headerCell.BorderBottom = NPOI.SS.UserModel.BorderStyle.THIN;
headerCell.BorderLeft = NPOI.SS.UserModel.BorderStyle.THIN;
headerCell.BorderRight = NPOI.SS.UserModel.BorderStyle.THIN;
headerCell.BorderTop = NPOI.SS.UserModel.BorderStyle.THIN;
NPOI.SS.UserModel.IFont fontShort = workbook.CreateFont();
fontShort.Boldweight = (short)(NPOI.SS.UserModel.FontBoldWeight.NORMAL);
fontShort.FontName = "Calibri";
NPOI.SS.UserModel.ICellStyle normalCell = workbook.CreateCellStyle();
normalCell.FillBackgroundColor = 50;
normalCell.VerticalAlignment = NPOI.SS.UserModel.VerticalAlignment.CENTER;
normalCell.WrapText = true;
normalCell.SetFont(fontShort);
normalCell.BorderBottom = NPOI.SS.UserModel.BorderStyle.THIN;
normalCell.BorderLeft = NPOI.SS.UserModel.BorderStyle.THIN;
normalCell.BorderRight = NPOI.SS.UserModel.BorderStyle.THIN;
normalCell.BorderTop = NPOI.SS.UserModel.BorderStyle.THIN;
NPOI.SS.UserModel.ICellStyle emptyCell = workbook.CreateCellStyle();
emptyCell.SetFont(font);
emptyCell.BorderBottom = NPOI.SS.UserModel.BorderStyle.NONE;
emptyCell.BorderLeft = NPOI.SS.UserModel.BorderStyle.NONE;
emptyCell.BorderRight = NPOI.SS.UserModel.BorderStyle.NONE;
emptyCell.BorderTop = NPOI.SS.UserModel.BorderStyle.NONE;
var headerRow = sheet.CreateRow(0);
var output ="<b>HelloWorld</b>"
var row = sheet.CreateRow(rowNumber++);
row.CreateCell(0).SetCellValue(output);
row.Cells[0].CellStyle = normalCell;
I've seen this question: Creating PowerPoint presentations programmatically, but that question asks "Can you?" to which the answer is "yes".
But I'm asking "How?" and specifically "From a list of images?"
Here's what I do to break a ppt up into images
var app = new PowerPoint.Application();
var pres = app.Presentations;
var file = pres.Open(input, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
file.SaveAs(output, Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsJPG, MsoTriState.msoTrue);
file.Close();
app.Quit();
How do I do the reverse?
It'll be something like this:
string pictureFileName = "C:\\temp\\test.jpg";
Application pptApplication = new Application();
Microsoft.Office.Interop.PowerPoint.Slides slides;
Microsoft.Office.Interop.PowerPoint._Slide slide;
Microsoft.Office.Interop.PowerPoint.TextRange objText;
// Create the Presentation File
Presentation pptPresentation = pptApplication.Presentations.Add(MsoTriState.msoTrue);
Microsoft.Office.Interop.PowerPoint.CustomLayout customLayout = pptPresentation.SlideMaster.CustomLayouts[Microsoft.Office.Interop.PowerPoint.PpSlideLayout.ppLayoutText];
// Create new Slide
slides = pptPresentation.Slides;
slide = slides.AddSlide(1, customLayout);
// Add title
objText = slide.Shapes[1].TextFrame.TextRange;
objText.Text = "test";
objText.Font.Name = "Arial";
objText.Font.Size = 32;
objText = slide.Shapes[2].TextFrame.TextRange;
objText.Text = "Content goes here\nYou can add text\nItem 3";
Microsoft.Office.Interop.PowerPoint.Shape shape = slide.Shapes[2];
slide.Shapes.AddPicture(pictureFileName,Microsoft.Office.Core.MsoTriState.msoFalse,Microsoft.Office.Core.MsoTriState.msoTrue,shape.Left, shape.Top, shape.Width, shape.Height);
slide.NotesPage.Shapes[2].TextFrame.TextRange.Text = "Test";
pptPresentation.SaveAs(#"c:\temp\test.pptx", Microsoft.Office.Interop.PowerPoint.PpSaveAsFileType.ppSaveAsDefault, MsoTriState.msoTrue);
//pptPresentation.Close();
//pptApplication.Quit();
I am trying to convert excel VBA code to c#. This code must be executed outside excel and I am going to convert my excel macros to do so. Here is the code to convert
ActiveWindow.Zoom = 85
Range("A1").Select
Range(Selection, Selection.End(xlToRight)).Select
With Selection
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlBottom
.WrapText = True
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
Cells.Select
Here is what I got so far:
var excelApp = new Microsoft.Office.Interop.Excel.Application();
excelApp.Visible = true;
excelApp.ActiveWindow.Zoom = 85;
excelApp.Range["A1"].Select();
I cannot figure out the rest below the Range("A1").Select. Any help on this
The with statement is a VB thing only, with c# you have to create a variable and call each of the properties from that variable explicitly
ActiveWindow.Zoom = 85;
Range["A1"].Select();
Range(Selection, Selection.End(xlToRight)).Select();
Selection.HorizontalAlignment = xlCenter;
Selection.VerticalAlignment = xlBottom;
Selection.WrapText = true;
Selection.Orientation = 0;
Selection.AddIndent = false;
Selection.IndentLevel = 0;
Selection.ShrinkToFit = false;
Selection.ReadingOrder = xlContext;
Selection.MergeCells = false;
Cells.Select();
(this is just a sample, do adjust your COM handling as required)
EDIT: Changed brackets to square brackets one the second line.
You need the namespace "Microsoft.Office.Interop.Excel".
using Microsoft.Office.Interop.Excel;
MyClass{
...
var app = new Application { Visible = true, ScreenUpdating = true, DisplayAlerts = false };
Workbook book = app.Workbooks.Open(path); //path is the fullFileName as string
Worksheet sheet = book.Worksheets[1];
Range range = sheet.get_Range("A1", "A1");
range.Select();
range.HorizontalAlignment = Constants.xlCenter;
range.VerticalAlignment = Constants.xlBottom;
range.WrapText = true;
range.Orientation = 0;
range.AddIndent = false;
range.IndentLevel = 0;
range.ShrinkToFit = false;
range.ReadingOrder = Constants.xlContext;
range.MergeCells = false;
}
Enjoy it!