using System; using System.Drawing; using System.ComponentModel; using System.Windows.Forms; using System.Drawing.Design; using FastReport.Utils; using System.Threading.Tasks; #if !FRCORE using FastReport.Forms; #endif namespace FastReport.Dialog { /// /// Represents the special kind of report page that wraps the /// and used to display dialog forms. /// /// /// Use the property to add/remove controls to/from a dialog form. /// If you set the Visible property to false, this dialog form will be /// skippen when you run a report. /// /// This example shows how to create a dialog form with one button in code. /// /// DialogPage form = new DialogPage(); /// // set the width and height in pixels /// form.Width = 200; /// form.Height = 200; /// form.Name = "Form1"; /// // create a button /// ButtonControl button = new ButtonControl(); /// button.Location = new Point(20, 20); /// button.Size = new Size(75, 25); /// button.Text = "The button"; /// // add the button to the form /// form.Controls.Add(button); /// /// public partial class DialogPage : PageBase, IParent { #region Fields private ButtonControl acceptButton; private ButtonControl cancelButton; #if !FRCORE private BaseForm form; #else private Form form; #endif private DialogComponentCollection controls; private string loadEvent; private string formClosedEvent; private string formClosingEvent; private string shownEvent; private string resizeEvent; private string paintEvent; private DialogControl errorControl; private Color errorControlBackColor; private Timer errorControlTimer; private int errorControlTimerTickCount; private bool activeInWeb; private int oldDpi; #endregion #region Properties /// /// Occurs before a form is displayed for the first time. /// Wraps the event. /// public event EventHandler Load; /// /// Occurs after the form is closed. /// Wraps the event. /// public event FormClosedEventHandler FormClosed; /// /// Occurs before the form is closed. /// Wraps the event. /// public event FormClosingEventHandler FormClosing; /// /// Occurs whenever the form is first displayed. /// Wraps the event. /// public event EventHandler Shown; /// /// Occurs when the form is resized. /// Wraps the event. /// public event EventHandler Resize; /// /// Occurs when the form is redrawn. /// Wraps the event. /// public event PaintEventHandler Paint; /// /// Gets an internal Form. /// [Browsable(false)] #if !FRCORE public BaseForm Form #else public Form Form #endif { get { return form; } } /// /// Gets or sets an active state in Web application. /// [Browsable(false)] public bool ActiveInWeb { get { return activeInWeb; } set { activeInWeb = value; } } /// /// Gets or sets the button on the form that is clicked when the user presses the ENTER key. /// Wraps the property. /// [Category("Misc")] [Editor("FastReport.TypeEditors.PageComponentRefEditor, FastReport", typeof(UITypeEditor))] [TypeConverter(typeof(FastReport.TypeConverters.ComponentRefConverter))] public ButtonControl AcceptButton { get { return acceptButton; } set { if (acceptButton != value) { if (acceptButton != null) acceptButton.Disposed -= new EventHandler(AcceptButton_Disposed); if (value != null) value.Disposed += new EventHandler(AcceptButton_Disposed); } acceptButton = value; Form.AcceptButton = value == null ? null : value.Button; } } /// /// Gets or sets the button control that is clicked when the user presses the ESC key. /// Wraps the property. /// [Category("Misc")] [Editor("FastReport.TypeEditors.PageComponentRefEditor, FastReport", typeof(UITypeEditor))] [TypeConverter(typeof(FastReport.TypeConverters.ComponentRefConverter))] public ButtonControl CancelButton { get { return cancelButton; } set { if (cancelButton != value) { if (cancelButton != null) cancelButton.Disposed -= new EventHandler(CancelButton_Disposed); if (value != null) value.Disposed += new EventHandler(CancelButton_Disposed); } cancelButton = value; Form.CancelButton = value == null ? null : value.Button; } } /// /// Gets the auto scale dimensions for this form. /// public SizeF AutoScaleDimensions { get { return Form.AutoScaleDimensions; } set { Form.AutoScaleDimensions = value; } } /// /// Gets or sets the background color for the form. /// Wraps the property. /// [Category("Appearance")] [Editor("FastReport.TypeEditors.ColorEditor, FastReport", typeof(UITypeEditor))] public Color BackColor { get { return Form.BackColor; } set { Form.BackColor = value; ResetFormBitmap(); } } /// /// Gets or sets the font of the text displayed by the control. /// Wraps the property. /// [Category("Appearance")] public Font Font { get { return Form.Font; } set { Form.Font = value; } } /// /// Gets or sets the border style of the form. /// Wraps the property. /// [DefaultValue(FormBorderStyle.FixedDialog)] [Category("Appearance")] public FormBorderStyle FormBorderStyle { get { return Form.FormBorderStyle; } set { Form.FormBorderStyle = value; ResetFormBitmap(); } } /// /// Gets or sets a value indicating whether control's elements are aligned to support locales using right-to-left fonts. /// Wraps the property. /// [DefaultValue(RightToLeft.No)] [Category("Appearance")] public RightToLeft RightToLeft { get { return Form.RightToLeft; } set { Form.RightToLeft = value; ResetFormBitmap(); } } /// /// Gets or sets the text associated with this form. /// Wraps the property. /// [Category("Appearance")] public string Text { get { return Form.Text; } set { Form.Text = value; ResetFormBitmap(); } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string LoadEvent { get { return loadEvent; } set { loadEvent = value; } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string FormClosedEvent { get { return formClosedEvent; } set { formClosedEvent = value; } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string FormClosingEvent { get { return formClosingEvent; } set { formClosingEvent = value; } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string ShownEvent { get { return shownEvent; } set { shownEvent = value; } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string ResizeEvent { get { return resizeEvent; } set { resizeEvent = value; } } /// /// Gets or sets a script method name that will be used to handle the /// event. /// [Category("Events")] public string PaintEvent { get { return paintEvent; } set { paintEvent = value; } } /// /// Gets the collection of controls contained within the form. /// [Browsable(false)] public DialogComponentCollection Controls { get { return controls; } } /// public override float Width { get { return Form.Width; } set { if (!IsDesigning || !HasRestriction(Restrictions.DontResize)) Form.Width = Math.Max(10, (int)value); ResetFormBitmap(); } } /// public override float Height { get { return Form.Height; } set { if (!IsDesigning || !HasRestriction(Restrictions.DontResize)) Form.Height = Math.Max(10, (int)value); ResetFormBitmap(); } } /// public override SizeF ClientSize { get { return new SizeF(Form.ClientSize.Width, Form.ClientSize.Height); } set { Form.ClientSize = new Size((int)value.Width, (int)value.Height); } } #endregion #region Private Methods private string CreateButtonName(string baseName) { if (Report.FindObject(baseName) == null) return baseName; int i = 1; while (Report.FindObject(baseName + i.ToString()) != null) { i++; } return baseName + i.ToString(); } private void AcceptButton_Disposed(object sender, EventArgs e) { AcceptButton = null; } private void CancelButton_Disposed(object sender, EventArgs e) { CancelButton = null; } private void Form_Load(object sender, EventArgs e) { OnLoad(e); } private void Form_FormClosed(object sender, FormClosedEventArgs e) { OnFormClosed(e); } private void Form_FormClosing(object sender, FormClosingEventArgs e) { OnFormClosing(e); } private void Form_Shown(object sender, EventArgs e) { OnShown(e); } private void Form_Resize(object sender, EventArgs e) { OnResize(e); } private void Form_Paint(object sender, PaintEventArgs e) { OnPaint(e); } #if !FRCORE private void FixControlFonts(Control parent) { #if !AVALONIA float m = Form.Dpi() / (float)oldDpi; foreach (Control c in parent.Controls) { if (!c.Font.Equals(c.Parent.Font)) { c.Font = new Font(c.Font.FontFamily, c.Font.Size * m, c.Font.Style); } FixControlFonts(c); } #endif } private void Form_DpiChanged(object sender, EventArgs e) { // take care of controls with non-standard fonts. Such fonts are not scaled automatically. FixControlFonts(Form); oldDpi = Form.Dpi(); } #endif private void SetErrorControl(DialogControl control) { errorControl = control; if (control != null) { control.Focus(); if (errorControlTimer == null) { errorControlTimerTickCount = 0; errorControlBackColor = errorControl.BackColor; errorControlTimer = new Timer(); errorControlTimer.Interval = 300; errorControlTimer.Tick += new EventHandler(FErrorControlTimer_Tick); errorControlTimer.Start(); } } } private void FErrorControlTimer_Tick(object sender, EventArgs e) { errorControl.BackColor = errorControlTimerTickCount % 2 == 0 ? Color.Red : errorControlBackColor; errorControlTimerTickCount++; if (errorControlTimerTickCount > 5) { errorControlTimer.Stop(); errorControlTimer.Dispose(); errorControlTimer = null; } } #endregion #region Protected Methods /// protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) Form.Dispose(); } #endregion #region IParent /// public virtual void GetChildObjects(ObjectCollection list) { foreach (DialogComponentBase c in controls) { list.Add(c); } } /// public virtual bool CanContain(Base child) { return (child is DialogComponentBase); } /// public virtual void AddChild(Base child) { if (child is DialogComponentBase) controls.Add(child as DialogComponentBase); } /// public virtual void RemoveChild(Base child) { if (child is DialogComponentBase) controls.Remove(child as DialogComponentBase); } /// public virtual int GetChildOrder(Base child) { return controls.IndexOf(child as DialogComponentBase); } /// public virtual void SetChildOrder(Base child, int order) { int oldOrder = child.ZOrder; if (oldOrder != -1 && order != -1 && oldOrder != order) { if (order > controls.Count) order = controls.Count; if (oldOrder <= order) order--; controls.Remove(child as DialogComponentBase); controls.Insert(order, child as DialogComponentBase); } } /// public virtual void UpdateLayout(float dx, float dy) { // do nothing } #endregion #region Public Methods /// public override void Assign(Base source) { BaseAssign(source); DialogPage src = source as DialogPage; AcceptButton = src.AcceptButton; CancelButton = src.CancelButton; #if !FRCORE int dpi = src.Form.Dpi(); float fontDpiMultiplier = src.Form.FontDpiMultiplier(); #else int dpi = 96; float fontDpiMultiplier = 1; #endif AutoScaleDimensions = new SizeF(dpi, dpi); BackColor = src.BackColor; Font = new Font(Font.FontFamily, Font.Size / fontDpiMultiplier, Font.Style); FormBorderStyle = src.FormBorderStyle; RightToLeft = src.RightToLeft; Text = src.Text; ClientSize = src.ClientSize; } /// public override void Serialize(FRWriter writer) { DialogPage c = writer.DiffObject as DialogPage; base.Serialize(writer); if (AcceptButton != c.AcceptButton) writer.WriteRef("AcceptButton", AcceptButton); if (CancelButton != c.CancelButton) writer.WriteRef("CancelButton", CancelButton); #if !FRCORE int dpi = Form.Dpi(); #else int dpi = 96; #endif writer.WriteValue("AutoScaleDimensions", new SizeF(dpi, dpi)); if (BackColor != c.BackColor) writer.WriteValue("BackColor", BackColor); if (!Font.Equals(c.Font) && writer.ItemName != "inherited") { #if !FRCORE float fontDpiMultiplier = Form.FontDpiMultiplier(); #else float fontDpiMultiplier = 1; #endif using (Font f = new Font(Font.FontFamily, Font.Size / fontDpiMultiplier, Font.Style)) writer.WriteValue("Font", f); } if (FormBorderStyle != c.FormBorderStyle) writer.WriteValue("FormBorderStyle", FormBorderStyle); if (RightToLeft != c.RightToLeft) writer.WriteValue("RightToLeft", RightToLeft); if (Text != c.Text) writer.WriteStr("Text", Text); if (LoadEvent != c.LoadEvent) writer.WriteStr("LoadEvent", LoadEvent); if (FormClosedEvent != c.FormClosedEvent) writer.WriteStr("FormClosedEvent", FormClosedEvent); if (FormClosingEvent != c.FormClosingEvent) writer.WriteStr("FormClosingEvent", FormClosingEvent); if (ShownEvent != c.ShownEvent) writer.WriteStr("ShownEvent", ShownEvent); if (ResizeEvent != c.ResizeEvent) writer.WriteStr("ResizeEvent", ResizeEvent); if (PaintEvent != c.PaintEvent) writer.WriteStr("PaintEvent", PaintEvent); writer.WriteValue("ClientSize", ClientSize); } /// public override void Deserialize(FRReader reader) { Form.SuspendLayout(); // in case the dimensions are not stored in the report file (old file format), use 96dpi by default if (!reader.HasProperty("AutoScaleDimensions")) Form.AutoScaleDimensions = new SizeF(96f, 96f); Form.AutoScaleMode = AutoScaleMode.Dpi; base.Deserialize(reader); // old file format - width and height were stored instead of ClientSize if (reader.HasProperty("Width")) { // old-style FixedDialog form size was a bit smaller if (FormBorderStyle == FormBorderStyle.FixedDialog) { Form.Width += 10; Form.Height += 10; } #if FRCORE // TODO: remove after fix in FR.Compat if (Form.Size.IsEmpty) // fix for Core { Form.Size = new Size(Form.Width, Form.Height); } #endif // compensate difference in caption/border size. Don't ask how but it's working Form.ClientSize = Form.Size; Form.Width -= (int)((Form.Width - Form.ClientSize.Width) * DrawUtils.ScreenDpiFX); Form.Height -= (int)((Form.Height - Form.ClientSize.Height) * DrawUtils.ScreenDpiFX); } #if !FRCORE FixControlFonts(Form); Form.ResumeLayout(false); #else Form.ResumeLayout(); #endif } internal void InitializeControls() { Form.Hide(); Form.StartPosition = FormStartPosition.CenterScreen; Form.Load += Form_Load; Form.FormClosed += Form_FormClosed; Form.FormClosing += Form_FormClosing; Form.Shown += Form_Shown; Form.Resize += Form_Resize; Form.Paint += Form_Paint; ObjectCollection allObjects = AllObjects; foreach (Base c in allObjects) { if (c is DialogControl) { (c as DialogControl).InitializeControl(); } } } internal void FinalizeControls() { Form.Load -= Form_Load; Form.FormClosed -= Form_FormClosed; Form.FormClosing -= Form_FormClosing; Form.Shown -= Form_Shown; Form.Resize -= Form_Resize; Form.Paint -= Form_Paint; ObjectCollection allObjects = AllObjects; foreach (Base c in allObjects) { if (c is DialogControl) (c as DialogControl).FinalizeControl(); } } /// /// Shows the form as a modal dialog box with the currently active window set as its owner. /// Wraps the method. /// /// One of the DialogResult values. public DialogResult ShowDialog() { try { InitializeControls(); return Form.ShowDialog(); } finally { FinalizeControls(); } } /// /// Shows the form as a modal dialog box with the currently active window set as its owner. /// Wraps the method. Uses async call to ShowDialog if possible. /// /// One of the DialogResult values. public async Task ShowDialogAsync() { try { InitializeControls(); #if AVALONIA return await Form.ShowDialogAsync(); #else return Form.ShowDialog(); #endif } finally { FinalizeControls(); } } /// /// This method fires the Load event and the script code connected to the LoadEvent. /// /// Event data. public void OnLoad(EventArgs e) { if (Load != null) Load(this, e); InvokeEvent(LoadEvent, e); } /// /// This method fires the FormClosed event and the script code connected to the FormClosedEvent. /// /// Event data. public void OnFormClosed(FormClosedEventArgs e) { if (FormClosed != null) FormClosed(this, e); InvokeEvent(FormClosedEvent, e); } /// /// This method fires the FormClosing event and the script code connected to the FormClosingEvent. /// /// Event data. public void OnFormClosing(FormClosingEventArgs e) { if (form.DialogResult == DialogResult.OK) { // filter data SetErrorControl(null); foreach (Base c in AllObjects) { DataFilterBaseControl c1 = c as DataFilterBaseControl; if (c1 != null && c1.Enabled) { try { if (c1.AutoFilter) c1.FilterData(); c1.SetReportParameter(); } catch { SetErrorControl(c1); } } if (errorControl != null) { e.Cancel = true; break; } } } if (FormClosing != null) FormClosing(this, e); InvokeEvent(FormClosingEvent, e); } /// /// This method fires the Shown event and the script code connected to the ShownEvent. /// /// Event data. public void OnShown(EventArgs e) { if (Shown != null) Shown(this, e); InvokeEvent(ShownEvent, e); } /// /// This method fires the Resize event and the script code connected to the ResizeEvent. /// /// Event data. public void OnResize(EventArgs e) { if (Resize != null) Resize(this, e); InvokeEvent(ResizeEvent, e); } /// /// This method fires the Paint event and the script code connected to the PaintEvent. /// /// Event data. public void OnPaint(PaintEventArgs e) { if (Paint != null) Paint(this, e); InvokeEvent(PaintEvent, e); } #endregion /// /// Initializes a new instance of the DialogPage class. /// public DialogPage() { controls = new DialogComponentCollection(this); #if !FRCORE form = new BaseForm(); #else form = new Form(); #endif form.ShowIcon = false; form.ShowInTaskbar = false; form.FormBorderStyle = FormBorderStyle.FixedDialog; form.MinimizeBox = false; form.MaximizeBox = false; form.Font = DrawUtils.DefaultFont; #if !FRCORE form.DpiChanged += Form_DpiChanged; #endif oldDpi = DrawUtils.ScreenDpi; activeInWeb = false; BaseName = "Form"; SetFlags(Flags.CanWriteBounds, false); } } }