在visual studio中是否有一个水晶报告API,我可以使用宏来操作rpt文件?

时间:2009-12-20 19:36:01

标签: visual-studio visual-studio-2005 crystal-reports macros

我想在Visual Studio 2005中使用宏或加载项以编程方式操作我的rpt文件。我想要实现的是能够自动更新报表中的自定义函数,因为似乎没有办法报告之间共享的功能的单个副本。

所以我想要一个宏:

  • 从某处读取函数定义,例如项目中的xml文件
  • 打开我的解决方案中的每个rpt文件,并用新的函数定义替换现有的函数定义。

是否有以这种方式与rpt文件交互的API?任何指针或例子将不胜感激。

1 个答案:

答案 0 :(得分:1)

我认为答案是否定的,VS Crystal Reports中没有。它看起来像其他版本的API,例如this

作为替代方案,我已更改为在报表公式中包含大量代码,而不是使用自定义函数。然后,我可以使用ReportDocument.DataDefinition.FormulaFields..Text

更新报告公式

在我的情况下,我只想更新每个报告中的一个公式,名为“期间”。我创建了一个文件PeriodFormula.txt并将其包含在项目中,其中包含Build Action = EmbeddedResource。

我创建了这个类来读取txt文件并更新给定目录中的所有报告。它目前硬编码只更新Period公式,但可以很容易地修改为从列表等操作。

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();
        }
    }
}

然后我像这样使用它来更新我的所有报告(位于'reports'文件夹下的文件夹中)。

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

希望其他人觉得这很有用!