Есть ли в Visual Studio API Crystal Reports, который я могу использовать для управления файлами rpt с помощью макроса? - PullRequest
0 голосов
/ 20 декабря 2009

Я бы хотел программно манипулировать своими файлами rpt с помощью макроса или надстройки в Visual Studio 2005. Чего я хочу добиться, так это возможности автоматизировать обновление пользовательских функций в моих отчетах, поскольку, похоже, нет возможности единственная копия функций, совместно используемых отчетами.

Итак, я хотел бы иметь макрос для:

  • Чтение определений функций откуда-то, например, XML-файл в моем проекте
  • Откройте каждый из файлов rpt в моем решении и замените существующие определения функций новыми.

Существует ли API для взаимодействия с файлами rpt таким образом? Любые указатели или примеры будут с благодарностью.

  • Рори

1 Ответ

1 голос
/ 21 декабря 2009

Я думаю, что ответ - нет, в VS Crystal Reports нет. Похоже, что есть API для других версий, например это

В качестве альтернативы я изменил использование большого количества кода в формуле отчета вместо использования пользовательских функций. Затем я могу обновить формулу отчета, используя ReportDocument.DataDefinition.FormulaFields..Text

В моем случае я хочу обновить только одну формулу в каждом отчете с именем «Период». Я создал файл PeriodFormula.txt и включил его в проект с помощью Build Action = EmbeddedResource.

Я создал этот класс для чтения текстового файла и обновления всех отчетов в данном каталоге. В настоящее время он жестко задан для обновления только формулы периода, но его можно легко изменить, чтобы он работал из списка и т. Д.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Text;
using CrystalDecisions.CrystalReports.Engine;
using CrystalDecisions.Shared;

namespace RMReports
{
    public class CustomFunctionUpdater
    {
        /// <summary>
        /// Update all rpt files in the given directory and all subdirectories.
        /// Currently only updates the Period formula.
        /// </summary>
        /// <param name="directoryPath"></param>
        public static void UpdateAllReports(String directoryPath)
        {
            Debug.WriteLine(string.Format("Starting update on all reports within {0}", directoryPath));
            const string formulaName = "Period";
            int reportsUpdated = 0;
            string formulaText = GetFormulaText(formulaName);
            foreach (String filename in Directory.GetFiles(directoryPath, "*.rpt", SearchOption.AllDirectories))
            {
                try
                {
                    if (UpdateReportFunction(filename, formulaName, formulaText))
                    {
                        reportsUpdated++;
                        Debug.WriteLine(string.Format("Updated: {0}", filename));
                    }
                    else
                        Debug.WriteLine(string.Format("No update to: {0}", filename));
                }
                catch(Exception ex)
                {
                    Debug.WriteLine(string.Format("Failed to update: {0}. Error: {1}", filename, ex.Message));
                }
            }
            Debug.WriteLine(string.Format("done. {0} reports updated", reportsUpdated));
        }

        /// <summary>
        /// Opens the given report file, updates the specified formula with the given text 
        /// and saves the report. 
        /// </summary>
        /// <param name="reportFilename">The report file to update</param>
        /// <param name="formulaName">The name of the formula to update</param>
        /// <param name="formulaText">The new text of the formula to update</param>
        /// <returns>Whether the report was updated. If the formula doesn't exist this will be false.</returns>
        public static bool UpdateReportFunction(String reportFilename, String formulaName, string formulaText)
        {
            if (String.IsNullOrEmpty(formulaText)) return false;
            if (!File.Exists(reportFilename)) throw new FileNotFoundException("reportFilename", reportFilename);

            bool updated = false;
            ReportDocument document = new ReportDocument();
            try
            {
                document.Load(reportFilename, OpenReportMethod.OpenReportByDefault);
                foreach (FormulaFieldDefinition f in document.DataDefinition.FormulaFields)
                {
                    if (f.Name != formulaName) continue;
                    if (f.Text == formulaText) break;           // no update needed
                    f.Text = formulaText;       
                    updated = true;
                    break;
                }
                if (updated)
                    document.SaveAs(reportFilename);
            }
            finally
            {
                if (document.IsLoaded)
                    document.Close();
            }
            return updated;
        }

        public static void UpdateReportFunction(String reportFilename, String formulaName)
        {
            string formulaText = GetFormulaText(formulaName);
            UpdateReportFunction(reportFilename, formulaName, formulaText);
        }

        /// <summary>
        /// Reads the text for the given formula from the current assembly. Assumes the formula 
        /// exists in a file named [formulaName]Formula.txt that's been compiled as an embedded resource
        /// in the current assembly, e.g. DoStuffFormula.txt for a formula named DoStuff.
        /// </summary>
        /// <param name="formulaName"></param>
        /// <returns></returns>
        public static String GetFormulaText(String formulaName)
        {
            string resourceName = Assembly.GetExecutingAssembly().GetName().Name + "." + formulaName + "Formula.txt";
            Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);
            if (stream==null) return null;
            return (new StreamReader(stream)).ReadToEnd();
        }
    }
}

Затем я использую это, чтобы обновить все мои отчеты (которые находятся в папках под папкой «отчеты»).

DirectoryInfo d = Directory.GetParent(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location));
string reportDirectory = Path.Combine(d.Parent.FullName, "reports");
CustomFunctionUpdater.UpdateAllReports(reportDirectory);

Надеюсь, кто-то найдет это полезным!

...