diff --git a/README.md b/README.md index db86d5a..ed4e226 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,26 @@ 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 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 +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")) + .WithTimeout(TimeSpan.FromSeconds(30), DialogResult.Cancel) + .ForNumericValue(0, -100, 100); +``` +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()` 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. + + ## Contributions Please view the [contributing guide](/CONTRIBUTING.md) for more information. diff --git a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs index fcd7ead..61e61ee 100644 --- a/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs +++ b/StylableWinFormsControls/StylableWinFormsControls.Example/FrmDefault.Designer.cs @@ -56,6 +56,7 @@ 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(); @@ -74,9 +75,9 @@ private void InitializeComponent() gb_stylableLabel.SuspendLayout(); gb_stylableTextBox.SuspendLayout(); SuspendLayout(); - // + // // stylableButton1 - // + // stylableButton1.BorderColor = Color.Black; stylableButton1.DisabledBackColor = Color.Gray; stylableButton1.DisabledForeColor = Color.Black; @@ -85,14 +86,14 @@ 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; stylableButton1.Click += stylableButton1_Click; - // + // // stylableCheckBox1 - // + // stylableCheckBox1.DisabledForeColor = Color.Empty; stylableCheckBox1.Location = new Point(6, 16); stylableCheckBox1.Name = "stylableCheckBox1"; @@ -100,9 +101,9 @@ private void InitializeComponent() stylableCheckBox1.TabIndex = 1; stylableCheckBox1.Text = "This is content"; stylableCheckBox1.UseVisualStyleBackColor = true; - // + // // stylableComboBox1 - // + // stylableComboBox1.BorderColor = SystemColors.ControlDark; stylableComboBox1.DrawMode = DrawMode.OwnerDrawFixed; stylableComboBox1.FormattingEnabled = true; @@ -113,9 +114,9 @@ private void InitializeComponent() stylableComboBox1.Size = new Size(199, 24); stylableComboBox1.TabIndex = 2; stylableComboBox1.Text = "This is content"; - // + // // stylableDataGridView1 - // + // stylableDataGridView1.AllowUserToOrderColumns = true; stylableDataGridView1.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; stylableDataGridView1.Columns.AddRange(new DataGridViewColumn[] { Column1, Column2, Column3, Column4 }); @@ -127,33 +128,33 @@ private void InitializeComponent() stylableDataGridView1.ScrollBars = ScrollBars.None; stylableDataGridView1.Size = new Size(759, 150); stylableDataGridView1.TabIndex = 3; - // + // // Column1 - // + // Column1.Frozen = true; Column1.HeaderText = "Column1"; Column1.Name = "Column1"; - // + // // Column2 - // + // Column2.HeaderText = "Column2"; Column2.Name = "Column2"; Column2.ReadOnly = true; - // + // // Column3 - // + // Column3.HeaderText = "Column3"; Column3.Name = "Column3"; - // + // // Column4 - // + // Column4.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill; Column4.HeaderText = "Column4"; Column4.Name = "Column4"; Column4.Resizable = DataGridViewTriState.True; - // + // // stylableDateTimePicker1 - // + // stylableDateTimePicker1.DisabledBackColor = Color.Gray; stylableDateTimePicker1.DisabledForeColor = Color.Black; stylableDateTimePicker1.EnabledBackColor = Color.White; @@ -162,9 +163,9 @@ private void InitializeComponent() stylableDateTimePicker1.Name = "stylableDateTimePicker1"; stylableDateTimePicker1.Size = new Size(200, 23); stylableDateTimePicker1.TabIndex = 4; - // + // // stylableLabel1 - // + // stylableLabel1.AutoSize = true; stylableLabel1.DisabledForeColor = Color.Empty; stylableLabel1.Location = new Point(6, 22); @@ -172,9 +173,9 @@ private void InitializeComponent() stylableLabel1.Size = new Size(83, 15); stylableLabel1.TabIndex = 5; stylableLabel1.Text = "This is content"; - // + // // stylableListView1 - // + // stylableListView1.Columns.AddRange(new ColumnHeader[] { columnHeader1, columnHeader2 }); stylableListView1.GroupHeaderBackColor = Color.LightGray; stylableListView1.GroupHeaderForeColor = Color.Black; @@ -187,17 +188,17 @@ private void InitializeComponent() stylableListView1.TabIndex = 6; stylableListView1.UseCompatibleStateImageBehavior = false; stylableListView1.View = View.Details; - // + // // columnHeader1 - // + // columnHeader1.Width = 100; - // + // // columnHeader2 - // + // columnHeader2.Width = 135; - // + // // stylableTabControl1 - // + // stylableTabControl1.ActiveTabBackgroundColor = SystemColors.Control; stylableTabControl1.ActiveTabForegroundColor = SystemColors.ControlText; stylableTabControl1.BackgroundColor = SystemColors.Control; @@ -210,9 +211,9 @@ private void InitializeComponent() stylableTabControl1.Size = new Size(274, 182); stylableTabControl1.TabIndex = 7; stylableTabControl1.UseRoundedCorners = false; - // + // // tabPage1 - // + // tabPage1.Location = new Point(4, 25); tabPage1.Name = "tabPage1"; tabPage1.Padding = new Padding(3); @@ -220,9 +221,9 @@ private void InitializeComponent() tabPage1.TabIndex = 0; tabPage1.Text = "tabPage1"; tabPage1.UseVisualStyleBackColor = true; - // + // // tabPage2 - // + // tabPage2.Location = new Point(4, 25); tabPage2.Name = "tabPage2"; tabPage2.Padding = new Padding(3); @@ -230,13 +231,13 @@ private void InitializeComponent() tabPage2.TabIndex = 1; tabPage2.Text = "tabPage2"; tabPage2.UseVisualStyleBackColor = true; - // + // // stylableTextBox1 - // + // stylableTextBox1.BorderColor = Color.Blue; stylableTextBox1.BorderStyle = BorderStyle.None; stylableTextBox1.DelayedTextChangedTimeout = 900; - stylableTextBox1.HintForeColor = Color.Gray; + stylableTextBox1.ForeColor = Color.Gray; stylableTextBox1.Hint = "Hello, my name is ..."; stylableTextBox1.HintForeColor = Color.Gray; stylableTextBox1.IsDelayActive = true; @@ -246,9 +247,9 @@ private void InitializeComponent() stylableTextBox1.TabIndex = 8; stylableTextBox1.Text = "Hello, my name is ..."; stylableTextBox1.TextForeColor = Color.Black; - // + // // lbl_description - // + // lbl_description.AutoSize = true; lbl_description.DisabledForeColor = Color.Empty; lbl_description.Location = new Point(12, 9); @@ -256,99 +257,134 @@ private void InitializeComponent() lbl_description.Size = new Size(408, 15); lbl_description.TabIndex = 9; lbl_description.Text = "This form displays all stylable controls in their default state without changes."; - // + // // 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); gb_stylabletabcontrol.TabIndex = 11; gb_stylabletabcontrol.TabStop = false; gb_stylabletabcontrol.Text = "StylableTabControl"; - // + // // 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); gb_stylablelistview.TabIndex = 12; gb_stylablelistview.TabStop = false; gb_stylablelistview.Text = "StylableListView"; - // + // // 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); gb_stylablebutton.TabIndex = 13; 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); + 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); gb_stylablecheckbox.TabIndex = 14; gb_stylablecheckbox.TabStop = false; gb_stylablecheckbox.Text = "StylableCheckBox"; - // + // // 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); gb_stylableComboBox.TabIndex = 15; gb_stylableComboBox.TabStop = false; gb_stylableComboBox.Text = "StylableComboBox"; - // + // // 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); gb_stylableDateTimePicker.TabIndex = 16; gb_stylableDateTimePicker.TabStop = false; gb_stylableDateTimePicker.Text = "StylableDateTimePicker"; - // + // // 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); gb_stylableDataGridView.TabIndex = 17; gb_stylableDataGridView.TabStop = false; gb_stylableDataGridView.Text = "StylableDataGridView"; - // + // // 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); gb_stylableLabel.TabIndex = 18; gb_stylableLabel.TabStop = false; gb_stylableLabel.Text = "StylableLabel"; - // + // // 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); gb_stylableTextBox.TabIndex = 19; gb_stylableTextBox.TabStop = false; gb_stylableTextBox.Text = "StylableTextBox"; - // + // // FrmDefault - // + // AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleMode = AutoScaleMode.Font; ClientSize = new Size(803, 510); @@ -411,5 +447,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 86bd153..ada1664 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,7 +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) + { + StylableNumericInputBox inputBox = StylableNumericInputBox.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); + + 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 new file mode 100644 index 0000000..d9f9d83 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.cs @@ -0,0 +1,98 @@ +namespace StylableWinFormsControls +{ + /// + /// 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.
+ /// 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 U Value => _accessor((T)StylableControls.InputControl); + + /// + /// 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 + /// accessor to read the current value from the control + protected StylableInputBox( + string caption, + MessageBoxIcon icon, + string text, + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton, + Uri? helpUri, + TimeSpan? timeout, + DialogResult timeoutResult, + T inputControl, + Func accessor + ) : base(caption, icon, text, buttons, defaultButton, helpUri, timeout, timeoutResult) + { + _accessor = accessor; + StylableControls.InputControl = handleInput(inputControl); + UpdateSize(); + stretchInputControlWidth(inputControl); + } + + 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; + } + + /// + /// 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 + /// + /// the input control + private T handleInput(T input) + { + Controls.Add(input); + return input; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.de.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.de.resx new file mode 100644 index 0000000..c57e676 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/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/InteractionBoxes/InputBoxes/StylableInputBox.resx b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBox.resx new file mode 100644 index 0000000..147c39a --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/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/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs new file mode 100644 index 0000000..77d9f35 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableInputBoxBuilder.cs @@ -0,0 +1,29 @@ + +namespace StylableWinFormsControls +{ + /// + /// the builder to configure the + /// + public sealed class StylableInputBoxBuilder : StylableInteractionBoxBuilder + { + /// + /// creates the for text input + /// + /// the value to show at the start + /// the completely configured but unstyled + public StylableTextInputBox ForText(string startValue = "") + { + return new StylableTextInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, startValue); + } + + /// + /// creates the for numeric input + /// + /// the completely configured but unstyled + public StylableNumericInputBox ForNumericValue(decimal startValue = 0, decimal minValue = decimal.MinValue, decimal maxValue = decimal.MaxValue) + { + return new StylableNumericInputBox(Caption, Icon, Text, Buttons, DefaultButton, HelpUri, Timeout, TimeoutResult, startValue, minValue, maxValue); + } + + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableNumericInputBox.cs new file mode 100644 index 0000000..bd1c897 --- /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) + { + + 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 new file mode 100644 index 0000000..7c699e6 --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InputBoxes/StylableTextInputBox.cs @@ -0,0 +1,35 @@ + +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) + { + StylableControls.InputControl!.Text = startValue; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs similarity index 56% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs index 53b9eef..3c626bc 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/MessageBoxControls.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/InteractionBoxControls.cs @@ -1,40 +1,42 @@ - -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 where T : Control + { + /// + /// the label containing the Text + /// + public StylableLabel? Text { get; internal set; } + /// + /// the optional checkbox + /// + public ReadOnlyCollection Buttons { get; internal set; } = new(Array.Empty()); + + /// + /// the control for entering a value + /// + public T? InputControl { get; internal set; } + + /// + /// constructor + /// + internal InteractionBoxControls() { } + + /// + /// constructor + /// + /// the label containing the Text + /// the optional input control + /// a list containing all buttons on the messageBox + internal InteractionBoxControls( + StylableLabel text, + T? inputControl, + ReadOnlyCollection buttons) + { + Text = text; + InputControl = inputControl; + 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..060950b --- /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.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.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; + } + + /// + /// 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..72a1eda --- /dev/null +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/MessageBoxes/StylableMessageBoxBuilder.cs @@ -0,0 +1,33 @@ +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); + } + + /// + /// 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 81% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBox.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBox.cs index dfb91a9..b7673b3 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 abstract class StylableInteractionBox : Form where T : Control { /// /// 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("StylableWinFormsControls.StylableInteractionBox", typeof(StylableInteractionBox<>).Assembly); - /// - /// 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 50% rename from StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBoxBuilder.cs rename to StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs index 5fa1363..7dd3a73 100644 --- a/StylableWinFormsControls/StylableWinFormsControls/MessageBoxes/StylableMessageBoxBuilder.cs +++ b/StylableWinFormsControls/StylableWinFormsControls/InteractionBoxes/StylableInteractionBoxBuilder.cs @@ -1,134 +1,116 @@ - - -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; - } - } -} +using System.Security.Policy; + +namespace StylableWinFormsControls +{ + /// + /// the builder to configure all informational boxes Set interaction possibilities + /// + /// + public abstract class StylableInteractionBoxBuilder where T : 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 + public T WithButtons( + MessageBoxButtons buttons, + MessageBoxDefaultButton defaultButton = MessageBoxDefaultButton.Button1) + { + Buttons = buttons; + DefaultButton = defaultButton; + return (T)(object)this; + } + /// + /// Set the messagebox/prompt text + /// + /// + public T WithText(string text) + { + Text = text ?? string.Empty; + return (T)(object)this; + } + /// + /// Configure the title bar + /// + /// the caption + /// the icon + 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 + 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 + public T 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 T WithHelpButton(Uri uri) + { + if (uri is null) + { + throw new ArgumentNullException(nameof(uri)); + } + HelpUri = uri; + return (T)(object)this; + } + } +} diff --git a/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj b/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj index f73e1dc..0a65ae1 100644 Binary files a/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj and b/StylableWinFormsControls/StylableWinFormsControls/StylableWinFormsControls.csproj differ