如何将 C# Control 加上额外的文本保存到磁盘?

How to save C# Control plus extra text to disk?

我有一个 C# 程序,它是一个 控制台应用程序 ,但使用了来自 System.Windows.Forms.DataVisualization.Charting 的图表对象,而没有将 Chart 附加到Form.

基本上我需要在 Chart 控件上生成一个圆环图,在圆环的中心打印一些文本,然后将图形和文本保存到磁盘上的文件中。

如果我在 PrePaint 事件中创建一个 TextAnnotation,然后使用 DrawToBitmap 将图表保存到磁盘,覆盖的文本不会显示在磁盘上的文件中,即使我使用 Chart.FlushChart.Update 等的各种组合。据我所知,事件正在被触发并且 TextAnnotation 代码正在 运行.

另一方面,如果我根本不使用事件,而是从 Chart.CreateGraphics 获取一个 Graphics 对象,然后 Graphics.DrawString 打印文本,然后 Graphics.FlushChart.DrawToBitmap,还是没有显示文字。

我猜这是因为 Chart.DrawToBitmap 不知道用 Chart.CreateGraphics 绘制的额外内容,尽管我假设 Graphics.Flush 会处理这些。

保存图形和文本的最佳方式是什么?

编辑:按要求添加代码:

static void Main(string[] args)
{
    String[] labels = { "Green", "Red", "Yellow", "Dark Red", "Blue" };
    Color[] colours = { Color.Green, Color.Red, Color.Yellow, Color.DarkRed, Color.Blue };
    Random rng = new Random();

    Chart chart = new Chart();
    chart.Size = new Size(320, 320);

    ChartArea area = new ChartArea();
    Series series = new Series();

    chart.ChartAreas.Add(area);

    series.ChartArea = area.Name;
    series.ChartType = SeriesChartType.Doughnut;
    series.IsValueShownAsLabel = true;

    int total = 0;
    for (int i = 0; i != labels.Length; i++)
    {
        int value = rng.Next(0, 50);
        DataPoint p = new DataPoint(0, value);
        total += value;
        p.Color = colours[i];
        p.Label = String.Empty;
        p.Font = new Font("Microsoft Sans Serif", 10, FontStyle.Bold);
        series.Points.Add(p);
    }

    series.Tag = total;
    chart.Series.Add(series);
    chart.Refresh();

    using (Graphics g = chart.CreateGraphics())
    {
        String str = series.Tag.ToString();
        Font font = new Font("Microsoft Sans Serif", 32, FontStyle.Bold);
        SizeF strSize = g.MeasureString(str, font);

        int strX = 100; int strY = 100;

        g.DrawString(str, font, new SolidBrush(Color.Black), strX, strY);
        g.DrawRectangle(new Pen(Color.Black), new Rectangle(strX, strY, (int)strSize.Width, (int)strSize.Height));

        g.Flush();
    }

    String chartFilename = "chart.bmp";
    String chartPath = Path.Combine("C:\Temp", chartFilename);

    using (Bitmap bmp = new Bitmap(chart.Width, chart.Height))
    {
        chart.DrawToBitmap(bmp, chart.Bounds);
        bmp.Save(chartPath);
    }

    System.Diagnostics.Process.Start("mspaint.exe", chartPath);
}

我怀疑图表在您的标签上方绘制。当您调用 DrawToBitmap 时,图表只会考虑它知道的视觉对象,而不是之后在顶部绘制的元素。

您需要颠倒绘图顺序。即

  1. 将图表绘制到位图中
  2. 将位图与预渲染图表放在一起,在顶部绘制标签

代码:

using (Bitmap bmp = new Bitmap(chart.Width, chart.Height))
{
    chart.DrawToBitmap(bmp, chart.Bounds); // draw chart into bitmap first!

    using (Graphics g = Graphics.FromImage(bmp)) // <--- new
    {
        // now draw label
        String str = series.Tag.ToString();
        Font font = new Font("Microsoft Sans Serif", 32, FontStyle.Bold);
        SizeF strSize = g.MeasureString(str, font);

        int strX = 100; int strY = 100;

        g.DrawString(str, font, new SolidBrush(Color.Black), strX, strY);
        g.DrawRectangle(new Pen(Color.Black), new Rectangle(strX, strY, (int)strSize.Width, (int)strSize.Height));

        g.Flush();
    }

    bmp.Save(chartPath);
}

编辑:请务必在下面的评论中遵循 Jimi's 建议:

"reference System.Drawing.Imaging, to have PixelFormat and ImageFormat available. At this moment, the image is saved as with a .bmp extension, while it's a .png file (the default)"