C# Windows 窗体将 DatagridView 内容添加到 PowerPoint 幻灯片中

C# WindowsForm Add DatagridView Content into PowerPoint's slide

我正在使用 .NET 4.7.2、Windowsform。

我有一个 datagridview,我设法生成了一个 powerpoint 文件 pptx。 我制作了第一张 ppt 幻灯片,我想将 datagridview 内容添加到第二张 ppt 幻灯片中,因为我需要可以选择更改 PPt 幻灯片中的数据。

Microsoft.Office.Interop.PowerPoint.Application pptApp = new Microsoft.Office.Interop.PowerPoint.Application();
pptApp.Visible = Microsoft.Office.Core.MsoTriState.msoTrue;
Microsoft.Office.Interop.PowerPoint.Slides slides;
Microsoft.Office.Interop.PowerPoint._Slide slide;
Microsoft.Office.Interop.PowerPoint._Slide slide2;
Microsoft.Office.Interop.PowerPoint.TextRange objText;

// Create File
Presentation pptPresentation = pptApp.Presentations.Add(Microsoft.Office.Core.MsoTriState.msoTrue);
CustomLayout customLayout = pptPresentation.SlideMaster.CustomLayouts[PpSlideLayout.ppLayoutText];

// new Slide
slides = pptPresentation.Slides;
slide = slides.AddSlide(1, customLayout);
slide2 = slides.AddSlide(1, customLayout);

// title
objText = slide.Shapes[1].TextFrame.TextRange;
objText.Text = "Bonds Screner Report";
objText.Font.Name = "Haboro Contrast Ext Light";
objText.Font.Size = 32;

Shape shape1 = slide.Shapes[2];
slide.Shapes.AddPicture("C:\mylogo.png", Microsoft.Office.Core.MsoTriState.msoFalse,    Microsoft.Office.Core.MsoTriState.msoTrue, shape1.Left, shape1.Top, shape1.Width, shape1.Height);
slide.NotesPage.Shapes[2].TextFrame.TextRange.Text = "Disclaimer";
dataGridViewBonds.ClipboardCopyMode = DataGridViewClipboardCopyMode.EnableAlwaysIncludeHeaderText;
dataGridViewBonds.SelectAll();
DataObject obj = dataGridViewBonds.GetClipboardContent();
Clipboard.SetDataObject(obj, true);
Shape shapegrid = slide2.Shapes[2];

我知道我现在还不远,但我想念一些东西。任何帮助将不胜感激!

我熟悉 Excel interop 并使用过它很多次,很可能已经对 interop 的笨拙工作方式感到麻木了。由于多种原因,使用 PowerPoint 互操作可能会非常令人沮丧,但是,我最大的感受是缺乏文档以及不同 MS 版本之间的差异。

此外,我寻找了一个 third-party PowerPoint 库,“Aspose”看起来是唯一的选择,不幸的是它不是“免费”选项。我会假设有一个免费的 third-party 选项,我只是没有找对地方……或者可能有一种完全不同的方法可以用 XML 来做到这一点。我有信心向唱诗班布道。

因此,我整理的内容可能对您有用。对于初学者,查看您当前发布的代码,缺少一个部分,您需要将“复制的”网格单元格放入幻灯片中……

slide.Shapes.Paste();

这会将网格中“复制的”单元格粘贴到幻灯片中的“未格式化”table。如果网格 AllowUserToAddRows 设置为 true,除了复制“新行”之外,这将复制“行 header”(如果它显示在网格中)。如果这个“无格式粘贴”适合你,那么你就可以开始了。

如果您希望至少有一个最小格式的 table 并忽略行 headers 和最后一个空行......简单地“创建”一个新的 Table 可能更容易] 在幻灯片中使用我们想要的大小以及正确的行数和列数。当然,这可能需要更多工作,但是,无论如何,使用粘贴都需要这个“如果”你想要 table 格式化。

该方法(如下)需要一个功率点 _Slide 和一个 DataGridView。代码根据给定网格中的行数和列数在幻灯片中“创建”一个新的 Table。通过这种方法,table 将在演示文稿中使用默认的“Table 样式”进行“格式化”。因此,这可能会通过简单地“创建”table 而不是“粘贴”table.

来为您提供所需的格式

我曾尝试在 powerpoint 中“应用”现有的“Table 样式”之一,但是,我看到的示例使用了类似...

