| File: System\Windows\Forms\Design\FormatControl.cs | Web Access |
| Project: src\winforms\src\System.Windows.Forms.Design\src\System.Windows.Forms.Design.csproj (System.Windows.Forms.Design) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Globalization; namespace System.Windows.Forms.Design; internal partial class FormatControl : UserControl { private const int NoFormattingIndex = 0; private const int NumericIndex = 1; private const int CurrencyIndex = 2; private const int DateTimeIndex = 3; private const int ScientificIndex = 4; private const int CustomIndex = 5; private TextBox _customStringTextBox = new(); // static because we want this value to be the same across a // VS session private static readonly DateTime s_dateTimeFormatValue = DateTime.Now; private bool _loaded; public FormatControl() { InitializeComponent(); } public bool Dirty { get; set; } public string FormatType { get { if (formatTypeListBox.SelectedItem is FormatTypeClass formatType) { return formatType.ToString(); } else { return string.Empty; } } set { formatTypeListBox.SelectedIndex = 0; for (int i = 0; i < formatTypeListBox.Items.Count; i++) { var formatType = (FormatTypeClass)formatTypeListBox.Items[i]; if (formatType.ToString().Equals(value)) { formatTypeListBox.SelectedIndex = i; } } } } public FormatTypeClass? FormatTypeItem => formatTypeListBox.SelectedItem as FormatTypeClass; public string? NullValue { get { // If text box is empty or contains just whitespace, return 'null' for the NullValue. // Otherwise we end up pushing empty string as the NullValue for every binding, which breaks non-string // bindings. This does mean that setting the NullValue to empty string now becomes a code-only scenario // for users, but that is an acceptable trade-off. string nullValue = nullValueTextBox.Text; return string.IsNullOrWhiteSpace(nullValue) ? null : nullValue.Trim(); } set { nullValueTextBox.TextChanged -= nullValueTextBox_TextChanged; nullValueTextBox.Text = value; nullValueTextBox.TextChanged += nullValueTextBox_TextChanged; } } public bool NullValueTextBoxEnabled { set { nullValueTextBox.Enabled = value; } } private void customStringTextBox_TextChanged(object? sender, EventArgs e) { var customFormatType = (CustomFormatType?)formatTypeListBox.SelectedItem; Debug.Assert(customFormatType is not null); sampleLabel.Text = customFormatType.SampleString; Dirty = true; } private void dateTimeFormatsListBox_SelectedIndexChanged(object? sender, EventArgs e) { // recompute the SampleLabel var item = (FormatTypeClass?)formatTypeListBox.SelectedItem; Debug.Assert(item is not null); sampleLabel.Text = item.SampleString; Dirty = true; } private void decimalPlacesUpDown_ValueChanged(object? sender, EventArgs e) { // update the sample label var item = (FormatTypeClass?)formatTypeListBox.SelectedItem; Debug.Assert(item is not null); sampleLabel.Text = item.SampleString; Dirty = true; } private void formatGroupBox_Enter(object? sender, EventArgs e) { } private void formatTypeListBox_SelectedIndexChanged(object? sender, EventArgs e) { var item = (FormatTypeClass?)formatTypeListBox.SelectedItem; Debug.Assert(item is not null); UpdateControlVisibility(item); sampleLabel.Text = item.SampleString; explanationLabel.Text = item.TopLabelString; Dirty = true; } // given a formatString/formatInfo combination, this method suggest the most appropriate user control // the result of the function is one of the strings "Numeric", "Currency", "DateTime", "Percentage", "Scientific", "Custom" public static string FormatTypeStringFromFormatString(string formatString) { if (string.IsNullOrEmpty(formatString)) { return SR.BindingFormattingDialogFormatTypeNoFormatting; } if (NumericFormatType.ParseStatic(formatString)) { return SR.BindingFormattingDialogFormatTypeNumeric; } else if (CurrencyFormatType.ParseStatic(formatString)) { return SR.BindingFormattingDialogFormatTypeCurrency; } else if (DateTimeFormatType.ParseStatic(formatString)) { return SR.BindingFormattingDialogFormatTypeDateTime; } else if (ScientificFormatType.ParseStatic(formatString)) { return SR.BindingFormattingDialogFormatTypeScientific; } else { return SR.BindingFormattingDialogFormatTypeCustom; } } protected override bool ProcessMnemonic(char charCode) { if (IsMnemonic(charCode, formatTypeLabel.Text)) { formatTypeListBox.Focus(); return true; } if (IsMnemonic(charCode, nullValueLabel.Text)) { nullValueTextBox.Focus(); return true; } int selIndex = formatTypeListBox.SelectedIndex; switch (selIndex) { case NoFormattingIndex: return false; case ScientificIndex: // FALL THRU case CurrencyIndex: // FALL THRU case NumericIndex: Debug.Assert(decimalPlacesUpDown.Visible); if (IsMnemonic(charCode, secondRowLabel.Text)) { decimalPlacesUpDown.Focus(); return true; } else { return false; } case DateTimeIndex: Debug.Assert(dateTimeFormatsListBox.Visible); if (IsMnemonic(charCode, secondRowLabel.Text)) { dateTimeFormatsListBox.Focus(); return true; } else { return false; } case CustomIndex: Debug.Assert(_customStringTextBox.Visible); if (IsMnemonic(charCode, secondRowLabel.Text)) { _customStringTextBox.Focus(); return true; } else { return false; } default: return false; } } public void ResetFormattingInfo() { decimalPlacesUpDown.ValueChanged -= decimalPlacesUpDown_ValueChanged; _customStringTextBox.TextChanged -= customStringTextBox_TextChanged; dateTimeFormatsListBox.SelectedIndexChanged -= dateTimeFormatsListBox_SelectedIndexChanged; formatTypeListBox.SelectedIndexChanged -= formatTypeListBox_SelectedIndexChanged; decimalPlacesUpDown.Value = 2; nullValueTextBox.Text = string.Empty; dateTimeFormatsListBox.SelectedIndex = -1; formatTypeListBox.SelectedIndex = -1; _customStringTextBox.Text = string.Empty; decimalPlacesUpDown.ValueChanged += decimalPlacesUpDown_ValueChanged; _customStringTextBox.TextChanged += customStringTextBox_TextChanged; dateTimeFormatsListBox.SelectedIndexChanged += dateTimeFormatsListBox_SelectedIndexChanged; formatTypeListBox.SelectedIndexChanged += formatTypeListBox_SelectedIndexChanged; } private void UpdateControlVisibility(FormatTypeClass formatType) { tableLayoutPanel1.SuspendLayout(); secondRowLabel.Text = string.Empty; // process the decimalPlacesLabelVisible if (formatType.DropDownVisible) { secondRowLabel.Text = SR.BindingFormattingDialogDecimalPlaces; decimalPlacesUpDown.Visible = true; } else { decimalPlacesUpDown.Visible = false; } // process customFormatLabelVisible if (formatType.FormatStringTextBoxVisible) { secondRowLabel.Text = SR.BindingFormattingDialogCustomFormat; thirdRowLabel.Visible = true; tableLayoutPanel1.SetColumn(thirdRowLabel, 0); tableLayoutPanel1.SetColumnSpan(thirdRowLabel, 2); _customStringTextBox.Visible = true; if (tableLayoutPanel1.Controls.Contains(dateTimeFormatsListBox)) { tableLayoutPanel1.Controls.Remove(dateTimeFormatsListBox); } tableLayoutPanel1.Controls.Add(_customStringTextBox, 1, 1); } else { thirdRowLabel.Visible = false; _customStringTextBox.Visible = false; } if (formatType.ListBoxVisible) { secondRowLabel.Text = SR.BindingFormattingDialogType; if (tableLayoutPanel1.Controls.Contains(_customStringTextBox)) { tableLayoutPanel1.Controls.Remove(_customStringTextBox); } dateTimeFormatsListBox.Visible = true; tableLayoutPanel1.Controls.Add(dateTimeFormatsListBox, 0, 2); tableLayoutPanel1.SetColumn(dateTimeFormatsListBox, 0); tableLayoutPanel1.SetColumnSpan(dateTimeFormatsListBox, 2); } else { dateTimeFormatsListBox.Visible = false; } secondRowLabel.Visible = secondRowLabel.Text.Length > 0; tableLayoutPanel1.ResumeLayout(performLayout: true); } private void UpdateCustomStringTextBox() { _customStringTextBox = new TextBox { AccessibleDescription = SR.BindingFormattingDialogCustomFormatAccessibleDescription, Margin = new Padding(0, 3, 0, 3), Anchor = AnchorStyles.Left | AnchorStyles.Right, TabIndex = 3 }; _customStringTextBox.TextChanged += customStringTextBox_TextChanged; } private void UpdateFormatTypeListBoxHeight() { // there seems to be a bug in layout because setting // the anchor on the list box does not work. formatTypeListBox.Height = tableLayoutPanel1.Bottom - formatTypeListBox.Top; } private void UpdateFormatTypeListBoxItems() { dateTimeFormatsListBox.SelectedIndexChanged -= dateTimeFormatsListBox_SelectedIndexChanged; dateTimeFormatsListBox.Items.Clear(); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "d")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "D")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "f")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "F")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "g")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "G")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "t")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "T")); dateTimeFormatsListBox.Items.Add(new DateTimeFormatsListBoxItem(s_dateTimeFormatValue, "M")); dateTimeFormatsListBox.SelectedIndex = 0; dateTimeFormatsListBox.SelectedIndexChanged += dateTimeFormatsListBox_SelectedIndexChanged; } private void UpdateTBLHeight() { tableLayoutPanel1.SuspendLayout(); // set up the customStringTextBox tableLayoutPanel1.Controls.Add(_customStringTextBox, 1, 1); _customStringTextBox.Visible = false; // set the thirdRowLabel thirdRowLabel.MaximumSize = new Drawing.Size(tableLayoutPanel1.Width, 0); dateTimeFormatsListBox.Visible = false; tableLayoutPanel1.SetColumn(thirdRowLabel, 0); tableLayoutPanel1.SetColumnSpan(thirdRowLabel, 2); thirdRowLabel.AutoSize = true; tableLayoutPanel1.ResumeLayout(performLayout: true); // Now that PerformLayout set the bounds for the tableLayoutPanel we can use these bounds // to specify the tableLayoutPanel minimumSize. tableLayoutPanel1.MinimumSize = new Drawing.Size(tableLayoutPanel1.Width, tableLayoutPanel1.Height); } private void FormatControl_Load(object? sender, EventArgs e) { if (_loaded) { // we already did the setup work return; } int minWidth, minHeight; nullValueLabel.Text = SR.BindingFormattingDialogNullValue; minWidth = nullValueLabel.Width; minHeight = nullValueLabel.Height; secondRowLabel.Text = SR.BindingFormattingDialogDecimalPlaces; minWidth = Math.Max(minWidth, secondRowLabel.Width); minHeight = Math.Max(minHeight, secondRowLabel.Height); secondRowLabel.Text = SR.BindingFormattingDialogCustomFormat; minWidth = Math.Max(minWidth, secondRowLabel.Width); minHeight = Math.Max(minHeight, secondRowLabel.Height); nullValueLabel.MinimumSize = new Drawing.Size(minWidth, minHeight); secondRowLabel.MinimumSize = new Drawing.Size(minWidth, minHeight); // add items to the list box formatTypeListBox.SelectedIndexChanged -= formatTypeListBox_SelectedIndexChanged; formatTypeListBox.Items.Clear(); formatTypeListBox.Items.Add(new NoFormattingFormatType()); formatTypeListBox.Items.Add(new NumericFormatType(this)); formatTypeListBox.Items.Add(new CurrencyFormatType(this)); formatTypeListBox.Items.Add(new DateTimeFormatType(this)); formatTypeListBox.Items.Add(new ScientificFormatType(this)); formatTypeListBox.Items.Add(new CustomFormatType(this)); formatTypeListBox.SelectedIndex = 0; formatTypeListBox.SelectedIndexChanged += formatTypeListBox_SelectedIndexChanged; UpdateCustomStringTextBox(); UpdateTBLHeight(); UpdateFormatTypeListBoxHeight(); UpdateFormatTypeListBoxItems(); var item = (FormatTypeClass?)formatTypeListBox.SelectedItem; Debug.Assert(item is not null); UpdateControlVisibility(item); sampleLabel.Text = item.SampleString; explanationLabel.Size = new Drawing.Size(formatGroupBox.Width - 10, 30); explanationLabel.Text = item.TopLabelString; Dirty = false; FormatControlFinishedLoading(); _loaded = true; } // This method tells the FormatStringDialog that the FormatControl is loaded and resized. private void FormatControlFinishedLoading() { for (Control? ctl = Parent; ctl is not null; ctl = ctl.Parent) { if (ctl is FormatStringDialog fsd) { fsd.FormatControlFinishedLoading(); break; } } } private class DateTimeFormatsListBoxItem { private readonly DateTime _value; public DateTimeFormatsListBoxItem(DateTime value, string formatString) { _value = value; FormatString = formatString; } public string FormatString { get; } public override string ToString() { return _value.ToString(FormatString, CultureInfo.CurrentCulture); } } internal abstract class FormatTypeClass { public abstract string TopLabelString { get; } public abstract string SampleString { get; } public abstract bool DropDownVisible { get; } public abstract bool ListBoxVisible { get; } public abstract bool FormatStringTextBoxVisible { get; } public abstract bool FormatLabelVisible { get; } public abstract string FormatString { get; } public abstract bool Parse(string formatString); public abstract void PushFormatStringIntoFormatType(string formatString); public abstract override string ToString(); } private void nullValueTextBox_TextChanged(object? sender, EventArgs e) { Dirty = true; } }