using System.Drawing; namespace System.Windows.Forms { public class Form : ContainerControl, IWin32Window { private bool isDisposed; private bool isClosing; private bool isModal; public System.Windows.Window window { get; } public static bool UseCustomWindowChrome = false; public bool IsCustomWindowChrome => window is CustomControls.ChromeWindow; private DialogResult dialogResult; public DialogResult DialogResult { get => dialogResult; set { dialogResult = value; if (value == DialogResult.None) return; if (!isClosing) window.Close(); } } public override string Text { get => window.Title; set => window.Title = value; } public override int Left { get => (int)(window.Left * DpiScale); set => window.Left = value / DpiScale; } public override int Top { get => (int)(window.Top * DpiScale); set => window.Top = value / DpiScale; } public override System.Drawing.Size ClientSize { get { var delta = ((IForm)window).ClientSizeDelta; return new Drawing.Size(Width - delta.Width, Height - delta.Height); } set { var delta = ((IForm)window).ClientSizeDelta; Width = value.Width + delta.Width; Height = value.Height + delta.Height; } } public FormBorderStyle FormBorderStyle { get => ((IForm)window).FormBorderStyle; set => ((IForm)window).FormBorderStyle = value; } public bool MaximizeBox { get => ((IForm)window).MaximizeBox; set => ((IForm)window).MaximizeBox = value; } public bool MinimizeBox { get => ((IForm)window).MinimizeBox; set => ((IForm)window).MinimizeBox = value; } public bool KeyPreview { get; set; } // TODO public bool ShowIcon { get => ((IForm)window).ShowIcon; set => ((IForm)window).ShowIcon = value; } public Form MdiParent { get; set; } // TODO? private Icon icon; public Icon Icon { get => icon; set { icon = value; window.Icon = Helper.GetIcon(icon); } } public bool TopMost { get => window.Topmost; set => window.Topmost = value; } public bool ShowInTaskbar { get => window.ShowInTaskbar; set => window.ShowInTaskbar = value; } public FormStartPosition StartPosition { get; set; } private Button acceptButton; public Button AcceptButton { get => acceptButton; set { if (value != acceptButton) { if (acceptButton != null) (acceptButton.control as System.Windows.Controls.Button).IsDefault = false; if (value != null) (value.control as System.Windows.Controls.Button).IsDefault = true; acceptButton = value; } } } private Button cancelButton; public Button CancelButton { get => cancelButton; set { if (value != cancelButton) { if (cancelButton != null) (cancelButton.control as System.Windows.Controls.Button).IsCancel = true; if (value != null) (value.control as System.Windows.Controls.Button).IsCancel = true; cancelButton = value; } } } public Form Owner { get => window.Owner?.Tag as Form; set => window.Owner = value?.window; } public Control ActiveControl // TODO? { get { var el = System.Windows.Input.FocusManager.GetFocusedElement(window); if (el is System.Windows.Controls.Control ctl && ctl.Tag is Control c) return c; return null; } set { if (value != null) { value.Focus(); } } } public FormWindowState WindowState { get => (FormWindowState)window.WindowState; set => window.WindowState = (Windows.WindowState)value; } public bool IsDisposed => isDisposed; public override Rectangle DisplayRectangle => new Rectangle(new System.Drawing.Point(0, 0), ClientSize); public event EventHandler Load; public event EventHandler Shown; public event EventHandler Closed; public event FormClosingEventHandler FormClosing; public event FormClosedEventHandler FormClosed; private void CenterWindowOnScreen() { IntPtr mon = NativeMethods.GetCurrentMonitorFromMousePosition(); NativeMethods.RECT rect = NativeMethods.WorkAreaBoundsForMointor(mon); float dpiScale = (float)NativeMethods.GetDpiForMonitor(mon) / DeviceDpi; int newWidth = (int)(Width * dpiScale); int newHeight = (int)(Height * dpiScale); MoveWindow(rect.left + (rect.Width - newWidth) / 2, rect.top + (rect.Height - newHeight) / 2, newWidth, newHeight); } private void CenterWindowOnParent() { if (Owner != null) { // TODO: check multimonitor dpi! window.Left = (Owner.Left + (Owner.Width - Width) / 2) / Owner.DpiScale; window.Top = (Owner.Top + (Owner.Height - Height) / 2) / Owner.DpiScale; } } private void SetWindowPosition() { if (StartPosition == FormStartPosition.CenterScreen) { CenterWindowOnScreen(); } else if (StartPosition == FormStartPosition.CenterParent) { CenterWindowOnParent(); } } protected virtual void OnLoad(EventArgs e) => Load?.Invoke(this, e); protected virtual void OnShown(EventArgs e) => Shown?.Invoke(this, e); protected virtual void OnFormClosing(FormClosingEventArgs e) => FormClosing?.Invoke(this, e); protected virtual void OnFormClosed(FormClosedEventArgs e) { FormClosed?.Invoke(this, e); OnClosed(EventArgs.Empty); isDisposed = true; } protected virtual void OnClosed(EventArgs e) => Closed?.Invoke(this, e); protected override void Dispose(bool disposing) { base.Dispose(disposing); if (disposing) { window.Close(); } } public override void ResumeLayout(bool resume) { float scale = DeviceDpi / AutoScaleDimensions.Width; if (AutoScaleMode == AutoScaleMode.Dpi || AutoScaleMode == AutoScaleMode.Font) { if (scale != 1) Scale(scale, scale); } base.ResumeLayout(resume); UpdateLayout(); } public new void Show() { SetWindowPosition(); OnLoad(EventArgs.Empty); isModal = false; window.Show(); } public void Show(IWin32Window owner) { Owner = owner as Form; Show(); } public DialogResult ShowDialog() { // this solves problem with dialog window & click on taskbar button if (Owner == null) { var ownerWindow = NativeMethods.ActiveWindow(); if (ownerWindow != null && ownerWindow != window && ownerWindow.IsVisible) window.Owner = ownerWindow; } SetWindowPosition(); OnLoad(EventArgs.Empty); isModal = true; window.ShowDialog(); return DialogResult; } public DialogResult ShowDialog(IWin32Window owner) { Owner = owner as Form; return ShowDialog(); } public void Close() => window.Close(); public new void Hide() => window.Hide(); protected virtual void OnDpiChanged(object sender, EventArgs e) { } private void EnumControls(Control control, Action action) { action(control); foreach (Control c in control.Controls) EnumControls(c, action); } public void MoveWindow(Rectangle rect) => MoveWindow(rect.Left, rect.Top, rect.Width, rect.Height); public void MoveWindow(int left, int top, int width, int height) { NativeMethods.MoveWindow(this, new Rectangle(left, top, width, height)); Width = (int)(window.Width * DpiScale); Height = (int)(window.Height * DpiScale); } // this method is called by the FR dialog form designer public void MoveWindow(int left, int top, System.Windows.Media.Visual target) { // do default dpi scale SuspendLayout(); ResumeLayout(false); // Suspend/Resume pair: fix issue with FR dialog form designer when moved to another monitor (bad anchors) SuspendLayout(); double rescale = Helper.GetDpiScale(target) / DpiScale; NativeMethods.MoveWindow(this, new Rectangle(left, top, (int)(Width * rescale), (int)(Height * rescale))); AutoScaleDimensions = new SizeF((int)(DeviceDpi * rescale), (int)(DeviceDpi * rescale)); // this.ResumeLayout will rescale controls, we don't need it base.ResumeLayout(false); // fix repaint issue EnumControls(this, c => { if (c != this) c.AfterDpiChange(1); }); } public Form() { window = UseCustomWindowChrome ? new CustomControls.ChromeWindow() : new SystemWindow(); var contentControl = ((IForm)window).ContentControl; SetContentControl(window, contentControl); contentControl.SizeChanged += (s, e) => UpdateLayout(); window.UseLayoutRounding = true; #if Demo var demoLabel = new Controls.TextBlock(); demoLabel.Text = " Demo version "; demoLabel.HorizontalAlignment = Windows.HorizontalAlignment.Center; demoLabel.VerticalAlignment = VerticalAlignment.Bottom; demoLabel.Opacity = 0.5; container.Children.Add(demoLabel); #endif window.Loaded += (sender, e) => OnShown(e); // this is the SWF Shown equivalent window.Closing += (sender, e) => { isClosing = true; var args = new FormClosingEventArgs(CloseReason.UserClosing, false); OnFormClosing(args); e.Cancel = args.Cancel; if (args.Cancel) DialogResult = DialogResult.None; isClosing = false; }; window.Closed += (sender, e) => OnFormClosed(new FormClosedEventArgs(CloseReason.UserClosing)); window.StateChanged += (s, e) => { if (window.WindowState == System.Windows.WindowState.Minimized && isModal && !ShowInTaskbar) { System.Windows.Application.Current.MainWindow.WindowState = System.Windows.WindowState.Minimized; } }; DpiRescaler.Install(window, this, container, OnDpiChanged); AutoScaleDimensions = new System.Drawing.SizeF(96, 96); BackColor = System.Drawing.SystemColors.Control; } } }