table.ApplyStyle("{5C22544A-7EE6-4342-B048-85BDC9FD1C3A}");

它使用 GUID id 来标识要使用的“哪种”样式。我不确定为什么 MS 决定采用这种 GUID 方法……这超出了我的范围,它适用于“某些”样式但不是全部。

此外,更多 common-sense 解决方案显示出类似...

table.StylePreset = TableStylePreset.MediumStyle2Accent2;

不幸的是,我使用的是 2019 版 Office PowerPoint,这个 属性 不存在。我已经放弃了对此的进一步研究,因为它似乎与版本有关。很烦人!

鉴于此,如果我们根据需要单独格式化单元格可能会更容易。无论如何,我们都需要将网格中的单元格文本添加到各个单元格中,因此我们也可以同时格式化各个单元格。同样,我相信有更好的方法,但是我找不到。

下面的InsertTableIntoSlide(_Slide slide, DataGridView dgv)方法以幻灯片和网格作为参数。它将使用给定网格中的数据向幻灯片添加 table。下面是一个简短的代码跟踪。

首先进行检查以获取网格中的总行数(不包括 headers)totRows。如果网格 AllowUsersToAddRowstrue,则总行数变量减 1 以忽略此新行。接下来,网格中的列数设置为变量 totCols。左上角的 X 和 Y 点定义为 topLeftXtopLeftY 以在幻灯片中定位 table 以及 tables widthheight.

添加注意: 使用 AllowUserToAddRows 属性 来确定行数......可能不起作用如上所述,将“错过”最后一行……“IF”AllowUserToAddRowstrue(默认)并且网格数据绑定到不允许添加新行的数据源。在那种情况下,您不想减少 totRows 变量。

接下来使用前面的变量将“Table”“形状”添加到幻灯片以定义基本 table 尺寸。接下来是两个循环。第一个循环将 header 单元格添加到 table 的第一行。然后是第二个循环,将网格中单元格的数据添加到幻灯片中的 table 个单元格。

commented-out 代码留作示例,您希望对单个单元格进行一些特定的格式化。这在我的案例中是不需要的,因为“默认”table 样式接近我想要的格式。

此外,请注意“前景色”是 cell/shape 的“背景”颜色。奇怪!

我希望这对您有所帮助,再次对必须使用 PowerPoint 互操作表示同情……我不能。

private void InsertTableIntoSlide(_Slide slide, DataGridView dgv) {
  try {
    int totRows;
    if (dgv.AllowUserToAddRows) {
      totRows = dgv.Rows.Count - 1;
    }
    else {
      totRows = dgv.Rows.Count;
    }
    int totCols = dgv.Columns.Count;
    int topLeftX = 10;
    int topLeftY = 10;
    int width = 400;
    int height = 100;
    // add extra row for header row
    Shape shape = slide.Shapes.AddTable(totRows + 1, totCols, topLeftX, topLeftY, width, height);
    Table table = shape.Table;
    for (int i = 0; i < dgv.Columns.Count; i++) {
      table.Cell(1, i+1).Shape.TextFrame.TextRange.Text = dgv.Columns[i].HeaderText;
      //table.Cell(1, i+1).Shape.Fill.ForeColor.RGB = ColorTranslator.ToOle(Color.Blue);
      //table.Cell(1, i+1).Shape.TextFrame.TextRange.Font.Bold = Microsoft.Office.Core.MsoTriState.msoTrue;
      //table.Cell(1, i+1).Shape.TextFrame.TextRange.Font.Color.RGB = ColorTranslator.ToOle(Color.White);
    }
    int curRow = 2;
    for (int i = 0; i < totRows; i++) {
      for (int j = 0; j < totCols; j++) {
        if (dgv.Rows[i].Cells[j].Value != null) {
          table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Text = dgv.Rows[i].Cells[j].Value.ToString();
          //table.Cell(curRow, j + 1).Shape.Fill.ForeColor.RGB = ColorTranslator.ToOle(Color.LightGreen);
          //table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Font.Bold = Microsoft.Office.Core.MsoTriState.msoTrue;
          //table.Cell(curRow, j + 1).Shape.TextFrame.TextRange.Font.Color.RGB = ColorTranslator.ToOle(Color.Black);
        }
      }
      curRow++;
    }
  }
  catch (Exception ex) {
    MessageBox.Show("Error: " + ex.Message);
  }
}