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