using FastReport.Code; using FastReport.CrossView; using FastReport.Data; using FastReport.Dialog; using FastReport.Engine; using FastReport.Export; using FastReport.Utils; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Diagnostics; using System.Drawing; using System.Drawing.Text; using System.IO; using System.Linq; using System.Linq.Expressions; using System.Security; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace FastReport { /// /// Specifies the language of the report's script. /// public enum Language { /// /// The C# language. /// CSharp, /// /// The VisualBasic.Net language. /// Vb } /// /// Specifies the quality of text rendering. /// public enum TextQuality { /// /// The default text quality, depends on system settings. /// Default, /// /// The regular quality. /// Regular, /// /// The "ClearType" quality. /// ClearType, /// /// The AntiAlias quality. This mode may be used to produce the WYSIWYG text. /// AntiAlias, /// /// The "SingleBitPerPixel" quality. /// SingleBPP, /// /// The "SingleBitPerPixelGridFit" quality. /// SingleBPPGridFit } /// /// Specifies the report operation. /// public enum ReportOperation { /// /// Specifies no operation. /// None, /// /// The report is running. /// Running, /// /// The report is printing. /// Printing, /// /// The report is exporting. /// Exporting } /// /// Specifies the page range to print/export. /// public enum PageRange { /// /// Print all pages. /// All, /// /// Print current page. /// Current, /// /// Print pages specified in the PageNumbers property of the PrintSettings. /// PageNumbers } public class ReportLogEventArgs : EventArgs { public bool IsError { get; private set; } public string Message { get; private set; } public ReportLogEventArgs(bool iserror, string message) { IsError = iserror; Message = message; } } public delegate void ReportLogEvent(object sender, ReportLogEventArgs args); /// /// Represents a report object. /// /// /// The instance of this class contains a report. Here are some common /// actions that can be performed with this object: /// /// /// To load a report, use the /// method or call static method. /// /// /// To save a report, call the method. /// /// /// To register application dataset for use it in a report, call one of the /// RegisterData methods. /// /// /// To pass some parameter to a report, use the /// method. /// /// /// To design a report, call the method. /// /// /// To run a report and preview it, call the method. /// Another way is to call the method, then call the /// method. /// /// /// To run a report and print it, call the method. /// Another way is to call the method, then call the /// method. /// /// /// To load/save prepared report, use one of the LoadPrepared and /// SavePrepared methods. /// /// /// To set up some global properties, use the static class /// or component that you can use in the Visual Studio IDE. /// /// /// /// The report consists of one or several report pages (pages of the /// type) and/or dialog forms (pages of the type). /// They are stored in the collection. In turn, each page may contain report /// objects. See the example below how to create a simple report in code. /// /// This example shows how to create a report instance, load it from a file, /// register the application data, run and preview. /// /// Report report = new Report(); /// report.Load("reportfile.frx"); /// report.RegisterData(application_dataset); /// report.Show(); /// /// This example shows how to create simple report in code. /// /// Report report = new Report(); /// // create the report page /// ReportPage page = new ReportPage(); /// page.Name = "ReportPage1"; /// // set paper width and height. Note: these properties are measured in millimeters. /// page.PaperWidth = 210; /// page.PaperHeight = 297; /// // add a page to the report /// report.Pages.Add(page); /// // create report title /// page.ReportTitle = new ReportTitleBand(); /// page.ReportTitle.Name = "ReportTitle1"; /// page.ReportTitle.Height = Units.Millimeters * 10; /// // create Text object and put it to the title /// TextObject text = new TextObject(); /// text.Name = "Text1"; /// text.Bounds = new RectangleF(0, 0, Units.Millimeters * 100, Units.Millimeters * 5); /// page.ReportTitle.Objects.Add(text); /// // create data band /// DataBand data = new DataBand(); /// data.Name = "Data1"; /// data.Height = Units.Millimeters * 10; /// // add data band to a page /// page.Bands.Add(data); /// /// public partial class Report : Base, IParent, ISupportInitialize { #region Fields private PageCollection pages; private Dictionary dictionary; private ReportInfo reportInfo; private string baseReport; private Report baseReportObject; private string baseReportAbsolutePath; private string fileName; private string scriptText; private Language scriptLanguage; private bool compressed; private bool useFileCache; private TextQuality textQuality; private bool smoothGraphics; private string password; private bool convertNulls; private bool doublePass; private bool autoFillDataSet; private int initialPageNumber; private int maxPages; private string startReportEvent; private string finishReportEvent; private StyleCollection styles; private CodeHelperBase codeHelper; private GraphicCache graphicCache; private string[] referencedAssemblies; private Hashtable cachedDataItems; private AssemblyCollection assemblies; private FastReport.Preview.PreparedPages preparedPages; private ReportEngine engine; private bool aborted; private Bitmap measureBitmap; private IGraphics measureGraphics; private bool storeInResources; private PermissionSet scriptRestrictions; private ReportOperation operation; private bool needCompile; private bool scriptChanged = false; private bool needRefresh; private bool isParameterChanged = false; private bool initializing; private object initializeData; private string initializeDataName; private object tag; private bool isLoadPrepared = false; #endregion Fields #region Properties /// /// Occurs when calc execution is started. /// public event CustomCalcEventHandler CustomCalc; /// /// Occurs when report is inherited and trying to load a base report. /// /// /// Typical use of this event is to load the base report from a database instead of a file. /// public event CustomLoadEventHandler LoadBaseReport; /// /// Occurs when report execution is started. /// public event EventHandler StartReport; /// /// Occurs when report execution is finished. /// public event EventHandler FinishReport; /// /// Occurs before export to set custom export parameters. /// public event EventHandler ExportParameters; /// /// Gets the pages contained in this report. /// /// /// This property contains pages of all types (report and dialog). Use the is/as operators /// if you want to work with pages of ReportPage type. /// /// The following code demonstrates how to access the first report page: /// /// ReportPage page1 = report1.Pages[0] as ReportPage; /// /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PageCollection Pages { get { return pages; } } /// /// Gets the report's data. /// /// /// The dictionary contains all data items such as connections, data sources, parameters, /// system variables. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Dictionary Dictionary { get { return dictionary; } set { SetProp(dictionary, value); dictionary = value; } } /// /// Gets the collection of report parameters. /// /// /// Parameters are displayed in the "Data" window under the "Parameters" node. /// Typical use of parameters is to pass some static data from the application to the report. /// You can print such data, use it in the data row filter, script etc. /// Another way to use parameters is to define some reusable piece of code, for example, /// to define an expression that will return the concatenation of first and second employee name. /// In this case, you set the parameter's Expression property to something like this: /// [Employees.FirstName] + " " + [Employees.LastName]. Now this parameter may be used in the report /// to print full employee name. Each time you access such parameter, it will calculate the expression /// and return its value. /// You can create nested parameters. To do this, add the new Parameter to the /// Parameters collection of the root parameter. To access the nested parameter, you may use the /// method. /// To get or set the parameter's value, use the and /// methods. To set the parameter's expression, use the /// method that returns a Parameter object and set its /// Expression property. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ParameterCollection Parameters { get { return dictionary.Parameters; } } /// /// Gets or sets the report information such as report name, author, description etc. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Design")] public ReportInfo ReportInfo { get { return reportInfo; } set { reportInfo = value; } } /// /// Gets or sets the base report file name. /// /// /// This property contains the name of a report file this report is inherited from. /// Note: setting this property to non-empty value will clear the report and /// load the base file into it. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string BaseReport { get { return baseReport; } set { SetBaseReport(value); } } /// /// Gets a value indicating whether Report is prepared /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool IsPrepared { get { return !isParameterChanged && PreparedPages != null && PreparedPages.Count != 0; } } /// /// Gets or sets the absolute path to the parent report. /// /// /// This property contains the absolute path to the parent report. /// [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string BaseReportAbsolutePath { get { return baseReportAbsolutePath; } set { baseReportAbsolutePath = value; } } /// /// Gets or sets the name of a file the report was loaded from. /// /// /// This property is used to support the FastReport.Net infrastructure; /// typically you don't need to use it. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string FileName { get { return fileName; } set { fileName = value; } } /// /// Gets or sets the report script. /// /// /// The script contains the ReportScript class that contains all report objects' /// event handlers and own items such as private fields, properties, methods etc. The script /// contains only items written by you. Unlike other report generators, the script does not /// contain report objects declarations, initialization code. It is added automatically when /// you run the report. /// By default this property contains an empty script text. You may see it in the designer /// when you switch to the Code window. /// If you set this property programmatically, you have to declare the FastReport /// namespace and the ReportScript class in it. Do not declare report items (such as bands, /// objects, etc) in the ReportScript class: the report engine does this automatically when /// you run the report. /// Security note: since the report script is compiled into .NET assembly, it allows /// you to do ANYTHING. For example, you may create a script that will read/write files from/to a disk. /// To restrict such operations, use the property. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string ScriptText { get { return scriptText; } set { scriptText = value; scriptChanged = scriptText != codeHelper.EmptyScript(); } } /// /// Gets or sets the script language of this report. /// /// /// Note: changing this property will reset the report script to default empty script. /// [DefaultValue(Language.CSharp)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Script")] public Language ScriptLanguage { get { return scriptLanguage; } set { bool needClear = scriptLanguage != value; scriptLanguage = value; if (scriptLanguage == Language.CSharp) codeHelper = new CsCodeHelper(this); else codeHelper = new VbCodeHelper(this); if (needClear) { scriptText = codeHelper.EmptyScript(); scriptChanged = false; } } } /// /// Gets or sets a value indicating whether the null DB value must be converted to zero, false or /// empty string depending on the data column type. /// /// /// This property is true by default. If you set it to false, you should check /// the DB value before you do something with it (for example, typecast it to any type, use it /// in a expression etc.) /// [DefaultValue(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Engine")] public bool ConvertNulls { get { return convertNulls; } set { convertNulls = value; } } /// /// Gets or sets a value that specifies whether the report engine should perform the second pass. /// /// /// Typically the second pass is necessary to print the number of total pages. It also /// may be used to perform some calculations on the first pass and print its results on the /// second pass. /// Use the Engine.FirstPass, Engine.FinalPass properties to determine which /// pass the engine is performing now. /// [DefaultValue(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Engine")] public bool DoublePass { get { return doublePass; } set { doublePass = value; } } /// /// Gets or sets a value that specifies whether to compress the report file. /// /// /// The report file is compressed using the Gzip algorithm. So you can open the /// compressed report in any zip-compatible archiver. /// [DefaultValue(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Misc")] public bool Compressed { get { return compressed; } set { compressed = value; } } /// /// Returns a bool value depending on the .frx or .fpx report was loaded /// public bool IsLoadPrepared { get => isLoadPrepared; } /// /// Gets or sets a value that specifies whether to use the file cache rather than memory /// to store the prepared report pages. /// [DefaultValue(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Engine")] public bool UseFileCache { get { return useFileCache; } set { useFileCache = value; } } /// /// Gets or sets a value that specifies the quality of text rendering. /// /// /// Note: the default property value is TextQuality.Default. That means the report /// may look different depending on OS settings. This property does not affect the printout. /// [DefaultValue(TextQuality.Default)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Misc")] public TextQuality TextQuality { get { return textQuality; } set { textQuality = value; } } /// /// Gets or sets a value that specifies if the graphic objects such as bitmaps /// and shapes should be displayed smoothly. /// [DefaultValue(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Misc")] public bool SmoothGraphics { get { return smoothGraphics; } set { smoothGraphics = value; } } /// /// Gets or sets the report password. /// /// /// When you try to load the password-protected report, you will be asked /// for a password. You also may specify the password in this property before loading /// the report. In this case the report will load silently. /// Password-protected report file is crypted using Rijndael algorithm. /// Do not forget your password! It will be hard or even impossible to open /// the protected file in this case. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public string Password { get { return password; } set { password = value; } } /// /// Gets or sets a value indicating whether it is necessary to automatically fill /// DataSet registered with RegisterData call. /// /// /// If this property is true (by default), FastReport will automatically fill /// the DataSet with data when you trying to run a report. Set it to false if /// you want to fill the DataSet by yourself. /// [DefaultValue(true)] [SRCategory("Misc")] public bool AutoFillDataSet { get { return autoFillDataSet; } set { autoFillDataSet = value; } } /// /// Gets or sets the maximum number of generated pages in a prepared report. /// /// /// Use this property to limit the number of pages in a prepared report. /// [DefaultValue(0)] [SRCategory("Misc")] public int MaxPages { get { return maxPages; } set { maxPages = value; } } /// /// Gets or sets the collection of styles used in this report. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Misc")] public StyleCollection Styles { get { return styles; } set { styles = value; } } /// /// Gets or sets an array of assembly names that will be used to compile the report script. /// /// /// By default this property contains the following assemblies: "System.dll", "System.Drawing.dll", /// "System.Windows.Forms.dll", "System.Data.dll", "System.Xml.dll". If your script uses some types /// from another assemblies, you have to add them to this property. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Script")] public string[] ReferencedAssemblies { get { return referencedAssemblies; } set { if (value != null) { // fix for old reports with "System.Windows.Forms.DataVisualization" in referenced assemblies for (int i = 0; i < value.Length; i++) { value[i] = value[i].Replace("System.Windows.Forms.DataVisualization", "FastReport.DataVisualization"); } } referencedAssemblies = value; } } /// /// Gets or sets a script event name that will be fired when the report starts. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Build")] public string StartReportEvent { get { return startReportEvent; } set { startReportEvent = value; } } /// /// Gets or sets a script event name that will be fired when the report is finished. /// [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] [SRCategory("Build")] public string FinishReportEvent { get { return finishReportEvent; } set { finishReportEvent = value; } } /// /// Gets a value indicating that report execution was aborted. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool Aborted { get { Config.DoEvent(); return aborted; } } /// /// Gets or sets a value that determines whether to store the report in the application resources. /// Use this property in the MS Visual Studio IDE only. /// /// /// By default this property is true. When set to false, you should store your report /// in a file. /// [DefaultValue(true)] [SRCategory("Design")] public bool StoreInResources { get { return storeInResources; } set { storeInResources = value; } } /// /// Gets or sets the resource string that contains the report. /// /// /// This property is used by the MS Visual Studio to store the report. Do not use it directly. /// [Browsable(false)] [Localizable(true)] public string ReportResourceString { get { if (!StoreInResources) return ""; return SaveToString(); } set { if (String.IsNullOrEmpty(value)) { Clear(); return; } LoadFromString(value); } } /// /// Gets a value indicating that this report contains dialog forms. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public bool HasDialogs { get { foreach (PageBase page in Pages) { if (page is DialogPage) return true; } return false; } } /// /// Gets or sets a set of permissions that will be restricted for the script code. /// /// /// Since the report script is compiled into .NET assembly, it allows you to do ANYTHING. /// For example, you may create a script that will read/write files from/to a disk. This property /// is used to restrict such operations. /// This example shows how to restrict the file IO operations in a script: /// /// using System.Security; /// using System.Security.Permissions; /// ... /// PermissionSet ps = new PermissionSet(PermissionState.None); /// ps.AddPermission(new FileIOPermission(PermissionState.Unrestricted)); /// report1.ScriptRestrictions = ps; /// report1.Prepare(); /// /// /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public PermissionSet ScriptRestrictions { get { return scriptRestrictions; } set { scriptRestrictions = value; } } /// /// Gets a reference to the graphics cache for this report. /// /// /// This property is used to support the FastReport.Net infrastructure. Do not use it directly. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public GraphicCache GraphicCache { get { return graphicCache; } } /// /// Gets a pages of the prepared report. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public Preview.PreparedPages PreparedPages { get { return preparedPages; } } /// /// Gets a reference to the report engine. /// /// /// This property can be used when report is running. In other cases it returns null. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public ReportEngine Engine { get { return engine; } } /// /// Gets or sets the initial page number for PageN/PageNofM system variables. /// [DefaultValue(1)] [SRCategory("Engine")] public int InitialPageNumber { get { return initialPageNumber; } set { initialPageNumber = value; } } /// /// This property is not relevant to this class. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new string Name { get { return base.Name; } } /// /// This property is not relevant to this class. /// [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public new Restrictions Restrictions { get { return base.Restrictions; } set { base.Restrictions = value; } } /// /// Gets the report operation that is currently performed. /// [Browsable(false)] public ReportOperation Operation { get { return operation; } } /// /// Gets or sets the Tag object of the report. /// [Browsable(false)] public object Tag { get { return tag; } set { tag = value; } } private string[] DefaultAssemblies { get { return new string[] { "System.dll", "System.Drawing.dll", "System.Data.dll", "System.Xml.dll", "FastReport.Compat.dll", #if !CROSSPLATFORM && !(WPF || AVALONIA) "System.Windows.Forms.dll", #endif #if WPF "FastReport.Forms.WPF.dll", #endif #if AVALONIA "FastReport.Forms.Avalonia.dll", #endif #if CROSSPLATFORM || COREWIN "System.Drawing.Primitives", #endif #if MSCHART "FastReport.DataVisualization.dll" #endif }; } } internal CodeHelperBase CodeHelper { get { return codeHelper; } } public IGraphics MeasureGraphics { get { if (measureGraphics == null) { #if CROSSPLATFORM || MONO measureBitmap = new Bitmap(1, 1); measureGraphics = new GdiGraphics(measureBitmap); #else measureGraphics = GdiGraphics.FromGraphics(Graphics.FromHwnd(IntPtr.Zero)); #endif } return measureGraphics; } } public string GetReportName { get { string result = ReportInfo.Name; if (String.IsNullOrEmpty(result)) result = Path.GetFileNameWithoutExtension(FileName); return result; } } /// /// Gets or sets the flag for refresh. /// public bool NeedRefresh { get { return needRefresh; } set { needRefresh = value; } } internal ObjectCollection AllNamedObjects { get { ObjectCollection allObjects = AllObjects; // data objects are not included into AllObjects list. Include named items separately. foreach (Base c in Dictionary.AllObjects) { if (c is DataConnectionBase || c is DataSourceBase || c is Relation || c is CubeSourceBase) allObjects.Add(c); } return allObjects; } } #endregion Properties #region Logging public event ReportLogEvent Log; public void DoLog(bool iserror, string message) => Log?.Invoke(this, new ReportLogEventArgs(iserror, message)); #endregion` #region Private Methods private bool ShouldSerializeReferencedAssemblies() { return Converter.ToString(ReferencedAssemblies) != Converter.ToString(DefaultAssemblies); } // convert absolute path to the base report to relative path (based on the main report path). private string GetRelativePathToBaseReport() { string path = ""; if (!String.IsNullOrEmpty(FileName)) { try { path = Path.GetDirectoryName(FileName); } catch { } } if (!String.IsNullOrEmpty(path)) { try { return FileUtils.GetRelativePath(BaseReport, path); } catch { } } return BaseReport; } private void SetBaseReport(string value) { baseReport = value; if (baseReportObject != null) { baseReportObject.Dispose(); baseReportObject = null; } // detach the base report if (String.IsNullOrEmpty(value)) { foreach (Base c in AllObjects) { c.SetAncestor(false); } SetAncestor(false); return; } string saveFileName = fileName; if (LoadBaseReport != null) { LoadBaseReport(this, new CustomLoadEventArgs(value, this)); } else { // convert the relative path to absolute path (based on the main report path). if (!Path.IsPathRooted(value)) { var fullPath = Path.GetFullPath(Path.GetDirectoryName(FileName)); // since directory path separator for Win OS is '\' and for Unix OS is '/' // we have to modify the incoming path string with actual for current OS path separator value = Path.Combine(fullPath, GetFixedSeparatedPath(value)); } if (!File.Exists(value) && File.Exists(BaseReportAbsolutePath)) { value = BaseReportAbsolutePath; } Load(value); } fileName = saveFileName; baseReport = ""; Password = ""; baseReportObject = Activator.CreateInstance(GetType()) as Report; baseReportObject.AssignAll(this, true); // set Ancestor & CanChangeParent flags foreach (Base c in AllObjects) { c.SetAncestor(true); } SetAncestor(true); baseReport = value; } private static string GetFixedSeparatedPath(string baseReport) { return baseReport.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar); } private void GetDiff(object sender, DiffEventArgs e) { if (baseReportObject != null) { if (e.Object is Report) e.DiffObject = baseReportObject; else if (e.Object is Base) e.DiffObject = baseReportObject.FindObject((e.Object as Base).Name); } } private void ClearReportProperties() { ReportInfo.Clear(); Dictionary.Clear(); if (IsDesigning) { ScriptLanguage = Config.ReportSettings.DefaultLanguage; } else { ScriptLanguage = Language.CSharp; } // not property, only field! scriptText = codeHelper.EmptyScript(); scriptChanged = false; BaseReport = ""; BaseReportAbsolutePath = ""; DoublePass = false; ConvertNulls = true; Compressed = false; TextQuality = TextQuality.Default; SmoothGraphics = false; Password = ""; InitialPageNumber = 1; MaxPages = 0; ClearDesign(); Styles.Clear(); Styles.Name = ""; referencedAssemblies = DefaultAssemblies; StartReportEvent = ""; FinishReportEvent = ""; #if REFLECTION_EMIT_COMPILER _cachedParsedExpressions.Clear(); #endif needCompile = true; } #endregion Private Methods #region Protected Methods /// protected override void Dispose(bool disposing) { if (disposing) { if (graphicCache != null) graphicCache.Dispose(); graphicCache = null; if (measureGraphics != null) measureGraphics.Dispose(); measureGraphics = null; if (measureBitmap != null) measureBitmap.Dispose(); measureBitmap = null; DisposeDesign(); if (PreparedPages != null) PreparedPages.Dispose(); } base.Dispose(disposing); } /// protected override void DeserializeSubItems(FRReader reader) { if (String.Compare(reader.ItemName, "ScriptText", true) == 0) ScriptText = reader.ReadPropertyValue(); else if (String.Compare(reader.ItemName, "Dictionary", true) == 0) reader.Read(Dictionary); else if (String.Compare(reader.ItemName, "Styles", true) == 0) reader.Read(Styles); else base.DeserializeSubItems(reader); } #endregion Protected Methods #region IParent /// public bool CanContain(Base child) { return child is PageBase || child is Dictionary; } /// public void GetChildObjects(ObjectCollection list) { foreach (PageBase page in pages) { list.Add(page); } } /// public void AddChild(Base obj) { if (obj is PageBase) pages.Add(obj as PageBase); else if (obj is Dictionary) Dictionary = obj as Dictionary; } /// public void RemoveChild(Base obj) { if (obj is PageBase) pages.Remove(obj as PageBase); else if (obj is Dictionary && (obj as Dictionary) == dictionary) Dictionary = null; } /// public virtual int GetChildOrder(Base child) { if (child is PageBase) return pages.IndexOf(child as PageBase); return 0; } /// public virtual void SetChildOrder(Base child, int order) { if (child is PageBase) { if (order > pages.Count) order = pages.Count; int oldOrder = child.ZOrder; if (oldOrder != -1 && order != -1 && oldOrder != order) { if (oldOrder <= order) order--; pages.Remove(child as PageBase); pages.Insert(order, child as PageBase); } } } /// public virtual void UpdateLayout(float dx, float dy) { // do nothing } #endregion IParent #region ISupportInitialize Members /// public void BeginInit() { initializing = true; } /// public void EndInit() { initializing = false; Dictionary.RegisterData(initializeData, initializeDataName, false); } #endregion ISupportInitialize Members #region Script related private void FillDataSourceCache() { cachedDataItems.Clear(); ObjectCollection dictionaryObjects = Dictionary.AllObjects; foreach (Parameter c in Dictionary.SystemVariables) { dictionaryObjects.Add(c); } foreach (Base c in dictionaryObjects) { if (c is DataSourceBase) { DataSourceBase data = c as DataSourceBase; CachedDataItem cachedItem = new CachedDataItem(); cachedItem.dataSource = data; cachedDataItems[data.FullName] = cachedItem; for (int i = 0; i < data.Columns.Count; i++) { cachedItem = new CachedDataItem(); cachedItem.dataSource = data; cachedItem.column = data.Columns[i]; cachedDataItems[data.FullName + "." + data.Columns[i].Alias] = cachedItem; } } else if (c is Parameter) { cachedDataItems[(c as Parameter).FullName] = c; } else if (c is Total) { cachedDataItems[(c as Total).Name] = c; } } } internal void Compile() { FillDataSourceCache(); #if REFLECTION_EMIT_COMPILER if (Config.CompilerSettings.ReflectionEmitCompiler) { SetIsCompileNeeded(); if (!IsCompileNeeded) return; } #endif if (needCompile) { Debug.WriteLine("Compile..."); using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText)) { assemblies.Clear(); assemblies.Add(descriptor); descriptor.AddObjects(); descriptor.AddExpressions(); descriptor.AddFunctions(); descriptor.Compile(); } } else { InternalInit(); } } #if ASYNC internal async Task CompileAsync(CancellationToken token) { FillDataSourceCache(); #if REFLECTION_EMIT_COMPILER if (Config.CompilerSettings.ReflectionEmitCompiler) { SetIsCompileNeeded(); if (!IsCompileNeeded) return; } #endif if (needCompile) { AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText); assemblies.Clear(); assemblies.Add(descriptor); descriptor.AddObjects(); descriptor.AddExpressions(); descriptor.AddFunctions(); await descriptor.CompileAsync(token); } else { InternalInit(); } } #endif /// /// Initializes the report's fields. /// /// /// This method is for internal use only. /// protected void InternalInit() { needCompile = false; AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript()); assemblies.Clear(); assemblies.Add(descriptor); descriptor.InitInstance(this); } /// /// Generates the file (.cs or .vb) that contains the report source code. /// /// Name of the file. /// /// Use this method to generate the report source code. This code can be attached to your project. /// In this case, you will need to call the following code to run a report: /// /// SimpleListReport report = new SimpleListReport(); /// report.RegisterData(your_dataset); /// report.Show(); /// /// public void GenerateReportAssembly(string fileName) { // create the class name string className = ""; const string punctuation = " ~`!@#$%^&*()-=+[]{},.<>/?;:'\"\\|"; foreach (char c in Path.GetFileNameWithoutExtension(fileName)) { if (!punctuation.Contains(c.ToString())) className += c; } AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText); descriptor.AddObjects(); descriptor.AddExpressions(); descriptor.AddFunctions(); string reportClassText = descriptor.GenerateReportClass(className); File.WriteAllText(fileName, reportClassText, Encoding.UTF8); } /// /// Calculates an expression and returns the result. /// /// The expression to calculate. /// If report is running, returns the result of calculation. /// Otherwise returns null. /// /// The expression may be any valid expression such as "1 + 2". The expression /// is calculated in the report script's ReportScript class instance context, /// so you may refer to any objects available in this context: private fields, /// methods, report objects. /// public object Calc(string expression) { return Calc(expression, 0); } /// /// Calculates an expression and returns the result. /// /// The expression to calculate. /// The value of currently printing object. /// If report is running, returns the result of calculation. /// Otherwise returns null. /// /// Do not call this method directly. Use the Calc(string expression) method instead. /// public object Calc(string expression, Variant value) { if (!IsRunning) return null; if (String.IsNullOrEmpty(expression) || String.IsNullOrEmpty(expression.Trim())) return null; string expr = expression; if (expr.StartsWith("[") && expr.EndsWith("]")) expr = expression.Substring(1, expression.Length - 2); // check cached items first object cachedObject = cachedDataItems[expr]; if (cachedObject is CachedDataItem) { CachedDataItem cachedItem = cachedObject as CachedDataItem; DataSourceBase data = cachedItem.dataSource; Column column = cachedItem.column; object val = ConvertToColumnDataType(column.Value, column.DataType, ConvertNulls); if (CustomCalc != null) { CustomCalcEventArgs e = new CustomCalcEventArgs(expr, val, this); CustomCalc(this, e); val = e.CalculatedObject; } return val; } else if (cachedObject is Parameter) { return (cachedObject as Parameter).Value; } else if (cachedObject is Total) { object val = (cachedObject as Total).Value; if (ConvertNulls && (val == null || val is DBNull)) val = 0; (cachedObject as Total).ExecuteTotal(val); return val; } // calculate the expression return CalcExpression(expression, value); } private object ConvertToColumnDataType(object val, Type dataType, bool convertNulls) { if (val == null || val is DBNull) { if (convertNulls) val = Converter.ConvertNull(dataType); } else { if (val is IConvertible) { Type t = Nullable.GetUnderlyingType(dataType); try { val = Convert.ChangeType(val, t != null ? t : dataType); } catch (InvalidCastException) { // do nothing } catch (FormatException) { // do nothing } } } return val; } /// /// Returns an expression value. /// /// The expression. /// The value of currently printing object. /// Returns the result of calculation. /// /// This method is for internal use only, do not call it directly. /// protected virtual object CalcExpression(string expression, Variant value) { if (expression.ToLower() == "true" || expression.ToLower() == "false") { expression = expression.ToLower(); } // try to calculate the expression foreach (AssemblyDescriptor d in assemblies) { if (d.ContainsExpression(expression)) return d.CalcExpression(expression, value); } #if REFLECTION_EMIT_COMPILER if (Config.CompilerSettings.ReflectionEmitCompiler) if (TryReflectionEmit(expression, value, out object returnValue)) return returnValue; #endif // expression not found. Probably it was added after the start of the report. // Compile new assembly containing this expression. using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript())) { assemblies.Add(descriptor); descriptor.AddObjects(); descriptor.AddSingleExpression(expression); descriptor.AddFunctions(); descriptor.Compile(); return descriptor.CalcExpression(expression, value); } } /// /// Invokes the script method with given name. /// /// The name of the script method. /// The method parameters. public object InvokeMethod(string name, object[] parms) { if (assemblies.Count > 0) return assemblies[0].InvokeMethod(name, parms); return null; } private Column GetColumn(string complexName) { if (String.IsNullOrEmpty(complexName)) return null; CachedDataItem cachedItem = cachedDataItems[complexName] as CachedDataItem; if (cachedItem != null) return cachedItem.column; string[] names = complexName.Split('.'); cachedItem = cachedDataItems[names[0]] as CachedDataItem; DataSourceBase data = cachedItem != null ? cachedItem.dataSource : GetDataSource(names[0]); return DataHelper.GetColumn(Dictionary, data, names, true); } private object GetColumnValue(string complexName, bool convertNull) { Column column = GetColumn(complexName); if (column == null) return null; return ConvertToColumnDataType(column.Value, column.DataType, convertNull); } private Variant GetTotalValue(string name, bool convertNull) { object value = Dictionary.Totals.GetValue(name); if (convertNull && (value == null || value is DBNull)) value = 0; return new Variant(value); } /// /// Gets the data column's value. Automatically converts null value to 0, false or "" /// depending on the column type. /// /// The name of the data column including the datasource name. /// If report is running, returns the column value. Otherwise returns null. /// /// The return value of this method does not depend on the property. /// /// /// /// string employeeName = (string)report.GetColumnValue("Employees.FirstName"); /// /// public object GetColumnValue(string complexName) { return GetColumnValue(complexName, true); } /// /// Gets the data column's value. This method does not convert null values. /// /// The name of the data column including the datasource name. /// If report is running, returns the column value. /// Otherwise returns null. public object GetColumnValueNullable(string complexName) { return GetColumnValue(complexName, false); } /// /// Gets the report parameter with given name. /// /// The name of the parameter. /// The object if found, otherwise null. /// /// To find nested parameter, use the "." separator: "MainParameter.NestedParameter" /// public Parameter GetParameter(string complexName) { if (IsRunning) return cachedDataItems[complexName] as Parameter; return DataHelper.GetParameter(Dictionary, complexName); } /// /// Gets a value of the parameter with given name. /// /// The name of the parameter. /// The parameter's value if found, otherwise null. /// /// To find nested parameter, use the "." separator: "MainParameter.NestedParameter" /// public object GetParameterValue(string complexName) { Parameter par = GetParameter(complexName); if (par != null) { // avoid InvalidCastException when casting object that is int to double if (par.DataType.Name == "Double" && par.Value.GetType() == typeof(int)) { return (double)(int)par.Value; } return par.Value; } return null; } /// /// Sets the parameter's value. /// /// The name of the parameter. /// Value to set. /// /// Use this method to pass a value to the parameter that you've created in the "Data" window. /// Such parameter may be used everythere in a report; for example, you can print its value /// or use it in expressions. /// You should call this method after the report was loaded and before you run it. /// To access a nested parameter, use the "." separator: "MainParameter.NestedParameter" /// /// This method will create the parameter if it does not exist. /// /// /// This example shows how to pass a value to the parameter with "MyParam" name: /// /// // load the report /// report1.Load("report.frx"); /// // setup the parameter /// report1.SetParameterValue("MyParam", 10); /// // show the report /// report1.Show(); /// /// public void SetParameterValue(string complexName, object value) { Parameter par = GetParameter(complexName); if (par == null) par = DataHelper.CreateParameter(Dictionary, complexName); if (par != null) { par.Value = value; par.Expression = ""; } isParameterChanged = true; } /// /// Gets a value of the system variable with specified name. /// /// Name of a variable. /// The variable's value if found, otherwise null. public object GetVariableValue(string complexName) { return GetParameterValue(complexName); } /// /// Gets a value of the total with specified name. /// /// Name of total. /// The total's value if found, otherwise 0. /// This method converts null values to 0 if the property is set to true. /// Use the method if you don't want the null conversion. /// public Variant GetTotalValue(string name) { return GetTotalValue(name, ConvertNulls); } /// /// Gets a value of the total with specified name. /// /// Name of total. /// The total's value if found, otherwise null. public Variant GetTotalValueNullable(string name) { return GetTotalValue(name, false); } /// /// Gets the datasource with specified name. /// /// Alias name of a datasource. /// The datasource object if found, otherwise null. public DataSourceBase GetDataSource(string alias) { return Dictionary.FindByAlias(alias) as DataSourceBase; } #endregion Script related #region Public Methods /// public override void Assign(Base source) { BaseAssign(source); } /// /// Aborts the report execution. /// public void Abort() { SetAborted(true); } /// public override Base FindObject(string name) { foreach (Base c in AllNamedObjects) { if (String.Compare(name, c.Name, true) == 0) return c; } return null; } /// public override void Clear() { base.Clear(); ClearReportProperties(); } /// /// Updates the report component's styles. /// /// /// Call this method if you change the collection. /// public void ApplyStyles() { foreach (Base c in AllObjects) { if (c is ReportComponentBase) (c as ReportComponentBase).Style = (c as ReportComponentBase).Style; } } /// /// Sets prepared pages. /// /// public void SetPreparedPages(Preview.PreparedPages pages) { preparedPages = pages; if (pages != null) pages.SetReport(this); } internal void SetAborted(bool value) { aborted = value; } internal void SetOperation(ReportOperation operation) { this.operation = operation; } /// /// This method fires the StartReport event and the script code connected /// to the StartReportEvent. /// public void OnStartReport(EventArgs e) { SetRunning(true); if (StartReport != null) StartReport(this, e); InvokeMethod(StartReportEvent, new object[] { this, e }); } /// /// This method fires the FinishReport event and the script code connected /// to the FinishReportEvent. /// public void OnFinishReport(EventArgs e) { SetRunning(false); if (FinishReport != null) FinishReport(this, e); InvokeMethod(FinishReportEvent, new object[] { this, e }); } /// /// Runs the Export event. /// /// ExportReportEventArgs object. public void OnExportParameters(ExportParametersEventArgs e) { if (ExportParameters != null) { ExportParameters(this, e); } } /// /// Add the name of the assembly (in addition to the default) that will be used to compile the report script /// /// Assembly name /// /// For example: report.AddReferencedAssembly("Newtonsoft.Json.dll") /// public void AddReferencedAssembly(string assembly_name) { string[] assemblies = ReferencedAssemblies; Array.Resize(ref assemblies, assemblies.Length + 1); assemblies[assemblies.Length - 1] = assembly_name; ReferencedAssemblies = assemblies; } /// /// Add the names of the assembly (in addition to the default) that will be used to compile the report script /// /// Assembly's names public void AddReferencedAssembly(IList assembly_names) { string[] assemblies = ReferencedAssemblies; int oldLength = assemblies.Length; Array.Resize(ref assemblies, oldLength + assembly_names.Count); for (int i = 0; i < assembly_names.Count; i++) { assemblies[oldLength + i] = assembly_names[i]; } ReferencedAssemblies = assemblies; } /// public override void Serialize(FRWriter writer) { Report c = writer.DiffObject as Report; writer.ItemName = IsAncestor ? "inherited" : ClassName; if (BaseReport != c.BaseReport) { // when save to the report file, convert absolute path to the base report to relative path // (based on the main report path). Do not convert when saving to the clipboard. string value = writer.SerializeTo != SerializeTo.Undo ? GetRelativePathToBaseReport() : BaseReport; writer.WriteStr("BaseReport", value); // Fix bug with moving child report to another folder without parent report. if (writer.SerializeTo == SerializeTo.Report) writer.WriteStr("BaseReportAbsolutePath", BaseReport); } // always serialize ScriptLanguage because its default value depends on Config.ReportSettings.DefaultLanguage writer.WriteValue("ScriptLanguage", ScriptLanguage); if (ScriptText != c.ScriptText) writer.WritePropertyValue("ScriptText", ScriptText); if (!writer.AreEqual(ReferencedAssemblies, c.ReferencedAssemblies)) writer.WriteValue("ReferencedAssemblies", ReferencedAssemblies); if (ConvertNulls != c.ConvertNulls) writer.WriteBool("ConvertNulls", ConvertNulls); if (DoublePass != c.DoublePass) writer.WriteBool("DoublePass", DoublePass); if (Compressed != c.Compressed) writer.WriteBool("Compressed", Compressed); if (UseFileCache != c.UseFileCache) writer.WriteBool("UseFileCache", UseFileCache); if (TextQuality != c.TextQuality) writer.WriteValue("TextQuality", TextQuality); if (SmoothGraphics != c.SmoothGraphics) writer.WriteBool("SmoothGraphics", SmoothGraphics); if (Password != c.Password) writer.WriteStr("Password", Password); if (InitialPageNumber != c.InitialPageNumber) writer.WriteInt("InitialPageNumber", InitialPageNumber); if (MaxPages != c.MaxPages) writer.WriteInt("MaxPages", MaxPages); if (StartReportEvent != c.StartReportEvent) writer.WriteStr("StartReportEvent", StartReportEvent); if (FinishReportEvent != c.FinishReportEvent) writer.WriteStr("FinishReportEvent", FinishReportEvent); ReportInfo.Serialize(writer, c.ReportInfo); SerializeDesign(writer, c); if (Styles.Count > 0) writer.Write(Styles); writer.Write(Dictionary); if (writer.SaveChildren) { foreach (Base child in ChildObjects) { writer.Write(child); } } } /// public override void Deserialize(FRReader reader) { if (reader.HasProperty("BaseReportAbsolutePath")) { BaseReportAbsolutePath = reader.ReadStr("BaseReportAbsolutePath"); } base.Deserialize(reader); // call OnAfterLoad method of each report object foreach (Base c in AllObjects) { c.OnAfterLoad(); } } /// /// Saves the report to a stream. /// /// The stream to save to. public void Save(Stream stream) { using (FRWriter writer = new FRWriter()) { if (IsAncestor) writer.GetDiff += new DiffEventHandler(GetDiff); writer.Write(this); List disposeList = new List(); if (Compressed) { stream = Compressor.Compress(stream); disposeList.Add(stream); } if (!String.IsNullOrEmpty(Password)) { stream = Crypter.Encrypt(stream, Password); disposeList.Insert(0, stream); } writer.Save(stream); foreach (Stream s in disposeList) { s.Dispose(); } } } /// /// Saves the report to a file. /// /// The name of the file to save to. public void Save(string fileName) { FileName = fileName; using (FileStream f = new FileStream(fileName, FileMode.Create)) { Save(f); } } /// /// Saves the report to a stream with randomized values in data sources. /// /// The stream to save to. public void SaveWithRandomData(Stream stream) { FRRandom random = new FRRandom(); random.RandomizeDataSources(Dictionary.DataSources); Save(stream); } /// /// Saves the report to a file with randomized values in data sources. /// /// The name of the file to save to. public void SaveWithRandomData(string fileName) { FRRandom random = new FRRandom(); random.RandomizeDataSources(Dictionary.DataSources); Save(fileName); } /// /// Loads report from a stream. /// /// The stream to load from. /// /// The stream must be seekable. /// When you load a password-protected report, you should specify a password in the property, /// otherwise you will get the . In this case you should ask for a password and try again: /// /// try /// { /// report.Load(stream); /// } /// catch (DecryptException) /// { /// report.Password = report.ShowPasswordForm(); // or use your own form to do this /// report.Load(stream); /// } /// /// public void Load(Stream stream) { string password = Password; Clear(); var saveStream = stream; var saveStreamPos = stream.Position; using (FRReader reader = new FRReader(this)) { List disposeList = new List(); if (Compressor.IsStreamCompressed(stream)) { stream = Compressor.Decompress(stream, true); disposeList.Add(stream); } bool crypted = Crypter.IsStreamEncrypted(stream); if (crypted) { stream = Crypter.Decrypt(stream, password); disposeList.Add(stream); } try { reader.Load(stream); } catch (Exception e) { if (crypted) { saveStream.Position = saveStreamPos; throw new DecryptException(); } throw e; } finally { foreach (Stream s in disposeList) { try { s.Dispose(); } catch { } } } reader.Read(this); } } /// /// Loads the report from a file. /// /// The name of the file to load from. /// /// When you try to load the password-protected report, you will be asked /// for a password. You also may specify the password in the /// property before loading the report. In this case the report will load silently. /// public void Load(string fileName) { this.fileName = ""; using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) { this.fileName = fileName; Load(f); } } /// /// Loads the report from a string. /// /// The string that contains a stream in UTF8 or Base64 encoding. public void LoadFromString(string s) { if (String.IsNullOrEmpty(s)) return; byte[] buffer; int startIndex = s.IndexOf(""); if (startIndex != -1) { buffer = Encoding.UTF8.GetBytes(s.Substring(startIndex)); } else { buffer = Convert.FromBase64String(s); } using (MemoryStream stream = new MemoryStream(buffer)) { Load(stream); } } /// /// Saves the report to a string. /// /// The string that contains a stream. public string SaveToString() { using (MemoryStream stream = new MemoryStream()) { Save(stream); if (Compressed || !String.IsNullOrEmpty(Password)) { return Convert.ToBase64String(stream.ToArray()); } else { return Encoding.UTF8.GetString(stream.ToArray()); } } } /// /// Saves the report to a string using the Base64 encoding. /// /// The string that contains a stream. public string SaveToStringBase64() { using (MemoryStream stream = new MemoryStream()) { Save(stream); return Convert.ToBase64String(stream.ToArray()); } } /// /// Creates the report instance and loads the report from a stream. /// /// The stream to load from. /// The new report instance. public static Report FromStream(Stream stream) { Report result = new Report(); result.Load(stream); return result; } /// /// Creates the report instance and loads the report from a file. /// /// The name of the file to load from. /// The new report instance. public static Report FromFile(string fileName) { Report result = new Report(); result.Load(fileName); return result; } /// /// Creates the report instance and loads the report from a string. /// /// The string that contains a stream in UTF8 encoding. /// The new report instance. public static Report FromString(string utf8String) { Report result = new Report(); result.LoadFromString(utf8String); return result; } /// /// Registers the application dataset with all its tables and relations to use it in the report. /// /// The application data. /// /// If you register more than one dataset, use the method. /// /// /// /// report1.Load("report.frx"); /// report1.RegisterData(dataSet1); /// /// public void RegisterData(DataSet data) { Dictionary.RegisterDataSet(data, "Data", false); } /// /// Registers the application dataset with all its tables and relations to use it in the report and enables all its tables. /// /// The application data. /// The boolean value indicating whether all tables should be enabled. /// /// If you register more than one dataset, use the method. /// /// /// /// report1.Load("report.frx"); /// report1.RegisterData(dataSet1, true); /// /// public void RegisterData(DataSet data, bool enableAllTables) { Dictionary.RegisterDataSet(data, "Data", false); foreach (DataTable table in data.Tables) { DataSourceBase ds = Report.GetDataSource(table.TableName); if (ds != null) ds.Enabled = true; } } /// /// Registers the application dataset with specified name. /// /// The application data. /// The name of the data. /// /// Use this method if you register more than one dataset. You may specify any value /// for the name parameter: it is not displayed anywhere in the designer and used only /// to load/save a report. The name must be persistent and unique for each registered dataset. /// /// /// /// report1.Load("report.frx"); /// report1.RegisterData(dataSet1, "NorthWind"); /// /// public void RegisterData(DataSet data, string name) { if (initializing) { initializeData = data; initializeDataName = name; } else Dictionary.RegisterDataSet(data, name, false); } /// /// Registers the application dataset with specified name and enables all its tables. /// /// The application data. /// The name of the data. /// The boolean value indicating whether all tables should be enabled. /// /// Use this method if you register more than one dataset. You may specify any value /// for the name parameter: it is not displayed anywhere in the designer and used only /// to load/save a report. The name must be persistent and unique for each registered dataset. /// /// /// /// report1.Load("report.frx"); /// report1.RegisterData(dataSet1, "NorthWind", true); /// /// public void RegisterData(DataSet data, string name, bool enableAllTables) { if (initializing) { initializeData = data; initializeDataName = name; } else { Dictionary.RegisterDataSet(data, name, false); foreach (DataTable table in data.Tables) { DataSourceBase ds = Report.GetDataSource(table.TableName); if (ds != null) ds.Enabled = true; } } } /// /// Registers the application data table to use it in the report. /// /// The application data. /// The name of the data. /// /// /// report1.Load("report.frx"); /// report1.RegisterData(dataSet1.Tables["Orders"], "Orders"); /// /// public void RegisterData(DataTable data, string name) { Dictionary.RegisterDataTable(data, name, false); } /// /// Registers the application data view to use it in the report. /// /// The application data. /// The name of the data. /// /// /// report1.Load("report.frx"); /// report1.RegisterData(myDataView, "OrdersView"); /// /// public void RegisterData(DataView data, string name) { Dictionary.RegisterDataView(data, name, false); } /// /// Registers the application data relation to use it in the report. /// /// The application data. /// The name of the data. /// /// You may specify any value for the name parameter: it is not displayed anywhere /// in the designer and used only to load/save a report. The name must be persistent /// and unique for each registered relation. /// /// /// /// report1.Load("report.frx"); /// report1.RegisterData(myDataRelation, "myRelation"); /// /// public void RegisterData(DataRelation data, string name) { Dictionary.RegisterDataRelation(data, name, false); } /// /// Obsolete. Registers the application business object to use it in the report. /// /// Application data. /// Name of the data. /// Not used. /// Maximum nesting level of business objects. /// /// This method is obsolete. Use the method instead. /// public void RegisterData(IEnumerable data, string name, BOConverterFlags flags, int maxNestingLevel) { RegisterData(data, name, maxNestingLevel); } /// /// Registers the application business object to use it in the report. /// /// Application data. /// Name of the data. /// /// /// report1.Load("report.frx"); /// report1.RegisterData(myBusinessObject, "Customers"); /// /// public void RegisterData(IEnumerable data, string name) { if (initializing) { initializeData = data; initializeDataName = name; } else Dictionary.RegisterBusinessObject(data, name, 1, false); } /// /// Registers the application business object to use it in the report. /// /// Application data. /// Name of the data. /// Maximum nesting level of business objects. /// /// This method creates initial datasource with specified nesting level. It is useful if /// you create a report in code. In most cases, you don't need to specify the nesting level /// because it may be selected in the designer's "Choose Report Data" dialog. /// public void RegisterData(IEnumerable data, string name, int maxNestingLevel) { Dictionary.RegisterBusinessObject(data, name, maxNestingLevel, false); } /// /// Registers the application cube link to use it in the report. /// /// The application data. /// The name of the data. /// /// /// report1.Load("report.frx"); /// report1.RegisterData(myCubeLink, "Orders"); /// /// public void RegisterData(IBaseCubeLink data, string name) { Dictionary.RegisterCubeLink(data, name, false); } /// /// Prepares the report. /// /// true if report was prepared succesfully. public bool Prepare() { return Prepare(false); } #if ASYNC /// /// Prepares the report asynchronously. /// /// Cancellation token /// true if report was prepared succesfully. [EditorBrowsable(EditorBrowsableState.Never)] // TODO public Task PrepareAsync(CancellationToken token = default) { return PrepareAsync(false, token); } private async Task PrepareAsync(bool append, CancellationToken token = default) { SetRunning(true); try { if (PreparedPages == null || !append) { ClearPreparedPages(); SetPreparedPages(new Preview.PreparedPages(this)); } engine = new ReportEngine(this); if (!Config.WebMode) StartPerformanceCounter(); try { await CompileAsync(token).ConfigureAwait(false); isParameterChanged = false; return Engine.Run(true, append, true); } finally { if (!Config.WebMode) StopPerformanceCounter(); } } finally { SetRunning(false); } } #endif /// /// Prepares the report. /// /// Specifies whether the new report should be added to a /// report that was prepared before. /// true if report was prepared succesfully. /// /// Use this method to merge prepared reports. /// /// This example shows how to merge two reports and preview the result: /// /// Report report = new Report(); /// report.Load("report1.frx"); /// report.Prepare(); /// report.Load("report2.frx"); /// report.Prepare(true); /// report.ShowPrepared(); /// /// public bool Prepare(bool append) { SetRunning(true); try { if (PreparedPages == null || !append) { ClearPreparedPages(); SetPreparedPages(new Preview.PreparedPages(this)); } engine = new ReportEngine(this); if (!Config.WebMode) StartPerformanceCounter(); try { Compile(); isParameterChanged = false; return Engine.Run(true, append, true); } finally { if (!Config.WebMode) StopPerformanceCounter(); } } finally { SetRunning(false); } } /// /// Prepares the report with pages limit. /// /// Pages limit. The number of pages equal or less will be prepared. /// true if report was prepared succesfully. public bool Prepare(int pagesLimit) { SetRunning(true); try { ClearPreparedPages(); SetPreparedPages(new Preview.PreparedPages(this)); engine = new ReportEngine(this); if (!Config.WebMode) StartPerformanceCounter(); try { Compile(); return Engine.Run(true, false, true, pagesLimit); } finally { if (!Config.WebMode) StopPerformanceCounter(); } } finally { SetRunning(false); } } /// /// For internal use only. /// [EditorBrowsable(EditorBrowsableState.Never)] public void PreparePhase1() { bool webDialog = false; SetRunning(true); if (preparedPages != null) { // if prepared pages are set before => it's call method again => it's web dialog webDialog = true; preparedPages.Clear(); } SetPreparedPages(new Preview.PreparedPages(this)); engine = new ReportEngine(this); Compile(); Engine.RunPhase1(true, webDialog); } /// /// For internal use only. /// [EditorBrowsable(EditorBrowsableState.Never)] public void PreparePhase2(int? pagesLimit = null) { Engine.RunPhase2(pagesLimit); SetRunning(false); } /// /// Refresh the current report. /// /// /// Call this method in the Click or MouseUp event handler of a report object to refresh /// the currently previewed report. Report will be generated again, but without dialog forms. /// public void Refresh() { needRefresh = true; } /// /// Refresh prepared report after interactive actions. /// public void InteractiveRefresh() { PreparedPages.ClearPageCache(); InternalRefresh(); } /// /// Serialize report object from string /// /// Serialized report object from string [EditorBrowsable(EditorBrowsableState.Never)] public ReportComponentBase Xml(string xml) { XmlDocument doc = new XmlDocument(); using (TextReader reader = new StringReader(xml)) { doc.WriteHeader = false; doc.ReadHeader = true; doc.Load(reader); } using (FRReader reader = new FRReader(this, doc.Root)) { reader.DeserializeFrom = SerializeTo.Clipboard; return reader.Read() as ReportComponentBase; } } internal void InternalRefresh() { SetRunning(true); try { Engine.Run(false, false, false); } finally { SetRunning(false); } } internal TextRenderingHint GetTextQuality() { switch (this.TextQuality) { case TextQuality.Regular: return TextRenderingHint.AntiAliasGridFit; case TextQuality.ClearType: return TextRenderingHint.ClearTypeGridFit; case TextQuality.AntiAlias: return TextRenderingHint.AntiAlias; case TextQuality.SingleBPP: return TextRenderingHint.SingleBitPerPixel; case TextQuality.SingleBPPGridFit: return TextRenderingHint.SingleBitPerPixelGridFit; } return TextRenderingHint.SystemDefault; } /// /// Prepare page /// /// public void PreparePage(ReportPage page) { SetRunning(true); try { Engine.Run(false, false, false, page); } finally { SetRunning(false); } } /// /// Prepare page /// /// /// Flag indicating whether the page is a detail page. public void PreparePage(ReportPage page, bool isDetailPage) { bool pageVisible = page.Visible; if (isDetailPage) page.Visible = true; PreparePage(page); page.Visible = pageVisible; } /// /// Exports a report. Report should be prepared using the method. /// /// The export filter. /// Stream to save export result to. public void Export(ExportBase export, Stream stream) { export.Export(this, stream); } /// /// Exports a report. Report should be prepared using the method. /// /// The export filter. /// File name to save export result to. public void Export(ExportBase export, string fileName) { export.Export(this, fileName); } /// /// Saves the prepared report. Report should be prepared using the method. /// /// File name to save to. public void SavePrepared(string fileName) { if (PreparedPages != null) PreparedPages.Save(fileName); } /// /// Saves the prepared report. Report should be prepared using the method. /// /// Stream to save to. public void SavePrepared(Stream stream) { if (PreparedPages != null) PreparedPages.Save(stream); } /// /// Loads the prepared report from a .fpx file. /// /// File name to load form. public void LoadPrepared(string fileName) { isLoadPrepared = true; if (PreparedPages == null) SetPreparedPages(new FastReport.Preview.PreparedPages(this)); PreparedPages.Load(fileName); } /// /// Loads the prepared report from a .fpx file. /// /// Stream to load from. public void LoadPrepared(Stream stream) { isLoadPrepared = true; if (PreparedPages == null) SetPreparedPages(new FastReport.Preview.PreparedPages(this)); PreparedPages.Load(stream); } #endregion Public Methods /// /// Initializes a new instance of the class with default settings. /// public Report() { pages = new PageCollection(this); reportInfo = new ReportInfo(); InitDesign(); styles = new StyleCollection(); Dictionary = new Dictionary(); graphicCache = new GraphicCache(); assemblies = new AssemblyCollection(); cachedDataItems = new Hashtable(StringComparer.InvariantCultureIgnoreCase); // needed for case insensitivity storeInResources = true; fileName = ""; autoFillDataSet = true; tag = null; ClearReportProperties(); SetFlags(Flags.CanMove | Flags.CanResize | Flags.CanDelete | Flags.CanEdit | Flags.CanChangeOrder | Flags.CanChangeParent | Flags.CanCopy, false); //FInlineImageCache = new InlineImageCache(); } static Report() { Config.Init(); } /// /// Ensure that static constructor is called. /// public static void EnsureInit() { // do nothing, just ensure that static constructor is called. } /// /// Create name for all unnamed elements with prefix and start with number /// /// Prefix for name /// Number from which to start public void PostNameProcess(string prefix, int number) { int i = number; foreach (Base obj in AllObjects) { if (String.IsNullOrEmpty(obj.Name)) { obj.SetName(prefix + i.ToString()); i++; } } } private class CachedDataItem { public DataSourceBase dataSource; public Column column; } } }