From 22aa88022dc8c41241e7c55db9a55341d5e48b54 Mon Sep 17 00:00:00 2001 From: "13997737+wolframhaussig@users.noreply.github.com" <13997737+wolframhaussig@users.noreply.github.com> Date: Sat, 24 Feb 2024 18:25:49 +0100 Subject: [PATCH 1/8] add StylableInputBox - add StylableInputBox (currently supports Text and Number) - add StylableInputBoxBuilder --- .../FrmDefault.Designer.cs | 62 ++++- .../FrmDefault.cs | 13 +- .../FrmDefault.resx | 2 +- .../InputBoxes/InputBoxControls.cs | 43 ++++ .../InputBoxes/StylableInputBox.Designer.cs | 81 ++++++ .../InputBoxes/StylableInputBox.cs | 241 ++++++++++++++++++ .../InputBoxes/StylableInputBox.de.resx | 126 +++++++++ .../InputBoxes/StylableInputBox.resx | 126 +++++++++ .../InputBoxes/StylableInputBoxBuilder.cs | 128 ++++++++++ .../StylableWinFormsControls.csproj | Bin 3274 -> 3534 bytes 10 files changed, 812 insertions(+), 10 deletions(-) create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs index 1d5345d..c1945dd 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs @@ -30,11 +30,11 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - ListViewItem listViewItem1 = new ListViewItem("Content"); - ListViewItem listViewItem2 = new ListViewItem("Content"); - ListViewItem listViewItem3 = new ListViewItem(new string[] { "Content", "Content" }, -1); - ListViewItem listViewItem4 = new ListViewItem("Content"); - ListViewItem listViewItem5 = new ListViewItem("Content"); + ListViewItem listViewItem6 = new ListViewItem("Content"); + ListViewItem listViewItem7 = new ListViewItem("Content"); + ListViewItem listViewItem8 = new ListViewItem(new string[] { "Content", "Content" }, -1); + ListViewItem listViewItem9 = new ListViewItem("Content"); + ListViewItem listViewItem10 = new ListViewItem("Content"); stylableButton1 = new StylableButton(); stylableCheckBox1 = new StylableCheckBox(); stylableComboBox1 = new StylableComboBox(); @@ -62,6 +62,7 @@ private void InitializeComponent() gb_stylableDataGridView = new StylableGroupBox(); gb_stylableLabel = new StylableGroupBox(); gb_stylableTextBox = new StylableGroupBox(); + stylableButton2 = new StylableButton(); ((System.ComponentModel.ISupportInitialize)stylableDataGridView1).BeginInit(); stylableTabControl1.SuspendLayout(); gb_stylabletabcontrol.SuspendLayout(); @@ -85,7 +86,7 @@ private void InitializeComponent() stylableButton1.EnabledHoverColor = Color.LightGray; stylableButton1.Location = new Point(6, 22); stylableButton1.Name = "stylableButton1"; - stylableButton1.Size = new Size(123, 23); + stylableButton1.Size = new Size(85, 23); stylableButton1.TabIndex = 0; stylableButton1.Text = "This is content"; stylableButton1.UseVisualStyleBackColor = true; @@ -102,8 +103,10 @@ private void InitializeComponent() // // stylableComboBox1 // + stylableComboBox1.BorderColor = SystemColors.ControlDark; stylableComboBox1.DrawMode = DrawMode.OwnerDrawFixed; stylableComboBox1.FormattingEnabled = true; + stylableComboBox1.ItemHoverColor = SystemColors.Highlight; stylableComboBox1.Items.AddRange(new object[] { "This is content 1", "This is content 2", "This is content 3", "This is content with slightly more length" }); stylableComboBox1.Location = new Point(6, 22); stylableComboBox1.Name = "stylableComboBox1"; @@ -173,9 +176,13 @@ private void InitializeComponent() // stylableListView1 // stylableListView1.Columns.AddRange(new ColumnHeader[] { columnHeader1, columnHeader2 }); - stylableListView1.Items.AddRange(new ListViewItem[] { listViewItem1, listViewItem2, listViewItem3, listViewItem4, listViewItem5 }); + stylableListView1.GroupHeaderBackColor = Color.LightGray; + stylableListView1.GroupHeaderForeColor = Color.Black; + stylableListView1.Items.AddRange(new ListViewItem[] { listViewItem6, listViewItem7, listViewItem8, listViewItem9, listViewItem10 }); stylableListView1.Location = new Point(6, 18); stylableListView1.Name = "stylableListView1"; + stylableListView1.SelectedItemBackColor = Color.LightGray; + stylableListView1.SelectedItemForeColor = Color.Black; stylableListView1.Size = new Size(242, 178); stylableListView1.TabIndex = 6; stylableListView1.UseCompatibleStateImageBehavior = false; @@ -193,6 +200,8 @@ private void InitializeComponent() // stylableTabControl1.ActiveTabBackgroundColor = SystemColors.Control; stylableTabControl1.ActiveTabForegroundColor = SystemColors.ControlText; + stylableTabControl1.BackgroundColor = SystemColors.Control; + stylableTabControl1.BorderColor = SystemColors.ControlDark; stylableTabControl1.Controls.Add(tabPage1); stylableTabControl1.Controls.Add(tabPage2); stylableTabControl1.Location = new Point(6, 22); @@ -227,7 +236,7 @@ private void InitializeComponent() stylableTextBox1.BorderColor = Color.Blue; stylableTextBox1.BorderStyle = BorderStyle.None; stylableTextBox1.DelayedTextChangedTimeout = 900; - stylableTextBox1.ForeColor = Color.Black; + stylableTextBox1.ForeColor = Color.Gray; stylableTextBox1.Hint = "Hello, my name is ..."; stylableTextBox1.HintForeColor = Color.Gray; stylableTextBox1.IsDelayActive = true; @@ -235,6 +244,7 @@ private void InitializeComponent() stylableTextBox1.Name = "stylableTextBox1"; stylableTextBox1.Size = new Size(207, 16); stylableTextBox1.TabIndex = 8; + stylableTextBox1.Text = "Hello, my name is ..."; stylableTextBox1.TextForeColor = Color.Black; // // lbl_description @@ -250,6 +260,8 @@ private void InitializeComponent() // gb_stylabletabcontrol // gb_stylabletabcontrol.Controls.Add(stylableTabControl1); + gb_stylabletabcontrol.DisabledForeColor = SystemColors.GrayText; + gb_stylabletabcontrol.EnabledForeColor = SystemColors.ControlText; gb_stylabletabcontrol.Location = new Point(237, 230); gb_stylabletabcontrol.Name = "gb_stylabletabcontrol"; gb_stylabletabcontrol.Size = new Size(286, 218); @@ -260,6 +272,8 @@ private void InitializeComponent() // gb_stylablelistview // gb_stylablelistview.Controls.Add(stylableListView1); + gb_stylablelistview.DisabledForeColor = SystemColors.GrayText; + gb_stylablelistview.EnabledForeColor = SystemColors.ControlText; gb_stylablelistview.Location = new Point(529, 234); gb_stylablelistview.Name = "gb_stylablelistview"; gb_stylablelistview.Size = new Size(262, 214); @@ -269,7 +283,10 @@ private void InitializeComponent() // // gb_stylablebutton // + gb_stylablebutton.Controls.Add(stylableButton2); gb_stylablebutton.Controls.Add(stylableButton1); + gb_stylablebutton.DisabledForeColor = SystemColors.GrayText; + gb_stylablebutton.EnabledForeColor = SystemColors.ControlText; gb_stylablebutton.Location = new Point(12, 349); gb_stylablebutton.Name = "gb_stylablebutton"; gb_stylablebutton.Size = new Size(217, 59); @@ -280,6 +297,8 @@ private void InitializeComponent() // gb_stylablecheckbox // gb_stylablecheckbox.Controls.Add(stylableCheckBox1); + gb_stylablecheckbox.DisabledForeColor = SystemColors.GrayText; + gb_stylablecheckbox.EnabledForeColor = SystemColors.ControlText; gb_stylablecheckbox.Location = new Point(610, 456); gb_stylablecheckbox.Name = "gb_stylablecheckbox"; gb_stylablecheckbox.Size = new Size(181, 44); @@ -290,6 +309,8 @@ private void InitializeComponent() // gb_stylableComboBox // gb_stylableComboBox.Controls.Add(stylableComboBox1); + gb_stylableComboBox.DisabledForeColor = SystemColors.GrayText; + gb_stylableComboBox.EnabledForeColor = SystemColors.ControlText; gb_stylableComboBox.Location = new Point(12, 287); gb_stylableComboBox.Name = "gb_stylableComboBox"; gb_stylableComboBox.Size = new Size(217, 56); @@ -300,6 +321,8 @@ private void InitializeComponent() // gb_stylableDateTimePicker // gb_stylableDateTimePicker.Controls.Add(stylableDateTimePicker1); + gb_stylableDateTimePicker.DisabledForeColor = SystemColors.GrayText; + gb_stylableDateTimePicker.EnabledForeColor = SystemColors.ControlText; gb_stylableDateTimePicker.Location = new Point(12, 230); gb_stylableDateTimePicker.Name = "gb_stylableDateTimePicker"; gb_stylableDateTimePicker.Size = new Size(217, 51); @@ -310,6 +333,8 @@ private void InitializeComponent() // gb_stylableDataGridView // gb_stylableDataGridView.Controls.Add(stylableDataGridView1); + gb_stylableDataGridView.DisabledForeColor = SystemColors.GrayText; + gb_stylableDataGridView.EnabledForeColor = SystemColors.ControlText; gb_stylableDataGridView.Location = new Point(12, 36); gb_stylableDataGridView.Name = "gb_stylableDataGridView"; gb_stylableDataGridView.Size = new Size(779, 178); @@ -320,6 +345,8 @@ private void InitializeComponent() // gb_stylableLabel // gb_stylableLabel.Controls.Add(stylableLabel1); + gb_stylableLabel.DisabledForeColor = SystemColors.GrayText; + gb_stylableLabel.EnabledForeColor = SystemColors.ControlText; gb_stylableLabel.Location = new Point(462, 454); gb_stylableLabel.Name = "gb_stylableLabel"; gb_stylableLabel.Size = new Size(142, 46); @@ -330,6 +357,8 @@ private void InitializeComponent() // gb_stylableTextBox // gb_stylableTextBox.Controls.Add(stylableTextBox1); + gb_stylableTextBox.DisabledForeColor = SystemColors.GrayText; + gb_stylableTextBox.EnabledForeColor = SystemColors.ControlText; gb_stylableTextBox.Location = new Point(237, 454); gb_stylableTextBox.Name = "gb_stylableTextBox"; gb_stylableTextBox.Size = new Size(219, 46); @@ -337,6 +366,22 @@ private void InitializeComponent() gb_stylableTextBox.TabStop = false; gb_stylableTextBox.Text = "StylableTextBox"; // + // stylableButton2 + // + stylableButton2.BorderColor = Color.Black; + stylableButton2.DisabledBackColor = Color.Gray; + stylableButton2.DisabledForeColor = Color.Black; + stylableButton2.EnabledBackColor = Color.White; + stylableButton2.EnabledForeColor = Color.Black; + stylableButton2.EnabledHoverColor = Color.LightGray; + stylableButton2.Location = new Point(111, 22); + stylableButton2.Name = "stylableButton2"; + stylableButton2.Size = new Size(85, 23); + stylableButton2.TabIndex = 1; + stylableButton2.Text = "InputBox"; + stylableButton2.UseVisualStyleBackColor = true; + stylableButton2.Click += stylableButton2_Click; + // // FrmDefault // AutoScaleDimensions = new SizeF(7F, 15F); @@ -401,5 +446,6 @@ private void InitializeComponent() private DataGridViewTextBoxColumn Column2; private DataGridViewTextBoxColumn Column3; private DataGridViewTextBoxColumn Column4; + private StylableButton stylableButton2; } } diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs index 038878e..e0453bf 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs @@ -6,5 +6,16 @@ public FrmDefault() { InitializeComponent(); } + + private void stylableButton2_Click(object sender, EventArgs e) + { + StylableInputBox iBox = StylableInputBox.BUILDER + .WithTitle("Numeric Test", MessageBoxIcon.Information) + .WithText("Please enter a random number between -100 and 100") + .WithHelpButton(new Uri("https://github.com/Assorted-Development/winforms-stylable-controls")) + .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) + .ForNumericValue(0, -100, 100); + iBox.ShowDialog(); + } } -} \ No newline at end of file +} diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.resx b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.resx index 9563326..45ad320 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.resx +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.resx @@ -18,7 +18,7 @@ System.Resources.ResXResourceReader, System.Windows.Forms, ... System.Resources.ResXResourceWriter, System.Windows.Forms, ... this is my long stringthis is a comment - Blue + Blue [base64 mime encoded serialized .NET Framework object] diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs new file mode 100644 index 0000000..a20722c --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs @@ -0,0 +1,43 @@ + +namespace StylableWinFormsControls +{ + /// + /// container to provide strongly typed access to all controls of the inputBox for styling + /// + public sealed class InputBoxControls where T : Control + { + /// + /// the label containing the Text + /// + public StylableLabel Text { get; init; } + /// + /// the 'OK' Button + /// + public StylableButton OkButton { get; init; } + /// + /// the 'Cancel' Button + /// + public StylableButton CancelButton { get; init; } + /// + /// returns all buttons + /// + public StylableButton[] Buttons => new StylableButton[] { OkButton, CancelButton }; + /// + /// the control for entering the value + /// + public T InputControl { get; init; } + /// + /// constructor + /// + /// the label containing the Text + /// + /// + public InputBoxControls(StylableLabel text, StylableButton okButton, StylableButton cancelButton, T inputControl) + { + Text = text; + OkButton = okButton; + CancelButton = cancelButton; + InputControl = inputControl; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs new file mode 100644 index 0000000..2360581 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// Dieser Code wurde von einem Tool generiert. +// Laufzeitversion:4.0.30319.42000 +// +// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn +// der Code erneut generiert wird. +// +//------------------------------------------------------------------------------ + +namespace StylableWinFormsControls.InputBoxes { + using System; + + + /// + /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. + /// + // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert + // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. + // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen + // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class StylableInputBox { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal StylableInputBox() { + } + + /// + /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StylableWinFormsControls.InputBoxes.StylableInputBox", typeof(StylableInputBox).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle + /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die Cancel ähnelt. + /// + internal static string Cancel { + get { + return ResourceManager.GetString("Cancel", resourceCulture); + } + } + + /// + /// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt. + /// + internal static string OK { + get { + return ResourceManager.GetString("OK", resourceCulture); + } + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs new file mode 100644 index 0000000..552b444 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs @@ -0,0 +1,241 @@ +using System.Data; +using System.Diagnostics; +using System.Globalization; +using StylableWinFormsControls.InputBoxes; +using System.Resources; + +namespace StylableWinFormsControls +{ + public class StylableInputBox : Form where T : Control + { + /// + /// additional form width + /// + public const int BORDER_WIDTH = 20; + /// + /// additional form height + /// + public const int BORDER_HEIGHT = 10; + /// + /// returns a builder object to configure the + /// + public static StylableInputBoxBuilder BUILDER => new(); + /// + /// resource manager used to access localized texts (does not use constructor with type as this fails with generic types) + /// + private static ResourceManager _resources = new("StylableWinFormsControls.StylableInputBox", typeof(StylableInputBox).Assembly); + /// + /// contains the stylable controls for easier access than iterating over Controls + /// + public InputBoxControls StylableControls { get; } + /// + /// constructor. not available to others as they should use the + /// + /// the caption + /// the icon in the title bar + /// the prompt text + /// defines which button should be selected by default + /// the url to open when the user clicks on the help button + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + /// the control to input the value + internal StylableInputBox(string caption, MessageBoxIcon icon, string text, MessageBoxDefaultButton defaultButton, Uri? helpUri, TimeSpan? timeout, DialogResult timeoutResult, T inputControl) + { + StartPosition = FormStartPosition.CenterScreen; + FormBorderStyle = FormBorderStyle.FixedDialog; + MinimizeBox = false; + MaximizeBox = false; + handleTitle(caption, icon, helpUri); + StylableControls = new InputBoxControls( + handleText(text), + createButton(DialogResult.OK), + createButton(DialogResult.Cancel), + handleInput(inputControl) + ); + handleTimeouts(timeout, timeoutResult); + UpdateSize(); + } + /// + /// resize the form to fit the content + /// + /// if true, the sizes and positions of all controls will be recalculated. otherwise, only the form will be updated + public void UpdateSize(bool updateControlSize = true) + { + int titleBarHeight = getWindowTitleBarHeight(); + + if (updateControlSize) + { + int marginLeft = (from c in Controls.Cast() select c.Margin.Left).Min(); + int marginTop = (from c in Controls.Cast() select c.Margin.Top).Min(); + + Point currentContentPos = new(6 + marginLeft, 20 + marginTop); + + if (StylableControls.Text is not null) + { + setMargin(StylableControls.Text, marginLeft, marginTop); + + StylableControls.Text.Left = currentContentPos.X; + StylableControls.Text.Top = currentContentPos.Y; + } + + currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; + + // Margins on CheckBoxes seem to not work directly + StylableControls.InputControl.Left = currentContentPos.X + marginLeft; + StylableControls.InputControl.Top = currentContentPos.Y + marginTop; + currentContentPos.Y += StylableControls.InputControl.Height + 6; + + currentContentPos.Y += 16; + + foreach (StylableButton sb in StylableControls.Buttons) + { + setMargin(sb, marginLeft, marginTop); + sb.Left = currentContentPos.X; + sb.Top = currentContentPos.Y; + + currentContentPos.X = currentContentPos.X + sb.Width + 10; + } + } + + Width = (from c in Controls.Cast() select c.Left + c.Width + c.Margin.Left + c.Margin.Right + BORDER_WIDTH).Max(); + Height = (from c in Controls.Cast() select c.Top + c.Height + c.Margin.Top + c.Margin.Bottom + BORDER_HEIGHT + titleBarHeight).Max(); + } + /// + /// creates the prompt text + /// + /// the prompt text + private StylableLabel handleText(string text) + { + StylableLabel label = new() + { + Text = text, + AutoSize = true + }; + Controls.Add(label); + return label; + } + /// + /// adds the input control + /// + /// the input control + private T handleInput(T input) + { + Controls.Add(input); + return input; + } + /// + /// Create a button for the given DialogResult + /// + /// + private StylableButton createButton(DialogResult result) + { + StylableButton b = new() + { + Text = _resources.GetString(result.ToString(), CultureInfo.CurrentCulture), + DialogResult = result, + AutoSize = true + }; + Controls.Add(b); + return b; + } + /// + /// the time left before the messageBox closes automatically + /// + private int _timeLeft; + /// + /// time for updating the time left on the default button + /// + private System.Windows.Forms.Timer? _uiUpdate; + /// + /// the timer to close the inputbox + /// + private System.Windows.Forms.Timer? _timeout; + /// + /// configures timeout and timers if needed + /// + /// defines the intervall after which the inputbox is closed automatically + /// defines the to return when the timeout hits + private void handleTimeouts(TimeSpan? timeout, DialogResult timeoutResult) + { + if (timeout is not null) + { + _uiUpdate = new System.Windows.Forms.Timer() + { + Interval = 1000 + }; + //the timeoutResult may not be necessarily in the list of available buttons + Button defaultButton = StylableControls.Buttons.FirstOrDefault(b => b.DialogResult == timeoutResult) ?? StylableControls.Buttons.First(b => b == AcceptButton); + string basicText = defaultButton.Text; + _uiUpdate.Tick += (sender, e) => { _timeLeft--; defaultButton!.Text = $"{basicText} ({_timeLeft}s)"; }; + + _timeout = new System.Windows.Forms.Timer() + { + Interval = (int)timeout.Value.TotalMilliseconds + }; + _timeout.Tick += (sender, e) => { DialogResult = timeoutResult; Close(); }; + + VisibleChanged += (sender, e) => + { + if (Visible) + { + _timeLeft = (int)timeout.Value.TotalSeconds; + _uiUpdate.Start(); + _timeout.Start(); + } + else + { + _uiUpdate.Stop(); + _timeout.Stop(); + } + }; + } + } + /// + /// configures the title bar + /// + /// the caption + /// the icon in the title bar + /// the url to open when the user clicks on the help button + private void handleTitle(string caption, MessageBoxIcon icon, Uri? helpUri) + { + Text = caption; + Icon = icon switch + { + MessageBoxIcon.Error => SystemIcons.Error, + MessageBoxIcon.Exclamation => SystemIcons.Exclamation, + MessageBoxIcon.Information => SystemIcons.Information, + MessageBoxIcon.Question => SystemIcons.Question, + _ => null + }; + if (helpUri is not null) + { + HelpButton = true; + HelpButtonClicked += (sender, e) => Process.Start(new ProcessStartInfo(helpUri.ToString()) { UseShellExecute = true }); + } + } + private int getWindowTitleBarHeight() + { + Rectangle screenRectangle = RectangleToScreen(ClientRectangle); + return screenRectangle.Top - Top; + } + + private static void setMargin(Control? c, int marginLeft, int marginTop) + { + if (c is null) + { + return; + } + + c.Margin = new Padding(marginLeft, marginTop, c.Margin.Right, c.Margin.Top); + } + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + if (disposing) + { + _uiUpdate?.Dispose(); + _timeout?.Dispose(); + } + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx new file mode 100644 index 0000000..c57e676 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Abbrechen + + + OK + + \ No newline at end of file diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx new file mode 100644 index 0000000..147c39a --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Cancel + + + OK + + \ No newline at end of file diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs new file mode 100644 index 0000000..4b81f44 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs @@ -0,0 +1,128 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace StylableWinFormsControls.InputBoxes +{ + /// + /// the builder to configure the + /// + public sealed class StylableInputBoxBuilder + { + /// + /// the caption + /// + private string _caption = string.Empty; + /// + /// the icon in the title bar + /// + private MessageBoxIcon _icon = MessageBoxIcon.None; + /// + /// the prompt text + /// + private string _text = string.Empty; + /// + /// defines which button should be selected by default + /// + private MessageBoxDefaultButton _defaultButton = MessageBoxDefaultButton.Button1; + /// + /// the url to open when the user clicks on the help button + /// + private Uri? _helpUri; + /// + /// defines the intervall after which the inputBox is closed automatically + /// + private TimeSpan? _timeout; + /// + /// defines the to return when the timeout hits + /// + private DialogResult _timeoutResult = DialogResult.None; + /// + /// creates the for text input + /// + /// the value to show at the start + /// the completely configured but unstyled + public StylableInputBox ForText(string startValue = "") + { + TextBox textBox = new() + { + Text = startValue + }; + return new StylableInputBox(_caption, _icon, _text, _defaultButton, _helpUri, _timeout, _timeoutResult, textBox); + } + /// + /// creates the for text input + /// + /// the completely configured but unstyled + public StylableInputBox ForNumericValue(decimal startValue = 0, decimal minValue = decimal.MinValue, decimal maxValue = decimal.MaxValue) + { + NumericUpDown nup = new() + { + Minimum = minValue, + Maximum = maxValue, + Value = startValue + }; + return new StylableInputBox(_caption, _icon, _text, _defaultButton, _helpUri, _timeout, _timeoutResult, nup); + } + /// + /// Set the prompt text of the InputBox + /// + /// + public StylableInputBoxBuilder WithText(string text) + { + _text = text ?? string.Empty; + return this; + } + /// + /// Configure the title bar + /// + /// the caption + /// the icon + public StylableInputBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) + { + _caption = caption ?? string.Empty; + _icon = icon; + return this; + } + /// + /// when called, the dialog will close after the given timeout and return the given default result + /// + /// defines the intervall after which the inputbox is closed automatically + /// defines the to return when the timeout hits + public StylableInputBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) + { + _timeout = timeout; + _timeoutResult = timeoutResult; + return this; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableInputBoxBuilder WithHelpButton(string url) + { + if (url is null) + { + throw new ArgumentNullException(nameof(url)); + } + return WithHelpButton(new Uri(url)); + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableInputBoxBuilder WithHelpButton(Uri url) + { + if (url is null) + { + throw new ArgumentNullException(nameof(url)); + } + _helpUri = url; + return this; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj b/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj index f73e1dc4fca8a7aeaec8c19d6f7f86262ad5937e..444ee8ff918bdf49aa6d899e626af17783cf8861 100644 GIT binary patch delta 295 zcmX>lc}{vl05dNG*F=B+iL>-33vjVaJW>RrCL1xjf$0*)I52$Ink2wuYe_&Pv(?TrYz%)p$1ZxbKt->xfxr_AxRQwTCECQ~shaF=6G;Wc} z4jclL)i}(+auFO5cOBz^xQm0+X0ijP!Q?(Jh+Tc0Ah#geSk@)PS<3C#!K8 wf%S)QNlor!W}7^PM-D94%cTytvy4Y*@-?o4$yVG6ll!=@fyEPejG*ex0A=1!RR910 delta 185 zcmX>neM)jdz{C*0iOaMm-pFILnOw*yJUNL`Z}JSrsL8*8IEJZg@-3!GlS`Q6Cf{OC zn(V@&G&zsu6HrWGas_M5 Date: Sat, 24 Feb 2024 18:31:16 +0100 Subject: [PATCH 2/8] add input box to readme --- README.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/README.md b/README.md index 767ad45..ab13d11 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,25 @@ Has the following additional characteristics: * Supports providing hints to be shown when the control does not have focus and the value is empty. * Supports delaying `TextChanged` events +### Interaction.InputBox => StylableInputBox +With the `StylableInputBox`, you can create forms similar to VB.NETs `Interaction.InputBox` but the handling is a bit different as we allow you to style the form +before showing. + +Let's create an input box first: +```csharp +StylableInputBox iBox = StylableInputBox.BUILDER + .WithTitle("Numeric Test", MessageBoxIcon.Information) + .WithText("Please enter a random number between -100 and 100") + .WithHelpButton(new Uri("https://github.com/Assorted-Development/winforms-stylable-controls")) + .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) + .ForNumericValue(0, -100, 100); +``` +This will create an input box for numeric values (currently, we support text and numeric) with a title and a message and two buttons: Okay, Cancel +Now, let's style the form as we want to: `iBox.StylableControls.Text.ForeColor = Color.Red;` +At last, you can show the dialog using `iBox.ShowDialog()` + +**Note:** If you change the size on the controls (e.g. increase the font size), please call `UpdateSize()` to update the UI to the new settings. Otherwise, the Ui may look weird. + ## Contributions From c570a087ed9b9b8004b91513bd84e44d337764d0 Mon Sep 17 00:00:00 2001 From: Nockiro Date: Sun, 25 Feb 2024 00:07:52 +0100 Subject: [PATCH 3/8] Restructured input boxes to reduce duplicate code as much as possible --- .../InputBoxes/InputBoxControls.cs | 43 ---- .../InputBoxes/StylableInputBox.Designer.cs | 81 ------ .../InputBoxes/StylableInputBox.cs | 241 ----------------- .../InputBoxes/StylableInputBox.cs | 63 +++++ .../InputBoxes/StylableInputBox.de.resx | 0 .../InputBoxes/StylableInputBox.resx | 0 .../InputBoxes/StylableInputBoxBuilder.cs | 165 +++++------- .../InteractionBoxControls.cs} | 86 ++++--- .../MessageBoxes/StylableMessageBox.cs | 82 ++++++ .../MessageBoxes/StylableMessageBox.de.resx | 0 .../MessageBoxes/StylableMessageBox.resx | 0 .../MessageBoxes/StylableMessageBoxBuilder.cs | 90 +++++++ .../StylableInteractionBox.cs} | 102 ++++---- .../StylableInteractionBox.de.resx | 144 +++++++++++ .../StylableInteractionBox.resx | 144 +++++++++++ .../StylableInteractionBoxBuilder.cs} | 243 ++++++++---------- .../StylableWinFormsControls.csproj | Bin 3534 -> 3750 bytes 17 files changed, 792 insertions(+), 692 deletions(-) delete mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs delete mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs delete mode 100644 StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs rename StylableWinFormsControls/StylableWinFormsControls/{ => InteractionBoxes}/InputBoxes/StylableInputBox.de.resx (100%) rename StylableWinFormsControls/StylableWinFormsControls/{ => InteractionBoxes}/InputBoxes/StylableInputBox.resx (100%) rename StylableWinFormsControls/StylableWinFormsControls/{ => InteractionBoxes}/InputBoxes/StylableInputBoxBuilder.cs (53%) rename StylableWinFormsControls/StylableWinFormsControls/{MessageBoxes/MessageBoxControls.cs => InteractionBoxes/InteractionBoxControls.cs} (59%) create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs rename StylableWinFormsControls/StylableWinFormsControls/{ => InteractionBoxes}/MessageBoxes/StylableMessageBox.de.resx (100%) rename StylableWinFormsControls/StylableWinFormsControls/{ => InteractionBoxes}/MessageBoxes/StylableMessageBox.resx (100%) create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs rename StylableWinFormsControls/StylableWinFormsControls/{MessageBoxes/StylableMessageBox.cs => InteractionBoxes/StylableInteractionBox.cs} (82%) create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.de.resx create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.resx rename StylableWinFormsControls/StylableWinFormsControls/{MessageBoxes/StylableMessageBoxBuilder.cs => InteractionBoxes/StylableInteractionBoxBuilder.cs} (52%) diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs deleted file mode 100644 index a20722c..0000000 --- a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/InputBoxControls.cs +++ /dev/null @@ -1,43 +0,0 @@ - -namespace StylableWinFormsControls -{ - /// - /// container to provide strongly typed access to all controls of the inputBox for styling - /// - public sealed class InputBoxControls where T : Control - { - /// - /// the label containing the Text - /// - public StylableLabel Text { get; init; } - /// - /// the 'OK' Button - /// - public StylableButton OkButton { get; init; } - /// - /// the 'Cancel' Button - /// - public StylableButton CancelButton { get; init; } - /// - /// returns all buttons - /// - public StylableButton[] Buttons => new StylableButton[] { OkButton, CancelButton }; - /// - /// the control for entering the value - /// - public T InputControl { get; init; } - /// - /// constructor - /// - /// the label containing the Text - /// - /// - public InputBoxControls(StylableLabel text, StylableButton okButton, StylableButton cancelButton, T inputControl) - { - Text = text; - OkButton = okButton; - CancelButton = cancelButton; - InputControl = inputControl; - } - } -} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs deleted file mode 100644 index 2360581..0000000 --- a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.Designer.cs +++ /dev/null @@ -1,81 +0,0 @@ -//------------------------------------------------------------------------------ -// -// Dieser Code wurde von einem Tool generiert. -// Laufzeitversion:4.0.30319.42000 -// -// Änderungen an dieser Datei können falsches Verhalten verursachen und gehen verloren, wenn -// der Code erneut generiert wird. -// -//------------------------------------------------------------------------------ - -namespace StylableWinFormsControls.InputBoxes { - using System; - - - /// - /// Eine stark typisierte Ressourcenklasse zum Suchen von lokalisierten Zeichenfolgen usw. - /// - // Diese Klasse wurde von der StronglyTypedResourceBuilder automatisch generiert - // -Klasse über ein Tool wie ResGen oder Visual Studio automatisch generiert. - // Um einen Member hinzuzufügen oder zu entfernen, bearbeiten Sie die .ResX-Datei und führen dann ResGen - // mit der /str-Option erneut aus, oder Sie erstellen Ihr VS-Projekt neu. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class StylableInputBox { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal StylableInputBox() { - } - - /// - /// Gibt die zwischengespeicherte ResourceManager-Instanz zurück, die von dieser Klasse verwendet wird. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("StylableWinFormsControls.InputBoxes.StylableInputBox", typeof(StylableInputBox).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Überschreibt die CurrentUICulture-Eigenschaft des aktuellen Threads für alle - /// Ressourcenzuordnungen, die diese stark typisierte Ressourcenklasse verwenden. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Sucht eine lokalisierte Zeichenfolge, die Cancel ähnelt. - /// - internal static string Cancel { - get { - return ResourceManager.GetString("Cancel", resourceCulture); - } - } - - /// - /// Sucht eine lokalisierte Zeichenfolge, die OK ähnelt. - /// - internal static string OK { - get { - return ResourceManager.GetString("OK", resourceCulture); - } - } - } -} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs deleted file mode 100644 index 552b444..0000000 --- a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.cs +++ /dev/null @@ -1,241 +0,0 @@ -using System.Data; -using System.Diagnostics; -using System.Globalization; -using StylableWinFormsControls.InputBoxes; -using System.Resources; - -namespace StylableWinFormsControls -{ - public class StylableInputBox : Form where T : Control - { - /// - /// additional form width - /// - public const int BORDER_WIDTH = 20; - /// - /// additional form height - /// - public const int BORDER_HEIGHT = 10; - /// - /// returns a builder object to configure the - /// - public static StylableInputBoxBuilder BUILDER => new(); - /// - /// resource manager used to access localized texts (does not use constructor with type as this fails with generic types) - /// - private static ResourceManager _resources = new("StylableWinFormsControls.StylableInputBox", typeof(StylableInputBox).Assembly); - /// - /// contains the stylable controls for easier access than iterating over Controls - /// - public InputBoxControls StylableControls { get; } - /// - /// constructor. not available to others as they should use the - /// - /// the caption - /// the icon in the title bar - /// the prompt text - /// defines which button should be selected by default - /// the url to open when the user clicks on the help button - /// defines the intervall after which the messagebox is closed automatically - /// defines the to return when the timeout hits - /// the control to input the value - internal StylableInputBox(string caption, MessageBoxIcon icon, string text, MessageBoxDefaultButton defaultButton, Uri? helpUri, TimeSpan? timeout, DialogResult timeoutResult, T inputControl) - { - StartPosition = FormStartPosition.CenterScreen; - FormBorderStyle = FormBorderStyle.FixedDialog; - MinimizeBox = false; - MaximizeBox = false; - handleTitle(caption, icon, helpUri); - StylableControls = new InputBoxControls( - handleText(text), - createButton(DialogResult.OK), - createButton(DialogResult.Cancel), - handleInput(inputControl) - ); - handleTimeouts(timeout, timeoutResult); - UpdateSize(); - } - /// - /// resize the form to fit the content - /// - /// if true, the sizes and positions of all controls will be recalculated. otherwise, only the form will be updated - public void UpdateSize(bool updateControlSize = true) - { - int titleBarHeight = getWindowTitleBarHeight(); - - if (updateControlSize) - { - int marginLeft = (from c in Controls.Cast() select c.Margin.Left).Min(); - int marginTop = (from c in Controls.Cast() select c.Margin.Top).Min(); - - Point currentContentPos = new(6 + marginLeft, 20 + marginTop); - - if (StylableControls.Text is not null) - { - setMargin(StylableControls.Text, marginLeft, marginTop); - - StylableControls.Text.Left = currentContentPos.X; - StylableControls.Text.Top = currentContentPos.Y; - } - - currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; - - // Margins on CheckBoxes seem to not work directly - StylableControls.InputControl.Left = currentContentPos.X + marginLeft; - StylableControls.InputControl.Top = currentContentPos.Y + marginTop; - currentContentPos.Y += StylableControls.InputControl.Height + 6; - - currentContentPos.Y += 16; - - foreach (StylableButton sb in StylableControls.Buttons) - { - setMargin(sb, marginLeft, marginTop); - sb.Left = currentContentPos.X; - sb.Top = currentContentPos.Y; - - currentContentPos.X = currentContentPos.X + sb.Width + 10; - } - } - - Width = (from c in Controls.Cast() select c.Left + c.Width + c.Margin.Left + c.Margin.Right + BORDER_WIDTH).Max(); - Height = (from c in Controls.Cast() select c.Top + c.Height + c.Margin.Top + c.Margin.Bottom + BORDER_HEIGHT + titleBarHeight).Max(); - } - /// - /// creates the prompt text - /// - /// the prompt text - private StylableLabel handleText(string text) - { - StylableLabel label = new() - { - Text = text, - AutoSize = true - }; - Controls.Add(label); - return label; - } - /// - /// adds the input control - /// - /// the input control - private T handleInput(T input) - { - Controls.Add(input); - return input; - } - /// - /// Create a button for the given DialogResult - /// - /// - private StylableButton createButton(DialogResult result) - { - StylableButton b = new() - { - Text = _resources.GetString(result.ToString(), CultureInfo.CurrentCulture), - DialogResult = result, - AutoSize = true - }; - Controls.Add(b); - return b; - } - /// - /// the time left before the messageBox closes automatically - /// - private int _timeLeft; - /// - /// time for updating the time left on the default button - /// - private System.Windows.Forms.Timer? _uiUpdate; - /// - /// the timer to close the inputbox - /// - private System.Windows.Forms.Timer? _timeout; - /// - /// configures timeout and timers if needed - /// - /// defines the intervall after which the inputbox is closed automatically - /// defines the to return when the timeout hits - private void handleTimeouts(TimeSpan? timeout, DialogResult timeoutResult) - { - if (timeout is not null) - { - _uiUpdate = new System.Windows.Forms.Timer() - { - Interval = 1000 - }; - //the timeoutResult may not be necessarily in the list of available buttons - Button defaultButton = StylableControls.Buttons.FirstOrDefault(b => b.DialogResult == timeoutResult) ?? StylableControls.Buttons.First(b => b == AcceptButton); - string basicText = defaultButton.Text; - _uiUpdate.Tick += (sender, e) => { _timeLeft--; defaultButton!.Text = $"{basicText} ({_timeLeft}s)"; }; - - _timeout = new System.Windows.Forms.Timer() - { - Interval = (int)timeout.Value.TotalMilliseconds - }; - _timeout.Tick += (sender, e) => { DialogResult = timeoutResult; Close(); }; - - VisibleChanged += (sender, e) => - { - if (Visible) - { - _timeLeft = (int)timeout.Value.TotalSeconds; - _uiUpdate.Start(); - _timeout.Start(); - } - else - { - _uiUpdate.Stop(); - _timeout.Stop(); - } - }; - } - } - /// - /// configures the title bar - /// - /// the caption - /// the icon in the title bar - /// the url to open when the user clicks on the help button - private void handleTitle(string caption, MessageBoxIcon icon, Uri? helpUri) - { - Text = caption; - Icon = icon switch - { - MessageBoxIcon.Error => SystemIcons.Error, - MessageBoxIcon.Exclamation => SystemIcons.Exclamation, - MessageBoxIcon.Information => SystemIcons.Information, - MessageBoxIcon.Question => SystemIcons.Question, - _ => null - }; - if (helpUri is not null) - { - HelpButton = true; - HelpButtonClicked += (sender, e) => Process.Start(new ProcessStartInfo(helpUri.ToString()) { UseShellExecute = true }); - } - } - private int getWindowTitleBarHeight() - { - Rectangle screenRectangle = RectangleToScreen(ClientRectangle); - return screenRectangle.Top - Top; - } - - private static void setMargin(Control? c, int marginLeft, int marginTop) - { - if (c is null) - { - return; - } - - c.Margin = new Padding(marginLeft, marginTop, c.Margin.Right, c.Margin.Top); - } - protected override void Dispose(bool disposing) - { - base.Dispose(disposing); - if (disposing) - { - _uiUpdate?.Dispose(); - _timeout?.Dispose(); - } - } - } -} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs new file mode 100644 index 0000000..ac57943 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -0,0 +1,63 @@ +namespace StylableWinFormsControls +{ + public sealed class StylableInputBox : StylableInteractionBox where T : Control + { + /// + /// returns a builder object to configure the + /// + public static StylableInputBoxBuilder BUILDER => new(); + + /// + /// constructor. not available to others as they should use the + /// + /// the caption + /// the icon in the title bar + /// the prompt text + /// defines which button should be selected by default + /// the url to open when the user clicks on the help button + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + /// the control to input the value + internal StylableInputBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + TimeSpan? timeout, + DialogResult timeoutResult, + T inputControl + ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult) + { + StylableControls.InputControl = handleInput(inputControl); + UpdateSize(); + } + + protected override Point OnUpdateControlSizeMid(int marginLeft, int marginTop, Point currentContentPos) + { + currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; + + if (StylableControls.InputControl is not null) + { + // Margins on CheckBoxes seem to not work directly + StylableControls.InputControl.Left = currentContentPos.X + marginLeft; + StylableControls.InputControl.Top = currentContentPos.Y + marginTop; + currentContentPos.Y += StylableControls.InputControl.Height + 6; + } + + currentContentPos.Y += 16; + return currentContentPos; + } + + /// + /// adds the input control + /// + /// the input control + private T handleInput(T input) + { + Controls.Add(input); + return input; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.de.resx similarity index 100% rename from StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.de.resx rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.de.resx diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.resx similarity index 100% rename from StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBox.resx rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.resx diff --git a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs similarity index 53% rename from StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs index 4b81f44..bee3c08 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InputBoxes/StylableInputBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs @@ -1,61 +1,28 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace StylableWinFormsControls.InputBoxes +namespace StylableWinFormsControls { /// /// the builder to configure the /// - public sealed class StylableInputBoxBuilder + public sealed class StylableInputBoxBuilder : StylableInteractionBoxBuilder { - /// - /// the caption - /// - private string _caption = string.Empty; - /// - /// the icon in the title bar - /// - private MessageBoxIcon _icon = MessageBoxIcon.None; - /// - /// the prompt text - /// - private string _text = string.Empty; - /// - /// defines which button should be selected by default - /// - private MessageBoxDefaultButton _defaultButton = MessageBoxDefaultButton.Button1; - /// - /// the url to open when the user clicks on the help button - /// - private Uri? _helpUri; - /// - /// defines the intervall after which the inputBox is closed automatically - /// - private TimeSpan? _timeout; - /// - /// defines the to return when the timeout hits - /// - private DialogResult _timeoutResult = DialogResult.None; /// /// creates the for text input /// /// the value to show at the start - /// the completely configured but unstyled + /// the completely configured but unstyled public StylableInputBox ForText(string startValue = "") { TextBox textBox = new() { Text = startValue }; - return new StylableInputBox(_caption, _icon, _text, _defaultButton, _helpUri, _timeout, _timeoutResult, textBox); - } + return new StylableInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, textBox); + } + /// /// creates the for text input /// - /// the completely configured but unstyled + /// the completely configured but unstyled public StylableInputBox ForNumericValue(decimal startValue = 0, decimal minValue = decimal.MinValue, decimal maxValue = decimal.MaxValue) { NumericUpDown nup = new() @@ -64,65 +31,65 @@ public StylableInputBox ForNumericValue(decimal startValue = 0, d Maximum = maxValue, Value = startValue }; - return new StylableInputBox(_caption, _icon, _text, _defaultButton, _helpUri, _timeout, _timeoutResult, nup); - } - /// - /// Set the prompt text of the InputBox - /// - /// - public StylableInputBoxBuilder WithText(string text) - { - _text = text ?? string.Empty; - return this; - } - /// - /// Configure the title bar - /// - /// the caption - /// the icon - public StylableInputBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) - { - _caption = caption ?? string.Empty; - _icon = icon; - return this; - } - /// - /// when called, the dialog will close after the given timeout and return the given default result - /// - /// defines the intervall after which the inputbox is closed automatically - /// defines the to return when the timeout hits - public StylableInputBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) - { - _timeout = timeout; - _timeoutResult = timeoutResult; - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableInputBoxBuilder WithHelpButton(string url) - { - if (url is null) - { - throw new ArgumentNullException(nameof(url)); - } - return WithHelpButton(new Uri(url)); - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableInputBoxBuilder WithHelpButton(Uri url) - { - if (url is null) - { - throw new ArgumentNullException(nameof(url)); - } - _helpUri = url; - return this; + return new StylableInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, nup); + } + + + public StylableInputBoxBuilder WithButtons( + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + { + SetButtons(buttons, defaultButton); + return this; + } + /// + /// Set the messagebox text + /// + /// + public StylableInputBoxBuilder WithText(string text) + { + SetText(text); + return this; + } + /// + /// Configure the title bar + /// + /// the caption + /// the icon + public StylableInputBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) + { + SetTitle(caption, icon); + return this; + } + /// + /// when called, the dialog will close after the given timeout and return the given default result + /// + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + public StylableInputBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) + { + SetTimeout(timeout, timeoutResult); + return this; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableInputBoxBuilder WithHelpButton(string url) + { + SetHelpButton(url); + return this; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableInputBoxBuilder WithHelpButton(Uri uri) + { + SetHelpButton(uri); + return this; } } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs similarity index 59% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs index 53b9eef..f061e2f 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs @@ -1,40 +1,46 @@ - -using System.Collections.ObjectModel; - -namespace StylableWinFormsControls -{ - /// - /// container to provide strongly typed access to all controls of the messageBox for styling - /// - public sealed class MessageBoxControls - { - /// - /// the label containing the Text - /// - public StylableLabel Text { get; init; } - /// - /// the optional checkbox - /// - public StylableCheckBox? CheckBox { get; init; } - /// - /// the optional checkbox - /// - public ReadOnlyCollection Buttons { get; init; } - /// - /// constructor - /// - public MessageBoxControls() { } - /// - /// constructor - /// - /// the label containing the Text - /// the optional checkbox - /// a list containing all buttons on the messageBox - public MessageBoxControls(StylableLabel text, StylableCheckBox? checkbox, ReadOnlyCollection buttons) - { - Text = text; - CheckBox = checkbox; - Buttons = buttons ?? new ReadOnlyCollection(new List()); - } - } -} +using System.Collections.ObjectModel; + +namespace StylableWinFormsControls +{ + public class InteractionBoxControls + { + /// + /// the label containing the Text + /// + public StylableLabel? Text { get; internal set; } + /// + /// the optional checkbox + /// + public StylableCheckBox? CheckBox { get; internal set; } + /// + /// the optional checkbox + /// + public ReadOnlyCollection Buttons { get; internal set; } = new(Array.Empty()); + + /// + /// the control for entering a value + /// + public Control InputControl { get; internal set; } + + /// + /// constructor + /// + internal InteractionBoxControls() { } + + /// + /// constructor + /// + /// the label containing the Text + /// the optional checkbox + /// a list containing all buttons on the messageBox + internal InteractionBoxControls( + StylableLabel text, + StylableCheckBox? checkbox, + ReadOnlyCollection buttons) + { + Text = text; + CheckBox = checkbox; + Buttons = buttons ?? new ReadOnlyCollection(new List()); + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs new file mode 100644 index 0000000..7d3009f --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs @@ -0,0 +1,82 @@ +namespace StylableWinFormsControls +{ + /// + /// A stylable version of the + /// + public sealed class StylableMessageBox : StylableInteractionBox + { + /// + /// returns a builder object to configure the + /// + public static StylableMessageBoxBuilder BUILDER => new(); + + /// + /// the checkstate of the checkbox if shown + /// + public CheckState CheckState { get; private set; } = CheckState.Indeterminate; + + /// + /// constructor. not available to others as they should use the + /// + /// the caption + /// the icon in the title bar + /// the messagebox text + /// describes which buttons should be shown to the user + /// defines which button should be selected by default + /// the url to open when the user clicks on the help button + /// the checkbox text to be shown to the user + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + internal StylableMessageBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + string? checkboxText, + TimeSpan? timeout, + DialogResult timeoutResult + ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult) + { + StylableControls.CheckBox = handleCheckBox(checkboxText); + UpdateSize(); + } + + protected override Point OnUpdateControlSizeMid(int marginLeft, int marginTop, Point currentContentPos) + { + currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; + if (StylableControls.CheckBox is not null) + { + // Margins on CheckBoxes seem to not work directly + StylableControls.CheckBox.Left = currentContentPos.X + marginLeft; + StylableControls.CheckBox.Top = currentContentPos.Y + marginTop; + currentContentPos.Y += StylableControls.CheckBox.Height + 6; + } + + currentContentPos.Y += 16; + return currentContentPos; + } + + /// + /// creates the message box content + /// + /// the checkbox text to be shown to the user + private StylableCheckBox? handleCheckBox(string? checkboxText) + { + if (checkboxText is null) + { + return null; + } + StylableCheckBox checkbox = new() + { + Text = checkboxText, + AutoSize = true, + }; + checkbox.CheckStateChanged += (sender, e) => CheckState = checkbox.CheckState; + + Controls.Add(checkbox); + return checkbox; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.de.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.de.resx similarity index 100% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.de.resx rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.de.resx diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.resx similarity index 100% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.resx rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.resx diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs new file mode 100644 index 0000000..d4f72e1 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs @@ -0,0 +1,90 @@ +namespace StylableWinFormsControls +{ + /// + /// the builder to configure the + /// + public sealed class StylableMessageBoxBuilder : StylableInteractionBoxBuilder + { + /// + /// the checkbox text to be shown to the user + /// + private string? _checkboxText; + + /// + /// creates the + /// + /// the completely configured but unstyled + public StylableMessageBox Build() + { + return new StylableMessageBox(Caption, Icon, Text, Buttons, DefaultButton, + HelpUri, _checkboxText, Timeout, TimeoutResult); + } + + public StylableMessageBoxBuilder WithButtons( + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + { + SetButtons(buttons, defaultButton); + return this; + } + /// + /// Set the messagebox text + /// + /// + public StylableMessageBoxBuilder WithText(string text) + { + SetText(text); + return this; + } + /// + /// Configure the title bar + /// + /// the caption + /// the icon + public StylableMessageBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) + { + SetTitle(caption, icon); + return this; + } + /// + /// when called, the dialog will close after the given timeout and return the given default result + /// + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + public StylableMessageBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) + { + SetTimeout(timeout, timeoutResult); + return this; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableMessageBoxBuilder WithHelpButton(string url) + { + SetHelpButton(url); + return this; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + public StylableMessageBoxBuilder WithHelpButton(Uri uri) + { + SetHelpButton(uri); + return this; + } + + /// + /// This adds a to the form. use to get the check state + /// + /// the text to be shown to the user + public StylableMessageBoxBuilder WithCheckBox(string checkBoxText) + { + _checkboxText = checkBoxText ?? string.Empty; + return this; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs similarity index 82% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs index dfb91a9..fa17a8f 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs @@ -2,41 +2,36 @@ using System.Diagnostics; using System.Globalization; using System.Resources; - using StylableWinFormsControls.Extensions; - + namespace StylableWinFormsControls { /// - /// A stylable version of the - /// - public sealed class StylableMessageBox : Form + /// A stylable base version of informational boxes with interaction possibilities + /// + /// + public class StylableInteractionBox : Form { /// /// additional form width /// - public const int BORDER_WIDTH = 20; + public const int BORDER_WIDTH = 20; + /// /// additional form height /// - public const int BORDER_HEIGHT = 10; - /// - /// returns a builder object to configure the - /// - public static StylableMessageBoxBuilder BUILDER => new(); + public const int BORDER_HEIGHT = 10; + /// /// resource manager used to access localized texts /// - private static ResourceManager _resources = new(typeof(StylableMessageBox)); + private static ResourceManager _resources = new(typeof(StylableInteractionBox)); - /// - /// the checkstate of the checkbox if shown - /// - public CheckState CheckState { get; private set; } = CheckState.Indeterminate; /// /// contains the stylable controls for easier access than iterating over Controls /// - public MessageBoxControls StylableControls { get; } + public InteractionBoxControls StylableControls { get; } + /// /// constructor. not available to others as they should use the /// @@ -46,25 +41,32 @@ public sealed class StylableMessageBox : Form /// describes which buttons should be shown to the user /// defines which button should be selected by default /// the url to open when the user clicks on the help button - /// the checkbox text to be shown to the user /// defines the intervall after which the messagebox is closed automatically /// defines the to return when the timeout hits - internal StylableMessageBox(string caption, MessageBoxIcon icon, string text, MessageBoxButtons buttons, MessageBoxDefaultButton defaultButton, Uri? helpUri, string? checkboxText, TimeSpan? timeout, DialogResult timeoutResult) + internal StylableInteractionBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + TimeSpan? timeout, + DialogResult timeoutResult) { StartPosition = FormStartPosition.CenterScreen; FormBorderStyle = FormBorderStyle.FixedDialog; MinimizeBox = false; MaximizeBox = false; handleTitle(caption, icon, helpUri); - StylableControls = new MessageBoxControls() + StylableControls = new InteractionBoxControls() { Text = handleText(text), - CheckBox = handleCheckBox(checkboxText), Buttons = handleButtons(buttons, defaultButton) - }; + }; + OnAfterSetStylableControls(); handleTimeouts(timeout, timeoutResult); - UpdateSize(); - } + } + /// /// resize the form to fit the content /// @@ -88,16 +90,7 @@ public void UpdateSize(bool updateControlSize = true) StylableControls.Text.Top = currentContentPos.Y; } - currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; - if (StylableControls.CheckBox is not null) - { - // Margins on CheckBoxes seem to not work directly - StylableControls.CheckBox.Left = currentContentPos.X + marginLeft; - StylableControls.CheckBox.Top = currentContentPos.Y + marginTop; - currentContentPos.Y += StylableControls.CheckBox.Height + 6; - } - - currentContentPos.Y += 16; + currentContentPos = OnUpdateControlSizeMid(marginLeft, marginTop, currentContentPos); foreach (StylableButton sb in StylableControls.Buttons) { @@ -113,6 +106,27 @@ public void UpdateSize(bool updateControlSize = true) Height = (from c in Controls.Cast() select c.Top + c.Height + c.Margin.Top + c.Margin.Bottom + BORDER_HEIGHT + titleBarHeight).Max(); } + /// + /// Gets called within between the text area and the bottom area.
+ /// Can be used to add own elements to the control. + ///
+ /// Currently calculated highest Margin.Left value of all controls + /// Currently calculated highest Margin.Top value of all controls + /// Position at which the calculation of elements currently is. + /// Returns the position the calculation of further elements should continue + protected virtual Point OnUpdateControlSizeMid(int marginLeft, int marginTop, Point currentContentPos) + { + return currentContentPos; + } + + /// + /// Gets called after the object has been initialized. + /// + protected virtual void OnAfterSetStylableControls() + { + + } + /// /// creates the message box content /// @@ -128,26 +142,6 @@ private StylableLabel handleText(string text) return label; } /// - /// creates the message box content - /// - /// the checkbox text to be shown to the user - private StylableCheckBox? handleCheckBox(string? checkboxText) - { - if (checkboxText is null) - { - return null; - } - StylableCheckBox checkbox = new() - { - Text = checkboxText, - AutoSize = true, - }; - checkbox.CheckStateChanged += (sender, e) => CheckState = checkbox.CheckState; - - Controls.Add(checkbox); - return checkbox; - } - /// /// Create a button for the given DialogResult /// /// diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.de.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.de.resx new file mode 100644 index 0000000..12c6f09 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.de.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Abbrechen + + + Abbrechen + + + Fortsetzen + + + Ignorieren + + + Nein + + + OK + + + Erneut Versuchen + + + Ja + + \ No newline at end of file diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.resx new file mode 100644 index 0000000..8c360f7 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.resx @@ -0,0 +1,144 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Abort + + + Cancel + + + Continue + + + Ignore + + + No + + + OK + + + Retry + + + Yes + + \ No newline at end of file diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs similarity index 52% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBoxBuilder.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs index 5fa1363..f356e47 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs @@ -1,134 +1,109 @@ - - -namespace StylableWinFormsControls -{ - /// - /// the builder to configure the - /// - public sealed class StylableMessageBoxBuilder - { - /// - /// the caption - /// - private string _caption = string.Empty; - /// - /// the icon in the title bar - /// - private MessageBoxIcon _icon = MessageBoxIcon.None; - /// - /// the messagebox text - /// - private string _text = string.Empty; - /// - /// describes which buttons should be shown to the user - /// - private MessageBoxButtons _buttons = MessageBoxButtons.OK; - /// - /// defines which button should be selected by default - /// - private MessageBoxDefaultButton _defaultButton = MessageBoxDefaultButton.Button1; - /// - /// the url to open when the user clicks on the help button - /// - private Uri? _helpUri; - /// - /// the checkbox text to be shown to the user - /// - private string? _checkboxText; - /// - /// defines the intervall after which the messagebox is closed automatically - /// - private TimeSpan? _timeout; - /// - /// defines the to return when the timeout hits - /// - private DialogResult _timeoutResult = DialogResult.None; - /// - /// creates the - /// - /// the completely configured but unstyled - public StylableMessageBox Build() - { - return new StylableMessageBox(_caption, _icon, _text, _buttons, _defaultButton, - _helpUri, _checkboxText, _timeout, _timeoutResult); - } - /// - /// This adds a to the form. use to get the check state - /// - /// the text to be shown to the user - public StylableMessageBoxBuilder WithCheckBox(string checkBoxText) - { - _checkboxText = checkBoxText ?? string.Empty; - return this; - } - /// - /// configures which buttons to show and which button should be the default button - /// - /// describes which buttons should be shown to the user - /// defines which button should be selected by default - public StylableMessageBoxBuilder WithButtons(MessageBoxButtons buttons, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) - { - _buttons = buttons; - _defaultButton = defaultButton; - return this; - } - /// - /// Set the messagebox text - /// - /// - public StylableMessageBoxBuilder WithText(string text) - { - _text = text ?? string.Empty; - return this; - } - /// - /// Configure the title bar - /// - /// the caption - /// the icon - public StylableMessageBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) - { - _caption = caption ?? string.Empty; - _icon = icon; - return this; - } - /// - /// when called, the dialog will close after the given timeout and return the given default result - /// - /// defines the intervall after which the messagebox is closed automatically - /// defines the to return when the timeout hits - public StylableMessageBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) - { - _timeout = timeout; - _timeoutResult = timeoutResult; - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableMessageBoxBuilder WithHelpButton(string url) - { - if (url is null) - { - throw new ArgumentNullException(nameof(url)); - } - return WithHelpButton(new Uri(url)); - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableMessageBoxBuilder WithHelpButton(Uri url) - { - if (url is null) - { - throw new ArgumentNullException(nameof(url)); - } - _helpUri = url; - return this; - } - } -} +namespace StylableWinFormsControls +{ + /// + /// the builder to configure all informational boxes Set interaction possibilities + /// + /// + public abstract class StylableInteractionBoxBuilder + { + /// + /// the caption + /// + internal string Caption = string.Empty; + /// + /// the icon in the title bar + /// + internal MessageBoxIcon Icon = MessageBoxIcon.None; + /// + /// the messagebox text + /// + internal string Text = string.Empty; + /// + /// describes which buttons should be shown to the user + /// + internal MessageBoxButtons Buttons = MessageBoxButtons.OK; + /// + /// defines which button should be selected by default + /// + internal MessageBoxDefaultButton DefaultButton = MessageBoxDefaultButton.Button1; + /// + /// the url to open when the user clicks on the help button + /// + internal Uri? HelpUri; + /// + /// defines the intervall after which the messagebox is closed automatically + /// + internal TimeSpan? Timeout; + /// + /// defines the to return when the timeout hits + /// + internal DialogResult TimeoutResult = DialogResult.None; + + /// + /// configures which buttons to show and which button should be the default button + /// + /// describes which buttons should be shown to the user + /// defines which button should be selected by default + protected void SetButtons( + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + { + Buttons = buttons; + DefaultButton = defaultButton; + } + /// + /// Set the messagebox text + /// + /// + protected void SetText(string text) + { + Text = text ?? string.Empty; + } + /// + /// Configure the title bar + /// + /// the caption + /// the icon + protected void SetTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) + { + Caption = caption ?? string.Empty; + Icon = icon; + } + /// + /// when called, the dialog will close after the given timeout and return the given default result + /// + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + protected void SetTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) + { + Timeout = timeout; + TimeoutResult = timeoutResult; + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + protected void SetHelpButton(string url) + { + if (url is null) + { + throw new ArgumentNullException(nameof(url)); + } + SetHelpButton(new Uri(url)); + } + /// + /// Shows the help button in the title bar + /// + /// the url to open when the user clicks on the help button + /// url must be non-null + protected void SetHelpButton(Uri url) + { + if (url is null) + { + throw new ArgumentNullException(nameof(url)); + } + HelpUri = url; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj b/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj index 444ee8ff918bdf49aa6d899e626af17783cf8861..0a65ae124f54a46545081b2b06b11b1088278ff9 100644 GIT binary patch delta 143 zcmX>ny-aq)Hr~ksTzd6349*Ps47m&i44Di$452*d>P}=x0-J$PhaS+3VxXxC4EhXq47`)Od7S~# C@f}qF delta 11 ScmZ1`dro@8Hr~m7d=da1 Date: Sun, 25 Feb 2024 00:19:09 +0100 Subject: [PATCH 4/8] Implemented easier way for fetching values --- .../FrmDefault.Designer.cs | 47 ++++++++++--------- .../FrmDefault.cs | 20 ++++++-- .../InputBoxes/StylableInputBox.cs | 24 +++++++++- 3 files changed, 62 insertions(+), 29 deletions(-) diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs index c1945dd..61e61ee 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs @@ -30,11 +30,11 @@ protected override void Dispose(bool disposing) /// private void InitializeComponent() { - ListViewItem listViewItem6 = new ListViewItem("Content"); - ListViewItem listViewItem7 = new ListViewItem("Content"); - ListViewItem listViewItem8 = new ListViewItem(new string[] { "Content", "Content" }, -1); - ListViewItem listViewItem9 = new ListViewItem("Content"); - ListViewItem listViewItem10 = new ListViewItem("Content"); + ListViewItem listViewItem1 = new ListViewItem("Content"); + ListViewItem listViewItem2 = new ListViewItem("Content"); + ListViewItem listViewItem3 = new ListViewItem(new string[] { "Content", "Content" }, -1); + ListViewItem listViewItem4 = new ListViewItem("Content"); + ListViewItem listViewItem5 = new ListViewItem("Content"); stylableButton1 = new StylableButton(); stylableCheckBox1 = new StylableCheckBox(); stylableComboBox1 = new StylableComboBox(); @@ -56,13 +56,13 @@ private void InitializeComponent() gb_stylabletabcontrol = new StylableGroupBox(); gb_stylablelistview = new StylableGroupBox(); gb_stylablebutton = new StylableGroupBox(); + stylableButton2 = new StylableButton(); gb_stylablecheckbox = new StylableGroupBox(); gb_stylableComboBox = new StylableGroupBox(); gb_stylableDateTimePicker = new StylableGroupBox(); gb_stylableDataGridView = new StylableGroupBox(); gb_stylableLabel = new StylableGroupBox(); gb_stylableTextBox = new StylableGroupBox(); - stylableButton2 = new StylableButton(); ((System.ComponentModel.ISupportInitialize)stylableDataGridView1).BeginInit(); stylableTabControl1.SuspendLayout(); gb_stylabletabcontrol.SuspendLayout(); @@ -90,6 +90,7 @@ private void InitializeComponent() stylableButton1.TabIndex = 0; stylableButton1.Text = "This is content"; stylableButton1.UseVisualStyleBackColor = true; + stylableButton1.Click += stylableButton1_Click; // // stylableCheckBox1 // @@ -178,7 +179,7 @@ private void InitializeComponent() stylableListView1.Columns.AddRange(new ColumnHeader[] { columnHeader1, columnHeader2 }); stylableListView1.GroupHeaderBackColor = Color.LightGray; stylableListView1.GroupHeaderForeColor = Color.Black; - stylableListView1.Items.AddRange(new ListViewItem[] { listViewItem6, listViewItem7, listViewItem8, listViewItem9, listViewItem10 }); + stylableListView1.Items.AddRange(new ListViewItem[] { listViewItem1, listViewItem2, listViewItem3, listViewItem4, listViewItem5 }); stylableListView1.Location = new Point(6, 18); stylableListView1.Name = "stylableListView1"; stylableListView1.SelectedItemBackColor = Color.LightGray; @@ -294,6 +295,22 @@ private void InitializeComponent() gb_stylablebutton.TabStop = false; gb_stylablebutton.Text = "StylableButton"; // + // stylableButton2 + // + stylableButton2.BorderColor = Color.Black; + stylableButton2.DisabledBackColor = Color.Gray; + stylableButton2.DisabledForeColor = Color.Black; + stylableButton2.EnabledBackColor = Color.White; + stylableButton2.EnabledForeColor = Color.Black; + stylableButton2.EnabledHoverColor = Color.LightGray; + stylableButton2.Location = new Point(111, 22); + stylableButton2.Name = "stylableButton2"; + stylableButton2.Size = new Size(85, 23); + stylableButton2.TabIndex = 1; + stylableButton2.Text = "InputBox"; + stylableButton2.UseVisualStyleBackColor = true; + stylableButton2.Click += stylableButton2_Click; + // // gb_stylablecheckbox // gb_stylablecheckbox.Controls.Add(stylableCheckBox1); @@ -366,22 +383,6 @@ private void InitializeComponent() gb_stylableTextBox.TabStop = false; gb_stylableTextBox.Text = "StylableTextBox"; // - // stylableButton2 - // - stylableButton2.BorderColor = Color.Black; - stylableButton2.DisabledBackColor = Color.Gray; - stylableButton2.DisabledForeColor = Color.Black; - stylableButton2.EnabledBackColor = Color.White; - stylableButton2.EnabledForeColor = Color.Black; - stylableButton2.EnabledHoverColor = Color.LightGray; - stylableButton2.Location = new Point(111, 22); - stylableButton2.Name = "stylableButton2"; - stylableButton2.Size = new Size(85, 23); - stylableButton2.TabIndex = 1; - stylableButton2.Text = "InputBox"; - stylableButton2.UseVisualStyleBackColor = true; - stylableButton2.Click += stylableButton2_Click; - // // FrmDefault // AutoScaleDimensions = new SizeF(7F, 15F); diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs index 83a722e..5cb4514 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs @@ -9,7 +9,7 @@ public FrmDefault() private void stylableButton1_Click(object sender, EventArgs e) { - StylableMessageBox mBox = StylableMessageBox.BUILDER + StylableMessageBox messageBox = StylableMessageBox.BUILDER .WithTitle("This is a text", MessageBoxIcon.Information) .WithText("This is an example of a stylable MessageBox") .WithButtons(MessageBoxButtons.YesNoCancel) @@ -17,18 +17,28 @@ private void stylableButton1_Click(object sender, EventArgs e) .WithHelpButton(new Uri("https://github.com/Assorted-Development/winforms-stylable-controls")) .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) .Build(); - mBox.ShowDialog(); + messageBox.ShowDialog(); } private void stylableButton2_Click(object sender, EventArgs e) { - StylableInputBox iBox = StylableInputBox.BUILDER - .WithTitle("Numeric Test", MessageBoxIcon.Information) + StylableInputBox inputBox = StylableInputBox.BUILDER + .WithTitle("Numeric Test", MessageBoxIcon.Question) .WithText("Please enter a random number between -100 and 100") + .WithButtons(MessageBoxButtons.OKCancel) .WithHelpButton(new Uri("https://github.com/Assorted-Development/winforms-stylable-controls")) .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) .ForNumericValue(0, -100, 100); - iBox.ShowDialog(); + + if (inputBox.ShowDialog() == DialogResult.OK) + { + StylableMessageBox mBox = StylableMessageBox.BUILDER + .WithTitle("Result value", MessageBoxIcon.Information) + .WithText($"You entered the following value: {inputBox.Value}") + .WithButtons(MessageBoxButtons.OK) + .Build(); + mBox.ShowDialog(); + } } } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs index ac57943..3b50f0a 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -3,9 +3,31 @@ namespace StylableWinFormsControls public sealed class StylableInputBox : StylableInteractionBox where T : Control { /// - /// returns a builder object to configure the + /// Returns a builder object to configure the /// public static StylableInputBoxBuilder BUILDER => new(); + + /// + /// Returns the value of the input control used with this instance.
+ /// Return type: for | + /// for . + ///
+ /// May be null if no input control has been specified (yet). + /// + /// Throws if hasn't been implemented for this property. + /// + public object Value + { + get + { + return StylableControls.InputControl switch + { + NumericUpDown numUpDown => numUpDown.Value, + TextBox textBox => textBox.Text, + _ => throw new NotSupportedException("The type of this input field has not been prepared for fetching values yet.") + }; + } + } /// /// constructor. not available to others as they should use the From 3cbf8a540d731a27cfbf1da3cc4fea680c0cf5cb Mon Sep 17 00:00:00 2001 From: Nockiro Date: Sun, 25 Feb 2024 00:29:03 +0100 Subject: [PATCH 5/8] Stretch input control to full width --- .../InteractionBoxes/InputBoxes/StylableInputBox.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs index 3b50f0a..c7c1571 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -54,6 +54,7 @@ T inputControl { StylableControls.InputControl = handleInput(inputControl); UpdateSize(); + stretchInputControlWidth(inputControl); } protected override Point OnUpdateControlSizeMid(int marginLeft, int marginTop, Point currentContentPos) @@ -71,6 +72,17 @@ protected override Point OnUpdateControlSizeMid(int marginLeft, int marginTop, P currentContentPos.Y += 16; return currentContentPos; } + + /// + /// Sets width of the input control to full length of the containing window (with margin). + /// + /// Input Control to stretch + private void stretchInputControlWidth(Control inputControl) + { + // Set width to complete width, but leave as much space to the right of the control as to the left. + inputControl.Width = ClientRectangle.Width - inputControl.Left - inputControl.Margin.Left - inputControl.Margin.Right; + UpdateSize(); + } /// /// adds the input control From 7d72a9eef110d5414245adf323a4c27755807645 Mon Sep 17 00:00:00 2001 From: Nockiro Date: Sun, 25 Feb 2024 00:36:45 +0100 Subject: [PATCH 6/8] Adjusted documentation --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 1658013..eecd902 100644 --- a/README.md +++ b/README.md @@ -132,8 +132,8 @@ At last, you can show the dialog using `mBox.ShowDialog()` **Note:** If you change the size on the controls (e.g. increase the font size), please call `UpdateSize()` to update the UI to the new settings. Otherwise, the Ui may look weird. ### Interaction.InputBox => StylableInputBox -With the `StylableInputBox`, you can create forms similar to VB.NETs `Interaction.InputBox` but the handling is a bit different as we allow you to style the form -before showing. +With the `StylableInputBox`, you can create forms similar to VB.NETs `Interaction.InputBox` but the handling is a bit different (as it's practically a slightly different `StylableMessageBox`). +Therefore, we allow you to style and adjust the form before you show it. Let's create an input box first: ```csharp @@ -144,9 +144,9 @@ StylableInputBox iBox = StylableInputBox.BUILDER .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) .ForNumericValue(0, -100, 100); ``` -This will create an input box for numeric values (currently, we support text and numeric) with a title and a message and two buttons: Okay, Cancel +This will create an input box for numeric values (currently, we support text via `TextBox` and numeric input via `NumericUpDown`). Now, let's style the form as we want to: `iBox.StylableControls.Text.ForeColor = Color.Red;` -At last, you can show the dialog using `iBox.ShowDialog()` +At last, you can show the dialog using `iBox.ShowDialog()` and either use its `DialogResult` or `iBox.Value` to get the input entered by the user. **Note:** If you change the size on the controls (e.g. increase the font size), please call `UpdateSize()` to update the UI to the new settings. Otherwise, the Ui may look weird. From f7a7453872c089842216088e0edc1068acdb7cd0 Mon Sep 17 00:00:00 2001 From: "13997737+wolframhaussig@users.noreply.github.com" <13997737+wolframhaussig@users.noreply.github.com> Date: Sun, 25 Feb 2024 07:11:12 +0100 Subject: [PATCH 7/8] minor improvements - make base class abstract - removed duplicate code in Builders - provide typesafe access to the input value - removed usage of typed parameters for the user - reuse InputControl for Checkbox from MessageBox --- README.md | 2 +- .../FrmDefault.cs | 2 +- .../InputBoxes/StylableInputBox.cs | 35 ++++---- .../InputBoxes/StylableInputBoxBuilder.cs | 84 ++----------------- .../InputBoxes/StylableNumericInputBox.cs | 42 ++++++++++ .../InputBoxes/StylableTextInputBox.cs | 36 ++++++++ .../MessageBoxes/StylableMessageBoxBuilder.cs | 59 +------------ .../StylableInteractionBox.cs | 2 +- .../StylableInteractionBoxBuilder.cs | 33 +++++--- 9 files changed, 129 insertions(+), 166 deletions(-) create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs create mode 100644 StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs diff --git a/README.md b/README.md index eecd902..ed4e226 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ Therefore, we allow you to style and adjust the form before you show it. Let's create an input box first: ```csharp -StylableInputBox iBox = StylableInputBox.BUILDER +StylableNumericInputBox iBox = StylableNumericInputBox.BUILDER .WithTitle("Numeric Test", MessageBoxIcon.Information) .WithText("Please enter a random number between -100 and 100") .WithHelpButton(new Uri("https://github.com/Assorted-Development/winforms-stylable-controls")) diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs index 5cb4514..ada1664 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.cs @@ -22,7 +22,7 @@ private void stylableButton1_Click(object sender, EventArgs e) private void stylableButton2_Click(object sender, EventArgs e) { - StylableInputBox inputBox = StylableInputBox.BUILDER + StylableNumericInputBox inputBox = StylableNumericInputBox.BUILDER .WithTitle("Numeric Test", MessageBoxIcon.Question) .WithText("Please enter a random number between -100 and 100") .WithButtons(MessageBoxButtons.OKCancel) diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs index c7c1571..d06d7a5 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -1,11 +1,20 @@ namespace StylableWinFormsControls -{ - public sealed class StylableInputBox : StylableInteractionBox where T : Control +{ + /// + /// A stylable version of VB.NETs Interaction.InputBox + /// + /// the type of the input control + /// the type of the value returned from the input control + public abstract class StylableInputBox : StylableInteractionBox where T : Control { /// /// Returns a builder object to configure the /// public static StylableInputBoxBuilder BUILDER => new(); + /// + /// accessor to return the current value + /// + private Func _accessor; /// /// Returns the value of the input control used with this instance.
@@ -16,18 +25,7 @@ public sealed class StylableInputBox : StylableInteractionBox where T : Contr /// /// Throws if hasn't been implemented for this property. /// - public object Value - { - get - { - return StylableControls.InputControl switch - { - NumericUpDown numUpDown => numUpDown.Value, - TextBox textBox => textBox.Text, - _ => throw new NotSupportedException("The type of this input field has not been prepared for fetching values yet.") - }; - } - } + public U Value => _accessor((T)StylableControls.InputControl); /// /// constructor. not available to others as they should use the @@ -39,8 +37,9 @@ public object Value /// the url to open when the user clicks on the help button /// defines the intervall after which the messagebox is closed automatically /// defines the to return when the timeout hits - /// the control to input the value - internal StylableInputBox( + /// the control to input the value + /// accessor to read the current value from the control + protected StylableInputBox( string caption, MessageBoxIcon icon, string text, @@ -49,9 +48,11 @@ internal StylableInputBox( Uri? helpUri, TimeSpan? timeout, DialogResult timeoutResult, - T inputControl + T inputControl, + Func accessor ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult) { + _accessor = accessor; StylableControls.InputControl = handleInput(inputControl); UpdateSize(); stretchInputControlWidth(inputControl); diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs index bee3c08..77d9f35 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs @@ -1,95 +1,29 @@ + namespace StylableWinFormsControls { /// /// the builder to configure the /// - public sealed class StylableInputBoxBuilder : StylableInteractionBoxBuilder + public sealed class StylableInputBoxBuilder : StylableInteractionBoxBuilder { /// /// creates the for text input /// /// the value to show at the start /// the completely configured but unstyled - public StylableInputBox ForText(string startValue = "") + public StylableTextInputBox ForText(string startValue = "") { - TextBox textBox = new() - { - Text = startValue - }; - return new StylableInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, textBox); + return new StylableTextInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, startValue); } /// - /// creates the for text input + /// creates the for numeric input /// - /// the completely configured but unstyled - public StylableInputBox ForNumericValue(decimal startValue = 0, decimal minValue = decimal.MinValue, decimal maxValue = decimal.MaxValue) + /// the completely configured but unstyled + public StylableNumericInputBox ForNumericValue(decimal startValue = 0, decimal minValue = decimal.MinValue, decimal maxValue = decimal.MaxValue) { - NumericUpDown nup = new() - { - Minimum = minValue, - Maximum = maxValue, - Value = startValue - }; - return new StylableInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, nup); - } - - - public StylableInputBoxBuilder WithButtons( - MessageBoxButtons buttons, - MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) - { - SetButtons(buttons, defaultButton); - return this; + return new StylableNumericInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, startValue, minValue, maxValue); } - /// - /// Set the messagebox text - /// - /// - public StylableInputBoxBuilder WithText(string text) - { - SetText(text); - return this; - } - /// - /// Configure the title bar - /// - /// the caption - /// the icon - public StylableInputBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) - { - SetTitle(caption, icon); - return this; - } - /// - /// when called, the dialog will close after the given timeout and return the given default result - /// - /// defines the intervall after which the messagebox is closed automatically - /// defines the to return when the timeout hits - public StylableInputBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) - { - SetTimeout(timeout, timeoutResult); - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableInputBoxBuilder WithHelpButton(string url) - { - SetHelpButton(url); - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableInputBoxBuilder WithHelpButton(Uri uri) - { - SetHelpButton(uri); - return this; - } + } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs new file mode 100644 index 0000000..ac12fed --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs @@ -0,0 +1,42 @@ + +namespace StylableWinFormsControls +{ + /// + /// A stylable version of VB.NETs Interaction.InputBox for numbers + /// + public class StylableNumericInputBox : StylableInputBox + { + /// + /// constructor. not available to others as they should use the + /// + /// the caption + /// the icon in the title bar + /// the prompt text + /// defines which button should be selected by default + /// the url to open when the user clicks on the help button + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + /// + /// + /// + internal StylableNumericInputBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + TimeSpan? timeout, + DialogResult timeoutResult, + decimal startValue, + decimal minValue, + decimal maxValue + ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult, new NumericUpDown(), nup => nup.Value) + { + NumericUpDown nup = (NumericUpDown) StylableControls.InputControl; + nup.Minimum = minValue; + nup.Maximum = maxValue; + nup.Value = startValue; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs new file mode 100644 index 0000000..92d0b19 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs @@ -0,0 +1,36 @@ + +namespace StylableWinFormsControls +{ + /// + /// A stylable version of VB.NETs Interaction.InputBox for numbers + /// + public class StylableTextInputBox : StylableInputBox + { + /// + /// constructor. not available to others as they should use the + /// + /// the caption + /// the icon in the title bar + /// the prompt text + /// defines which button should be selected by default + /// the url to open when the user clicks on the help button + /// defines the intervall after which the messagebox is closed automatically + /// defines the to return when the timeout hits + /// + internal StylableTextInputBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + TimeSpan? timeout, + DialogResult timeoutResult, + string startValue + ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult, new TextBox(), text => text.Text) + { + TextBox nup = (TextBox)StylableControls.InputControl; + nup.Text = startValue; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs index d4f72e1..72a1eda 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs @@ -3,7 +3,7 @@ namespace StylableWinFormsControls /// /// the builder to configure the /// - public sealed class StylableMessageBoxBuilder : StylableInteractionBoxBuilder + public sealed class StylableMessageBoxBuilder : StylableInteractionBoxBuilder { /// /// the checkbox text to be shown to the user @@ -19,63 +19,6 @@ public StylableMessageBox Build() return new StylableMessageBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, _checkboxText, Timeout, TimeoutResult); } - - public StylableMessageBoxBuilder WithButtons( - MessageBoxButtons buttons, - MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) - { - SetButtons(buttons, defaultButton); - return this; - } - /// - /// Set the messagebox text - /// - /// - public StylableMessageBoxBuilder WithText(string text) - { - SetText(text); - return this; - } - /// - /// Configure the title bar - /// - /// the caption - /// the icon - public StylableMessageBoxBuilder WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) - { - SetTitle(caption, icon); - return this; - } - /// - /// when called, the dialog will close after the given timeout and return the given default result - /// - /// defines the intervall after which the messagebox is closed automatically - /// defines the to return when the timeout hits - public StylableMessageBoxBuilder WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) - { - SetTimeout(timeout, timeoutResult); - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableMessageBoxBuilder WithHelpButton(string url) - { - SetHelpButton(url); - return this; - } - /// - /// Shows the help button in the title bar - /// - /// the url to open when the user clicks on the help button - /// url must be non-null - public StylableMessageBoxBuilder WithHelpButton(Uri uri) - { - SetHelpButton(uri); - return this; - } /// /// This adds a to the form. use to get the check state diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs index fa17a8f..d197cec 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs @@ -10,7 +10,7 @@ namespace StylableWinFormsControls /// A stylable base version of informational boxes with interaction possibilities /// /// - public class StylableInteractionBox : Form + public abstract class StylableInteractionBox : Form { /// /// additional form width diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs index f356e47..7dd3a73 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs @@ -1,10 +1,12 @@ +using System.Security.Policy; + namespace StylableWinFormsControls { /// /// the builder to configure all informational boxes Set interaction possibilities /// /// - public abstract class StylableInteractionBoxBuilder + public abstract class StylableInteractionBoxBuilder where T : StylableInteractionBoxBuilder { /// /// the caption @@ -44,66 +46,71 @@ public abstract class StylableInteractionBoxBuilder /// /// describes which buttons should be shown to the user /// defines which button should be selected by default - protected void SetButtons( + public T WithButtons( MessageBoxButtons buttons, MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) { Buttons = buttons; DefaultButton = defaultButton; + return (T)(object)this; } /// - /// Set the messagebox text + /// Set the messagebox/prompt text /// /// - protected void SetText(string text) + public T WithText(string text) { Text = text ?? string.Empty; + return (T)(object)this; } /// /// Configure the title bar /// /// the caption /// the icon - protected void SetTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) + public T WithTitle(string caption = "", MessageBoxIcon icon = MessageBoxIcon.None) { Caption = caption ?? string.Empty; Icon = icon; + return (T)(object)this; } /// /// when called, the dialog will close after the given timeout and return the given default result /// /// defines the intervall after which the messagebox is closed automatically /// defines the to return when the timeout hits - protected void SetTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) + public T WithTimeout(TimeSpan timeout, DialogResult timeoutResult = DialogResult.Cancel) { Timeout = timeout; TimeoutResult = timeoutResult; + return (T)(object)this; } /// /// Shows the help button in the title bar /// /// the url to open when the user clicks on the help button /// url must be non-null - protected void SetHelpButton(string url) + public T WithHelpButton(string url) { if (url is null) { throw new ArgumentNullException(nameof(url)); } - SetHelpButton(new Uri(url)); + return WithHelpButton(new Uri(url)); } /// /// Shows the help button in the title bar /// - /// the url to open when the user clicks on the help button + /// the url to open when the user clicks on the help button /// url must be non-null - protected void SetHelpButton(Uri url) + public T WithHelpButton(Uri uri) { - if (url is null) + if (uri is null) { - throw new ArgumentNullException(nameof(url)); + throw new ArgumentNullException(nameof(uri)); } - HelpUri = url; + HelpUri = uri; + return (T)(object)this; } } } From f4fd186a0976a2e1d9552e99c46aa9d874b7bdbd Mon Sep 17 00:00:00 2001 From: "13997737+wolframhaussig@users.noreply.github.com" <13997737+wolframhaussig@users.noreply.github.com> Date: Sun, 25 Feb 2024 09:12:05 +0100 Subject: [PATCH 8/8] strongly typed InteractionBoxControls --- .../InputBoxes/StylableInputBox.cs | 2 +- .../InputBoxes/StylableNumericInputBox.cs | 8 ++++---- .../InputBoxes/StylableTextInputBox.cs | 3 +-- .../InteractionBoxes/InteractionBoxControls.cs | 14 +++++--------- .../MessageBoxes/StylableMessageBox.cs | 12 ++++++------ .../InteractionBoxes/StylableInteractionBox.cs | 8 ++++---- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs index d06d7a5..d9f9d83 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -5,7 +5,7 @@ namespace StylableWinFormsControls /// /// the type of the input control /// the type of the value returned from the input control - public abstract class StylableInputBox : StylableInteractionBox where T : Control + public abstract class StylableInputBox : StylableInteractionBox where T : Control { /// /// Returns a builder object to configure the diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs index ac12fed..bd1c897 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs @@ -33,10 +33,10 @@ internal StylableNumericInputBox( decimal maxValue ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult, new NumericUpDown(), nup => nup.Value) { - NumericUpDown nup = (NumericUpDown) StylableControls.InputControl; - nup.Minimum = minValue; - nup.Maximum = maxValue; - nup.Value = startValue; + + StylableControls.InputControl!.Minimum = minValue; + StylableControls.InputControl!.Maximum = maxValue; + StylableControls.InputControl!.Value = startValue; } } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs index 92d0b19..7c699e6 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs @@ -29,8 +29,7 @@ internal StylableTextInputBox( string startValue ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult, new TextBox(), text => text.Text) { - TextBox nup = (TextBox)StylableControls.InputControl; - nup.Text = startValue; + StylableControls.InputControl!.Text = startValue; } } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs index f061e2f..3c626bc 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs @@ -2,7 +2,7 @@ namespace StylableWinFormsControls { - public class InteractionBoxControls + public class InteractionBoxControls where T : Control { /// /// the label containing the Text @@ -11,16 +11,12 @@ public class InteractionBoxControls /// /// the optional checkbox /// - public StylableCheckBox? CheckBox { get; internal set; } - /// - /// the optional checkbox - /// public ReadOnlyCollection Buttons { get; internal set; } = new(Array.Empty()); /// /// the control for entering a value /// - public Control InputControl { get; internal set; } + public T? InputControl { get; internal set; } /// /// constructor @@ -31,15 +27,15 @@ internal InteractionBoxControls() { } /// constructor /// /// the label containing the Text - /// the optional checkbox + /// the optional input control /// a list containing all buttons on the messageBox internal InteractionBoxControls( StylableLabel text, - StylableCheckBox? checkbox, + T? inputControl, ReadOnlyCollection buttons) { Text = text; - CheckBox = checkbox; + InputControl = inputControl; Buttons = buttons ?? new ReadOnlyCollection(new List()); } } diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs index 7d3009f..060950b 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBox.cs @@ -3,7 +3,7 @@ namespace StylableWinFormsControls /// /// A stylable version of the /// - public sealed class StylableMessageBox : StylableInteractionBox + public sealed class StylableMessageBox : StylableInteractionBox { /// /// returns a builder object to configure the @@ -39,19 +39,19 @@ internal StylableMessageBox( DialogResult timeoutResult ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult) { - StylableControls.CheckBox = handleCheckBox(checkboxText); + StylableControls.InputControl = handleCheckBox(checkboxText); UpdateSize(); } protected override Point OnUpdateControlSizeMid(int marginLeft, int marginTop, Point currentContentPos) { currentContentPos.Y += StylableControls.Text is null ? 0 : StylableControls.Text.Height + 6; - if (StylableControls.CheckBox is not null) + if (StylableControls.InputControl is not null) { // Margins on CheckBoxes seem to not work directly - StylableControls.CheckBox.Left = currentContentPos.X + marginLeft; - StylableControls.CheckBox.Top = currentContentPos.Y + marginTop; - currentContentPos.Y += StylableControls.CheckBox.Height + 6; + StylableControls.InputControl.Left = currentContentPos.X + marginLeft; + StylableControls.InputControl.Top = currentContentPos.Y + marginTop; + currentContentPos.Y += StylableControls.InputControl.Height + 6; } currentContentPos.Y += 16; diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs index d197cec..b7673b3 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs @@ -10,7 +10,7 @@ namespace StylableWinFormsControls /// A stylable base version of informational boxes with interaction possibilities /// /// - public abstract class StylableInteractionBox : Form + public abstract class StylableInteractionBox : Form where T : Control { /// /// additional form width @@ -25,12 +25,12 @@ public abstract class StylableInteractionBox : Form /// /// resource manager used to access localized texts /// - private static ResourceManager _resources = new(typeof(StylableInteractionBox)); + private static ResourceManager _resources = new("StylableWinFormsControls.StylableInteractionBox", typeof(StylableInteractionBox<>).Assembly); /// /// contains the stylable controls for easier access than iterating over Controls /// - public InteractionBoxControls StylableControls { get; } + public InteractionBoxControls StylableControls { get; } /// /// constructor. not available to others as they should use the @@ -58,7 +58,7 @@ internal StylableInteractionBox( MinimizeBox = false; MaximizeBox = false; handleTitle(caption, icon, helpUri); - StylableControls = new InteractionBoxControls() + StylableControls = new InteractionBoxControls() { Text = handleText(text), Buttons = handleButtons(buttons, defaultButton)