diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.cs index 28913569921..a904a9890a5 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ComboBox.cs @@ -1984,7 +1984,7 @@ private void ChildWndProc(ref Message m) // Forward context menu messages to the parent control if (ContextMenuStrip != null) { - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), WindowMessages.WM_CONTEXTMENU, m.WParam, m.LParam); + SendMessageW(this, WindowMessage.WM_CONTEXTMENU, m.WParam, m.LParam); } else { @@ -3584,7 +3584,7 @@ private void UpdateText() { if (childEdit != null && childEdit.Handle != IntPtr.Zero) { - UnsafeNativeMethods.SendMessage(new HandleRef(this, childEdit.Handle), WindowMessages.WM_SETTEXT, IntPtr.Zero, s); + SendMessageW(new HandleRef(this, childEdit.Handle), WindowMessage.WM_SETTEXT, IntPtr.Zero, s); } } } diff --git a/src/System.Windows.Forms/src/System/Windows/Forms/ListBox.cs b/src/System.Windows.Forms/src/System/Windows/Forms/ListBox.cs index 20b4bd95b41..f04033d8f03 100644 --- a/src/System.Windows.Forms/src/System/Windows/Forms/ListBox.cs +++ b/src/System.Windows.Forms/src/System/Windows/Forms/ListBox.cs @@ -300,7 +300,7 @@ public int ColumnWidth } else if (IsHandleCreated) { - SendMessage((int)LB.SETCOLUMNWIDTH, columnWidth, 0); + SendMessageW(this, (WindowMessage)LB.SETCOLUMNWIDTH, (IntPtr)columnWidth); } } } @@ -469,7 +469,7 @@ internal int FocusedIndex { if (IsHandleCreated) { - return unchecked((int)(long)SendMessage((int)LB.GETCARETINDEX, 0, 0)); + return unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETCARETINDEX)); } return -1; @@ -667,7 +667,7 @@ public virtual int ItemHeight if (drawMode == DrawMode.OwnerDrawFixed && IsHandleCreated) { BeginUpdate(); - SendMessage((int)LB.SETITEMHEIGHT, 0, value); + SendMessageW(this, (WindowMessage)LB.SETITEMHEIGHT, IntPtr.Zero, (IntPtr)value); // Changing the item height might require a resize for IntegralHeight list boxes // @@ -913,7 +913,7 @@ public override int SelectedIndex if (current == SelectionMode.One && IsHandleCreated) { - return unchecked((int)(long)SendMessage((int)LB.GETCURSEL, 0, 0)); + return unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETCURSEL)); } if (itemsCollection != null && SelectedItems.Count > 0) @@ -1216,7 +1216,7 @@ public int TopIndex { if (IsHandleCreated) { - return unchecked((int)(long)SendMessage((int)LB.GETTOPINDEX, 0, 0)); + return unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETTOPINDEX)); } else { @@ -1227,7 +1227,7 @@ public int TopIndex { if (IsHandleCreated) { - SendMessage((int)LB.SETTOPINDEX, value, 0); + SendMessageW(this, (WindowMessage)LB.SETTOPINDEX, (IntPtr)value); } else { @@ -1531,7 +1531,7 @@ public int GetItemHeight(int index) if (IsHandleCreated) { - int h = unchecked((int)(long)SendMessage((int)LB.GETITEMHEIGHT, index, 0)); + int h = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETITEMHEIGHT, (IntPtr)index)); if (h == -1) { throw new Win32Exception(); @@ -1587,7 +1587,7 @@ private bool GetSelectedInternal(int index) { if (IsHandleCreated) { - int sel = unchecked((int)(long)SendMessage((int)LB.GETSEL, index, 0)); + int sel = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETSEL, (IntPtr)index)); if (sel == -1) { throw new Win32Exception(); @@ -1624,7 +1624,7 @@ public int IndexFromPoint(int x, int y) GetClientRect(new HandleRef(this, Handle), ref r); if (r.left <= x && x < r.right && r.top <= y && y < r.bottom) { - int index = unchecked((int)(long)SendMessage((int)LB.ITEMFROMPOINT, 0, unchecked((int)(long)PARAM.FromLowHigh(x, y)))); + int index = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.ITEMFROMPOINT, IntPtr.Zero, PARAM.FromLowHigh(x, y))); if (PARAM.HIWORD(index) == 0) { // Inside ListBox client area @@ -1642,8 +1642,7 @@ public int IndexFromPoint(int x, int y) private int NativeAdd(object item) { Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created."); - int insertIndex = unchecked((int)(long)SendMessage((int)LB.ADDSTRING, 0, GetItemText(item))); - + int insertIndex = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.ADDSTRING, IntPtr.Zero, GetItemText(item))); if (insertIndex == LB_ERRSPACE) { throw new OutOfMemoryException(); @@ -1667,7 +1666,7 @@ private int NativeAdd(object item) private void NativeClear() { Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created."); - SendMessage((int)LB.RESETCONTENT, 0, 0); + SendMessageW(this, (WindowMessage)LB.RESETCONTENT); } /// @@ -1675,7 +1674,7 @@ private void NativeClear() /// internal string NativeGetItemText(int index) { - int len = unchecked((int)(long)SendMessage((int)LB.GETTEXTLEN, index, 0)); + int len = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETTEXTLEN, (IntPtr)index)); StringBuilder sb = new StringBuilder(len + 1); UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), (int)LB.GETTEXT, index, sb); return sb.ToString(); @@ -1688,7 +1687,7 @@ internal string NativeGetItemText(int index) private int NativeInsert(int index, object item) { Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created."); - int insertIndex = unchecked((int)(long)SendMessage((int)LB.INSERTSTRING, index, GetItemText(item))); + int insertIndex = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.INSERTSTRING, (IntPtr)index, GetItemText(item))); if (insertIndex == LB_ERRSPACE) { @@ -1715,8 +1714,8 @@ private void NativeRemoveAt(int index) { Debug.Assert(IsHandleCreated, "Shouldn't be calling Native methods before the handle is created."); - bool selected = (unchecked((int)(long)SendMessage((int)LB.GETSEL, (IntPtr)index, IntPtr.Zero)) > 0); - SendMessage((int)LB.DELETESTRING, index, 0); + bool selected = (unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETSEL, (IntPtr)index, IntPtr.Zero)) > 0); + SendMessageW(this, (WindowMessage)LB.DELETESTRING, (IntPtr)index); //If the item currently selected is removed then we should fire a Selectionchanged event... //as the next time selected index returns -1... @@ -1738,11 +1737,11 @@ private void NativeSetSelected(int index, bool value) if (selectionMode == SelectionMode.One) { - SendMessage((int)LB.SETCURSEL, (value ? index : -1), 0); + SendMessageW(this, (WindowMessage)LB.SETCURSEL, (IntPtr)(value ? index : -1)); } else { - SendMessage((int)LB.SETSEL, value ? -1 : 0, index); + SendMessageW(this, (WindowMessage)LB.SETSEL, PARAM.FromBool(value), (IntPtr)index); } } @@ -1751,7 +1750,7 @@ private void NativeSetSelected(int index, bool value) /// query on that collection after we have called Dirty(). Dirty() is called /// when we receive a LBN_SELCHANGE message. /// - private void NativeUpdateSelection() + private unsafe void NativeUpdateSelection() { Debug.Assert(IsHandleCreated, "Should only call native methods if handle is created"); @@ -1768,7 +1767,7 @@ private void NativeUpdateSelection() switch (selectionMode) { case SelectionMode.One: - int index = unchecked((int)(long)SendMessage((int)LB.GETCURSEL, 0, 0)); + int index = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETCURSEL)); if (index >= 0) { result = new int[] { index }; @@ -1778,11 +1777,14 @@ private void NativeUpdateSelection() case SelectionMode.MultiSimple: case SelectionMode.MultiExtended: - int count = unchecked((int)(long)SendMessage((int)LB.GETSELCOUNT, 0, 0)); + int count = unchecked((int)(long)SendMessageW(this, (WindowMessage)LB.GETSELCOUNT)); if (count > 0) { result = new int[count]; - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), (int)LB.GETSELITEMS, count, result); + fixed (int* pResult = result) + { + SendMessageW(this, (WindowMessage)LB.GETSELITEMS, (IntPtr)count, (IntPtr)pResult); + } } break; } @@ -1814,17 +1816,20 @@ protected override void OnChangeUICues(UICuesEventArgs e) protected override void OnGotFocus(EventArgs e) { - AccessibleObject item = AccessibilityObject.GetFocused(); - - if (item != null) - { - HasKeyboardFocus = false; - item.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); - } - else + if (IsHandleCreated) { - HasKeyboardFocus = true; - AccessibilityObject.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); + AccessibleObject item = AccessibilityObject.GetFocused(); + + if (item != null) + { + HasKeyboardFocus = false; + item.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); + } + else + { + HasKeyboardFocus = true; + AccessibilityObject.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); + } } base.OnGotFocus(e); @@ -1847,26 +1852,26 @@ protected virtual void OnDrawItem(DrawItemEventArgs e) /// set up a few things, like column width, etc! Inheriting classes should /// not forget to call base.OnHandleCreated(). /// - protected override void OnHandleCreated(EventArgs e) + protected unsafe override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); //for getting the current Locale to set the Scrollbars... // - SendMessage((int)LB.SETLOCALE, CultureInfo.CurrentCulture.LCID, 0); + SendMessageW(this, (WindowMessage)LB.SETLOCALE, (IntPtr)CultureInfo.CurrentCulture.LCID); if (columnWidth != 0) { - SendMessage((int)LB.SETCOLUMNWIDTH, columnWidth, 0); + SendMessageW(this, (WindowMessage)LB.SETCOLUMNWIDTH, (IntPtr)columnWidth); } if (drawMode == DrawMode.OwnerDrawFixed) { - SendMessage((int)LB.SETITEMHEIGHT, 0, ItemHeight); + SendMessageW(this, (WindowMessage)LB.SETITEMHEIGHT, IntPtr.Zero, (IntPtr)ItemHeight); } if (topIndex != 0) { - SendMessage((int)LB.SETTOPINDEX, topIndex, 0); + SendMessageW(this, (WindowMessage)LB.SETTOPINDEX, (IntPtr)topIndex); } if (UseCustomTabOffsets && CustomTabOffsets != null) @@ -1874,7 +1879,11 @@ protected override void OnHandleCreated(EventArgs e) int wpar = CustomTabOffsets.Count; int[] offsets = new int[wpar]; CustomTabOffsets.CopyTo(offsets, 0); - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), (int)LB.SETTABSTOPS, wpar, offsets); + + fixed (int* pOffsets = offsets) + { + SendMessageW(this, (WindowMessage)LB.SETTABSTOPS, (IntPtr)wpar, (IntPtr)pOffsets); + } } if (itemsCollection != null) @@ -1972,18 +1981,21 @@ protected override void OnResize(EventArgs e) /// protected override void OnSelectedIndexChanged(EventArgs e) { - if (Focused && FocusedItemIsChanged()) + if (IsHandleCreated) { - var focused = AccessibilityObject.GetFocused(); - if (focused == AccessibilityObject.GetSelected()) + if (Focused && FocusedItemIsChanged()) { - focused?.RaiseAutomationEvent(UiaCore.UIA.SelectionItem_ElementSelectedEventId); + var focused = AccessibilityObject.GetFocused(); + if (focused == AccessibilityObject.GetSelected()) + { + focused?.RaiseAutomationEvent(UiaCore.UIA.SelectionItem_ElementSelectedEventId); + } + focused?.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); + } + else if (ItemsCountIsChanged()) + { + AccessibilityObject?.GetChild(Items.Count - 1)?.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); } - focused?.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); - } - else if (ItemsCountIsChanged()) - { - AccessibilityObject?.GetChild(Items.Count - 1)?.RaiseAutomationEvent(UiaCore.UIA.AutomationFocusChangedEventId); } base.OnSelectedIndexChanged(e); @@ -2211,7 +2223,7 @@ protected override void SetItemsCore(IList value) if (IsHandleCreated) { - SendMessage((int)LB.SETCURSEL, DataManager.Position, 0); + SendMessageW(this, (WindowMessage)LB.SETCURSEL, (IntPtr)DataManager.Position); } // if the list changed and we still did not fire the @@ -2337,7 +2349,7 @@ private void UpdateHorizontalExtent() { width = MaxItemWidth; } - SendMessage((int)LB.SETHORIZONTALEXTENT, width, 0); + SendMessageW(this, (WindowMessage)LB.SETHORIZONTALEXTENT, (IntPtr)width); } } @@ -2388,17 +2400,17 @@ private void UpdateMaxItemWidth(object item, bool removing) } } - // Updates the Custom TabOffsets - // - - private void UpdateCustomTabOffsets() + private unsafe void UpdateCustomTabOffsets() { if (IsHandleCreated && UseCustomTabOffsets && CustomTabOffsets != null) { int wpar = CustomTabOffsets.Count; int[] offsets = new int[wpar]; CustomTabOffsets.CopyTo(offsets, 0); - UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), (int)LB.SETTABSTOPS, wpar, offsets); + fixed (int* pOffsets = offsets) + { + SendMessageW(this, (WindowMessage)LB.SETTABSTOPS, (IntPtr)wpar, (IntPtr)pOffsets); + } Invalidate(); } } @@ -4282,7 +4294,7 @@ public int Count case SelectionMode.MultiSimple: case SelectionMode.MultiExtended: - return unchecked((int)(long)owner.SendMessage((int)LB.GETSELCOUNT, 0, 0)); + return unchecked((int)(long)SendMessageW(owner, (WindowMessage)LB.GETSELCOUNT)); } return 0; diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComboBoxTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComboBoxTests.cs index bb13b52f753..d50abb22ccd 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComboBoxTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ComboBoxTests.cs @@ -106,6 +106,7 @@ public void ComboBox_Ctor_Default() Assert.Equal(Padding.Empty, control.Padding); Assert.Null(control.Parent); Assert.Equal("Microsoft\u00AE .NET", control.ProductName); + Assert.True(control.PreferredHeight > 0); Assert.Equal(new Size(121, control.PreferredHeight), control.PreferredSize); Assert.False(control.RecreatingHandle); Assert.Null(control.Region); @@ -153,17 +154,25 @@ public void ComboBox_CreateParams_GetDefault_ReturnsExpected() Assert.False(control.IsHandleCreated); } + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(AutoCompleteMode))] + public void ComboBox_AutoCompleteMode_SetInvalidValue_ThrowsInvalidEnumArgumentException(AutoCompleteMode value) + { + using var control = new ComboBox(); + Assert.Throws("value", () => control.AutoCompleteMode = value); + } + public static IEnumerable BackColor_Set_TestData() { yield return new object[] { Color.Empty, SystemColors.Window }; yield return new object[] { Color.Red, Color.Red }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(BackColor_Set_TestData))] public void ComboBox_BackColor_Set_GetReturnsExpected(Color value, Color expected) { - var control = new ComboBox + using var control = new ComboBox { BackColor = value }; @@ -182,11 +191,11 @@ public static IEnumerable BackColor_SetWithHandle_TestData() yield return new object[] { Color.Red, Color.Red, 1 }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(BackColor_SetWithHandle_TestData))] public void ComboBox_BackColor_SetWithHandle_GetReturnsExpected(Color value, Color expected, int expectedInvalidatedCallCount) { - var control = new ComboBox(); + using var control = new ComboBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -211,10 +220,10 @@ public void ComboBox_BackColor_SetWithHandle_GetReturnsExpected(Color value, Col Assert.Equal(0, createdCallCount); } - [Fact] + [WinFormsFact] public void ComboBox_BackColor_SetWithHandler_CallsBackColorChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -246,25 +255,59 @@ public void ComboBox_BackColor_SetWithHandler_CallsBackColorChanged() Assert.Equal(2, callCount); } - [Theory] + [WinFormsFact] + public void ComboBox_BackColor_ResetValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ComboBox))[nameof(ComboBox.BackColor)]; + using var control = new ComboBox(); + Assert.False(property.CanResetValue(control)); + + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.True(property.CanResetValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.Window, control.BackColor); + Assert.False(property.CanResetValue(control)); + } + + [WinFormsFact] + public void ComboBox_BackColor_ShouldSerializeValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ComboBox))[nameof(ComboBox.BackColor)]; + using var control = new ComboBox(); + Assert.False(property.ShouldSerializeValue(control)); + + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.True(property.ShouldSerializeValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.Window, control.BackColor); + Assert.False(property.ShouldSerializeValue(control)); + } + + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetImageTheoryData))] - public void BackgroundImage_Set_GetReturnsExpected(Image value) + public void ComboBox_BackgroundImage_Set_GetReturnsExpected(Image value) { - var control = new ComboBox + using var control = new ComboBox { BackgroundImage = value }; Assert.Equal(value, control.BackgroundImage); + Assert.False(control.IsHandleCreated); // Set same. control.BackgroundImage = value; Assert.Equal(value, control.BackgroundImage); + Assert.False(control.IsHandleCreated); } - [Fact] - public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() + [WinFormsFact] + public void ComboBox_BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -275,7 +318,7 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() control.BackgroundImageChanged += handler; // Set different. - var image1 = new Bitmap(10, 10); + using var image1 = new Bitmap(10, 10); control.BackgroundImage = image1; Assert.Same(image1, control.BackgroundImage); Assert.Equal(1, callCount); @@ -286,7 +329,7 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() Assert.Equal(1, callCount); // Set different. - var image2 = new Bitmap(10, 10); + using var image2 = new Bitmap(10, 10); control.BackgroundImage = image2; Assert.Same(image2, control.BackgroundImage); Assert.Equal(2, callCount); @@ -303,25 +346,27 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() Assert.Equal(3, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(ImageLayout))] - public void BackgroundImageLayout_Set_GetReturnsExpected(ImageLayout value) + public void ComboBox_BackgroundImageLayout_Set_GetReturnsExpected(ImageLayout value) { - var control = new ComboBox + using var control = new ComboBox { BackgroundImageLayout = value }; Assert.Equal(value, control.BackgroundImageLayout); + Assert.False(control.IsHandleCreated); // Set same. control.BackgroundImageLayout = value; Assert.Equal(value, control.BackgroundImageLayout); + Assert.False(control.IsHandleCreated); } - [Fact] - public void BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChanged() + [WinFormsFact] + public void ComboBox_BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -353,11 +398,11 @@ public void BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChang Assert.Equal(2, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(ImageLayout))] - public void BackgroundImageLayout_SetInvalid_ThrowsInvalidEnumArgumentException(ImageLayout value) + public void ComboBox_BackgroundImageLayout_SetInvalid_ThrowsInvalidEnumArgumentException(ImageLayout value) { - var control = new ComboBox(); + using var control = new ComboBox(); Assert.Throws("value", () => control.BackgroundImageLayout = value); } @@ -374,29 +419,31 @@ public static IEnumerable DataSource_Set_TestData() yield return new object[] { mockSource.Object }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(DataSource_Set_TestData))] - public void DataSource_Set_GetReturnsExpected(object value) + public void ComBox_DataSource_Set_GetReturnsExpected(object value) { - var control = new SubComboBox + using var control = new SubComboBox { DataSource = value }; Assert.Same(value, control.DataSource); Assert.Empty(control.DisplayMember); Assert.Null(control.DataManager); + Assert.False(control.IsHandleCreated); // Set same. control.DataSource = value; Assert.Same(value, control.DataSource); Assert.Empty(control.DisplayMember); Assert.Null(control.DataManager); + Assert.False(control.IsHandleCreated); } - [Fact] - public void DataSource_SetWithHandler_CallsDataSourceChanged() + [WinFormsFact] + public void ComBox_DataSource_SetWithHandler_CallsDataSourceChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int dataSourceCallCount = 0; int displayMemberCallCount = 0; EventHandler dataSourceHandler = (sender, e) => @@ -449,6 +496,153 @@ public void DataSource_SetWithHandler_CallsDataSourceChanged() Assert.Equal(0, displayMemberCallCount); } + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(ComboBoxStyle))] + public void ComboBox_DropDownStyle_Set_GetReturnsExpected(ComboBoxStyle value) + { + using var control = new ComboBox + { + DropDownStyle = value + }; + Assert.Equal(value, control.DropDownStyle); + Assert.False(control.IsHandleCreated); + + // Set same. + control.DropDownStyle = value; + Assert.Equal(value, control.DropDownStyle); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable DropDownStyle_Set_TestData() + { + foreach (AutoCompleteSource source in Enum.GetValues(typeof(AutoCompleteSource))) + { + foreach (AutoCompleteMode mode in Enum.GetValues(typeof(AutoCompleteMode))) + { + yield return new object[] { source, mode, ComboBoxStyle.Simple, mode }; + yield return new object[] { source, mode, ComboBoxStyle.DropDown, mode }; + yield return new object[] { source, mode, ComboBoxStyle.DropDownList, source != AutoCompleteSource.ListItems ? AutoCompleteMode.None : mode }; + } + } + } + + [WinFormsTheory] + [MemberData(nameof(DropDownStyle_Set_TestData))] + public void ComboBox_DropDownStyle_SetWithSourceAndMode_GetReturnsExpected(AutoCompleteSource source, AutoCompleteMode mode, ComboBoxStyle value, AutoCompleteMode expectedMode) + { + using var control = new ComboBox + { + AutoCompleteSource = source, + AutoCompleteMode = mode, + DropDownStyle = value + }; + Assert.Equal(value, control.DropDownStyle); + Assert.Equal(source, control.AutoCompleteSource); + Assert.Equal(expectedMode, control.AutoCompleteMode); + Assert.False(control.IsHandleCreated); + + // Set same. + control.DropDownStyle = value; + Assert.Equal(value, control.DropDownStyle); + Assert.Equal(source, control.AutoCompleteSource); + Assert.Equal(expectedMode, control.AutoCompleteMode); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ComboBox_DropDownStyle_SetWithPreferredHeight_ResetsPreferredHeight() + { + using var control = new ComboBox + { + FormattingEnabled = true + }; + int height1 = control.PreferredHeight; + + control.DropDownStyle = ComboBoxStyle.DropDownList; + Assert.Equal(height1, control.PreferredHeight); + + control.DropDownStyle = ComboBoxStyle.Simple; + int height2 = control.PreferredHeight; + Assert.True(height2 > height1); + + control.DropDownStyle = ComboBoxStyle.DropDownList; + Assert.Equal(height1, control.PreferredHeight); + } + + [WinFormsTheory] + [InlineData(ComboBoxStyle.Simple, 1)] + [InlineData(ComboBoxStyle.DropDown, 0)] + [InlineData(ComboBoxStyle.DropDownList, 1)] + public void ComboBox_DropDownStyle_SetWithHandle_GetReturnsExpected(ComboBoxStyle value, int expectedCreatedCallCount) + { + using var control = new ComboBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.DropDownStyle = value; + Assert.Equal(value, control.DropDownStyle); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.DropDownStyle = value; + Assert.Equal(value, control.DropDownStyle); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + } + + [WinFormsFact] + public void ComboBox_DropDownStyle_SetWithHandler_CallsDropDownStyleChanged() + { + using var control = new ComboBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.DropDownStyleChanged += handler; + + // Set different. + control.DropDownStyle = ComboBoxStyle.DropDownList; + Assert.Equal(ComboBoxStyle.DropDownList, control.DropDownStyle); + Assert.Equal(1, callCount); + + // Set same. + control.DropDownStyle = ComboBoxStyle.DropDownList; + Assert.Equal(ComboBoxStyle.DropDownList, control.DropDownStyle); + Assert.Equal(1, callCount); + + // Set different. + control.DropDownStyle = ComboBoxStyle.Simple; + Assert.Equal(ComboBoxStyle.Simple, control.DropDownStyle); + Assert.Equal(2, callCount); + + // Remove handler. + control.DropDownStyleChanged -= handler; + control.DropDownStyle = ComboBoxStyle.DropDownList; + Assert.Equal(ComboBoxStyle.DropDownList, control.DropDownStyle); + Assert.Equal(2, callCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(ComboBoxStyle))] + public void ComboBox_DropDownStyle_SetInvalidValue_ThrowsInvalidEnumArgumentException(ComboBoxStyle value) + { + using var control = new ComboBox(); + Assert.Throws("value", () => control.DropDownStyle = value); + } + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetFontTheoryData))] public void ComboBox_Font_Set_GetReturnsExpected(Font value) @@ -519,11 +713,11 @@ public static IEnumerable ForeColor_Set_TestData() yield return new object[] { Color.Red, Color.Red }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(ForeColor_Set_TestData))] public void ComboBox_ForeColor_Set_GetReturnsExpected(Color value, Color expected) { - var control = new ComboBox + using var control = new ComboBox { ForeColor = value }; @@ -545,11 +739,11 @@ public static IEnumerable ForeColor_SetWithHandle_TestData() yield return new object[] { Color.Red, Color.Red, 1 }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(ForeColor_SetWithHandle_TestData))] public void ComboBox_ForeColor_SetWithHandle_GetReturnsExpected(Color value, Color expected, int expectedInvalidatedCallCount) { - var control = new ComboBox(); + using var control = new ComboBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -574,10 +768,10 @@ public void ComboBox_ForeColor_SetWithHandle_GetReturnsExpected(Color value, Col Assert.Equal(0, createdCallCount); } - [Fact] + [WinFormsFact] public void ComboBox_ForeColor_SetWithHandler_CallsForeColorChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -609,6 +803,38 @@ public void ComboBox_ForeColor_SetWithHandler_CallsForeColorChanged() Assert.Equal(2, callCount); } + [WinFormsFact] + public void ComboBox_ForeColor_ResetValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ComboBox))[nameof(ComboBox.ForeColor)]; + using var control = new ComboBox(); + Assert.False(property.CanResetValue(control)); + + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); + Assert.True(property.CanResetValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.WindowText, control.ForeColor); + Assert.False(property.CanResetValue(control)); + } + + [WinFormsFact] + public void ComboBox_ForeColor_ShouldSerializeValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ComboBox))[nameof(ComboBox.ForeColor)]; + using var control = new ComboBox(); + Assert.False(property.ShouldSerializeValue(control)); + + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); + Assert.True(property.ShouldSerializeValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.WindowText, control.ForeColor); + Assert.False(property.ShouldSerializeValue(control)); + } + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] public void ComboBox_Padding_Set_GetReturnsExpected(Padding value, Padding expected) @@ -692,11 +918,11 @@ public void ComboBox_Padding_SetWithHandler_CallsPaddingChanged() Assert.Equal(2, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetRightToLeftTheoryData))] - public void RightToLeft_Set_GetReturnsExpected(RightToLeft value, RightToLeft expected) + public void ComboBox_RightToLeft_Set_GetReturnsExpected(RightToLeft value, RightToLeft expected) { - var control = new ComboBox + using var control = new ComboBox { RightToLeft = value }; @@ -707,10 +933,10 @@ public void RightToLeft_Set_GetReturnsExpected(RightToLeft value, RightToLeft ex Assert.Equal(expected, control.RightToLeft); } - [Fact] - public void RightToLeft_SetWithHandler_CallsRightToLeftChanged() + [WinFormsFact] + public void ComboBox_RightToLeft_SetWithHandler_CallsRightToLeftChanged() { - var control = new ComboBox(); + using var control = new ComboBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -742,21 +968,21 @@ public void RightToLeft_SetWithHandler_CallsRightToLeftChanged() Assert.Equal(2, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(RightToLeft))] - public void RightToLeft_SetInvalid_ThrowsInvalidEnumArgumentException(RightToLeft value) + public void ComboBox_RightToLeft_SetInvalid_ThrowsInvalidEnumArgumentException(RightToLeft value) { - var control = new ComboBox(); + using var control = new ComboBox(); Assert.Throws("value", () => control.RightToLeft = value); } - [Theory] + [WinFormsTheory] [InlineData(-1, "")] [InlineData(0, "System.Windows.Forms.Tests.ComboBoxTests+DataClass")] [InlineData(1, "System.Windows.Forms.Tests.ComboBoxTests+DataClass")] - public void SelectedIndex_SetWithoutDisplayMember_GetReturnsExpected(int value, string expectedText) + public void ComboBox_SelectedIndex_SetWithoutDisplayMember_GetReturnsExpected(int value, string expectedText) { - var control = new ComboBox(); + using var control = new ComboBox(); control.Items.Add(new DataClass { Value = "Value1" }); control.Items.Add(new DataClass { Value = "Value2" }); @@ -772,13 +998,13 @@ public void SelectedIndex_SetWithoutDisplayMember_GetReturnsExpected(int value, Assert.Equal(expectedText, control.Text); } - [Theory] + [WinFormsTheory] [InlineData(-1, "")] [InlineData(0, "Value1")] [InlineData(1, "Value2")] - public void SelectedIndex_SetWithDisplayMember_GetReturnsExpected(int value, string expectedText) + public void ComboBox_SelectedIndex_SetWithDisplayMember_GetReturnsExpected(int value, string expectedText) { - var control = new ComboBox + using var control = new ComboBox { DisplayMember = "Value" }; @@ -920,14 +1146,14 @@ public static IEnumerable FindString_TestData() yield return new object[] { new ComboBox(), string.Empty, startIndex, -1 }; yield return new object[] { new ComboBox(), "s", startIndex, -1 }; - var controlWithNoItems = new ComboBox(); + using var controlWithNoItems = new ComboBox(); Assert.Empty(controlWithNoItems.Items); yield return new object[] { new ComboBox(), null, startIndex, -1 }; yield return new object[] { new ComboBox(), string.Empty, startIndex, -1 }; yield return new object[] { new ComboBox(), "s", startIndex, -1 }; } - var controlWithItems = new ComboBox + using var controlWithItems = new ComboBox { DisplayMember = "Value" }; @@ -993,9 +1219,9 @@ public static IEnumerable FindString_TestData() yield return new object[] { controlWithItems, "NoSuchItem", 5, -1 }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(FindString_TestData))] - public void FindString_Invoke_ReturnsExpected(ComboBox control, string s, int startIndex, int expected) + public void ComboBox_FindString_Invoke_ReturnsExpected(ComboBox control, string s, int startIndex, int expected) { if (startIndex == -1) { @@ -1005,13 +1231,13 @@ public void FindString_Invoke_ReturnsExpected(ComboBox control, string s, int st Assert.Equal(expected, control.FindString(s, startIndex)); } - [Theory] + [WinFormsTheory] [InlineData(-2)] [InlineData(1)] [InlineData(2)] - public void FindString_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + public void ComboBox_FindString_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) { - var control = new ComboBox(); + using var control = new ComboBox(); control.Items.Add("item"); Assert.Throws("startIndex", () => control.FindString("s", startIndex)); } @@ -1026,7 +1252,7 @@ public static IEnumerable FindStringExact_TestData() yield return new object[] { new ComboBox(), string.Empty, startIndex, ignoreCase, -1 }; yield return new object[] { new ComboBox(), "s", startIndex, ignoreCase, -1 }; - var controlWithNoItems = new ComboBox(); + using var controlWithNoItems = new ComboBox(); Assert.Empty(controlWithNoItems.Items); yield return new object[] { new ComboBox(), null, startIndex, ignoreCase, -1 }; yield return new object[] { new ComboBox(), string.Empty, startIndex, ignoreCase, -1 }; @@ -1034,7 +1260,7 @@ public static IEnumerable FindStringExact_TestData() } } - var controlWithItems = new ComboBox + using var controlWithItems = new ComboBox { DisplayMember = "Value" }; @@ -1112,9 +1338,9 @@ public static IEnumerable FindStringExact_TestData() } } - [Theory] + [WinFormsTheory] [MemberData(nameof(FindStringExact_TestData))] - public void FindStringExact_Invoke_ReturnsExpected(ComboBox control, string s, int startIndex, bool ignoreCase, int expected) + public void ComboBox_FindStringExact_Invoke_ReturnsExpected(ComboBox control, string s, int startIndex, bool ignoreCase, int expected) { if (ignoreCase) { @@ -1129,13 +1355,13 @@ public void FindStringExact_Invoke_ReturnsExpected(ComboBox control, string s, i Assert.Equal(expected, control.FindStringExact(s, startIndex, ignoreCase)); } - [Theory] + [WinFormsTheory] [InlineData(-2)] [InlineData(1)] [InlineData(2)] - public void FindStringExact_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + public void ComboBox_FindStringExact_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) { - var control = new ComboBox(); + using var control = new ComboBox(); control.Items.Add("item"); Assert.Throws("startIndex", () => control.FindStringExact("s", startIndex)); Assert.Throws("startIndex", () => control.FindStringExact("s", startIndex, ignoreCase: true)); @@ -1160,7 +1386,7 @@ private void SendCtrlBackspace(SubComboBox tb) tb.ProcessCmdKey(ref message, Keys.Control | Keys.Back); } - [Fact] + [WinFormsFact] public void CtrlBackspaceTextRemainsEmpty() { SubComboBox control = CreateControlForCtrlBackspace(); @@ -1168,7 +1394,7 @@ public void CtrlBackspaceTextRemainsEmpty() Assert.Equal("", control.Text); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetCtrlBackspaceData))] public void CtrlBackspaceTextChanged(string value, string expected, int cursorRelativeToEnd) { @@ -1177,7 +1403,7 @@ public void CtrlBackspaceTextChanged(string value, string expected, int cursorRe Assert.Equal(expected, control.Text); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetCtrlBackspaceRepeatedData))] public void CtrlBackspaceRepeatedTextChanged(string value, string expected, int repeats) { @@ -1189,7 +1415,7 @@ public void CtrlBackspaceRepeatedTextChanged(string value, string expected, int Assert.Equal(expected, control.Text); } - [Fact] + [WinFormsFact] public void CtrlBackspaceDeletesSelection() { SubComboBox control = CreateControlForCtrlBackspace("123-5-7-9"); @@ -1637,12 +1863,58 @@ public new bool ResizeRedraw public new bool ShowKeyboardCues => base.ShowKeyboardCues; +#pragma warning disable 0618 + public new void AddItemsCore(object[] value) => base.AddItemsCore(value); +#pragma warning restore 0618 + + public new AccessibleObject CreateAccessibilityInstance() => base.CreateAccessibilityInstance(); + + public new void CreateHandle() => base.CreateHandle(); + + public new void Dispose(bool disposing) => base.Dispose(disposing); + public new AutoSizeMode GetAutoSizeMode() => base.GetAutoSizeMode(); public new bool GetStyle(ControlStyles flag) => base.GetStyle(flag); + public new bool IsInputKey(Keys keyData) => base.IsInputKey(keyData); + + public new void OnDrawItem(DrawItemEventArgs e) => base.OnDrawItem(e); + + public new void OnDropDown(EventArgs e) => base.OnDropDown(e); + + public new void OnDropDownStyleChanged(EventArgs e) => base.OnDropDownStyleChanged(e); + + public new void OnFontChanged(EventArgs e) => base.OnFontChanged(e); + + public new void OnHandleCreated(EventArgs e) => base.OnHandleCreated(e); + + public new void OnHandleDestroyed(EventArgs e) => base.OnHandleDestroyed(e); + + public new void OnKeyDown(KeyEventArgs e) => base.OnKeyDown(e); + + public new void OnKeyPress(KeyPressEventArgs e) => base.OnKeyPress(e); + + public new void OnMeasureItem(MeasureItemEventArgs e) => base.OnMeasureItem(e); + + public new void OnMouseEnter(EventArgs e) => base.OnMouseEnter(e); + + public new void OnMouseLeave(EventArgs e) => base.OnMouseLeave(e); + + public new void OnParentBackColorChanged(EventArgs e) => base.OnParentBackColorChanged(e); + + public new void OnSelectedIndexChanged(EventArgs e) => base.OnSelectedIndexChanged(e); + + public new void OnSelectedItemChanged(EventArgs e) => base.OnSelectedItemChanged(e); + + public new void OnSelectedValueChanged(EventArgs e) => base.OnSelectedValueChanged(e); + + public new void OnSelectionChangeCommitted(EventArgs e) => base.OnSelectionChangeCommitted(e); + public new bool ProcessCmdKey(ref Message msg, Keys keyData) => base.ProcessCmdKey(ref msg, keyData); + public new void ScaleControl(SizeF factor, BoundsSpecified specified) => base.ScaleControl(factor, specified); + public new void SetStyle(ControlStyles flag, bool value) => base.SetStyle(flag, value); public new void WndProc(ref Message m) => base.WndProc(ref m); @@ -1653,10 +1925,10 @@ private class DataClass public string Value { get; set; } } - [Fact] + [WinFormsFact] public void GettingComboBoxItemAccessibleObject_Not_ThrowsException() { - var control = new ComboBox(); + using var control = new ComboBox(); var h1 = new HashNotImplementedObject(); var h2 = new HashNotImplementedObject(); diff --git a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListBoxTests.cs b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListBoxTests.cs index e8d1a4feae5..102cf2020b3 100644 --- a/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListBoxTests.cs +++ b/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ListBoxTests.cs @@ -2,13 +2,16 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.Linq; using Moq; using WinForms.Common.Tests; using Xunit; using static Interop; +using static Interop.User32; namespace System.Windows.Forms.Tests { @@ -102,6 +105,7 @@ public void ListBox_Ctor_Default() Assert.Equal(Padding.Empty, control.Padding); Assert.Null(control.Parent); Assert.Equal("Microsoft\u00AE .NET", control.ProductName); + Assert.Equal(13 + SystemInformation.BorderSize.Height * 4 + 3, control.PreferredHeight); Assert.Equal(new Size(120, 96), control.PreferredSize); Assert.False(control.RecreatingHandle); Assert.Null(control.Region); @@ -111,6 +115,7 @@ public void ListBox_Ctor_Default() Assert.False(control.ScrollAlwaysVisible); Assert.Null(control.SelectedValue); Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); Assert.Empty(control.SelectedIndices); Assert.Same(control.SelectedIndices, control.SelectedIndices); Assert.Null(control.SelectedItem); @@ -158,17 +163,206 @@ public void ListBox_CreateParams_GetDefault_ReturnsExpected() Assert.False(control.IsHandleCreated); } + [WinFormsTheory] + [InlineData(true, 0x562110C1)] + [InlineData(false, 0x562100C1)] + public void ListBox_CreateParams_GetScrolAlwaysVisible_ReturnsExpected(bool scrollAlwaysVisible, int expectedStyle) + { + using var control = new SubListBox + { + ScrollAlwaysVisible = scrollAlwaysVisible + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0x562100C1)] + [InlineData(false, 0x562101C1)] + public void ListBox_CreateParams_GetIntegralHeight_ReturnsExpected(bool integralHeight, int expectedStyle) + { + using var control = new SubListBox + { + IntegralHeight = integralHeight + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0x562100C1)] + [InlineData(false, 0x56210041)] + public void ListBox_CreateParams_GetUseTabStops_ReturnsExpected(bool useTabStops, int expectedStyle) + { + using var control = new SubListBox + { + UseTabStops = useTabStops + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(BorderStyle.None, 0x562100C1, 0)] + [InlineData(BorderStyle.Fixed3D, 0x562100C1, 0x200)] + [InlineData(BorderStyle.FixedSingle, 0x56A100C1, 0)] + public void ListBox_CreateParams_GetBorderStyle_ReturnsExpected(BorderStyle borderStyle, int expectedStyle, int expectedExStyle) + { + using var control = new SubListBox + { + BorderStyle = borderStyle + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(expectedExStyle, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, true, 0x563102C1)] + [InlineData(true, false, 0x563102C1)] + [InlineData(false, true, 0x563100C1)] + [InlineData(false, false, 0x562100C1)] + public void ListBox_CreateParams_GetMultiColumn_ReturnsExpected(bool multiColumn, bool horizontalScrollBar, int expectedStyle) + { + using var control = new SubListBox + { + MultiColumn = multiColumn, + HorizontalScrollbar = horizontalScrollBar + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended, 0x562108C1)] + [InlineData(SelectionMode.MultiSimple, 0x562100C9)] + [InlineData(SelectionMode.None, 0x562140C1)] + [InlineData(SelectionMode.One, 0x562100C1)] + public void ListBox_CreateParams_GetSelectionMode_ReturnsExpected(SelectionMode selectionMode, int expectedStyle) + { + using var control = new SubListBox + { + SelectionMode = selectionMode + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(DrawMode.Normal, 0x562100C1)] + [InlineData(DrawMode.OwnerDrawFixed, 0x562100D1)] + [InlineData(DrawMode.OwnerDrawVariable, 0x562100E1)] + public void ListBox_CreateParams_GetDrawMode_ReturnsExpected(DrawMode drawMode, int expectedStyle) + { + using var control = new SubListBox + { + DrawMode = drawMode + }; + + CreateParams createParams = control.CreateParams; + Assert.Null(createParams.Caption); + Assert.Equal("ListBox", createParams.ClassName); + Assert.Equal(0x8, createParams.ClassStyle); + Assert.Equal(0x200, createParams.ExStyle); + Assert.Equal(96, createParams.Height); + Assert.Equal(IntPtr.Zero, createParams.Parent); + Assert.Null(createParams.Param); + Assert.Equal(expectedStyle, createParams.Style); + Assert.Equal(120, createParams.Width); + Assert.Equal(0, createParams.X); + Assert.Equal(0, createParams.Y); + Assert.Same(createParams, control.CreateParams); + Assert.False(control.IsHandleCreated); + } + public static IEnumerable BackColor_Set_TestData() { yield return new object[] { Color.Empty, SystemColors.Window }; yield return new object[] { Color.Red, Color.Red }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(BackColor_Set_TestData))] public void ListBox_BackColor_Set_GetReturnsExpected(Color value, Color expected) { - var control = new ListBox + using var control = new ListBox { BackColor = value }; @@ -187,11 +381,11 @@ public static IEnumerable BackColor_SetWithHandle_TestData() yield return new object[] { Color.Red, Color.Red, 1 }; } - [Theory] + [WinFormsTheory] [MemberData(nameof(BackColor_SetWithHandle_TestData))] public void ListBox_BackColor_SetWithHandle_GetReturnsExpected(Color value, Color expected, int expectedInvalidatedCallCount) { - var control = new ListBox(); + using var control = new ListBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -216,10 +410,10 @@ public void ListBox_BackColor_SetWithHandle_GetReturnsExpected(Color value, Colo Assert.Equal(0, createdCallCount); } - [Fact] + [WinFormsFact] public void ListBox_BackColor_SetWithHandler_CallsBackColorChanged() { - var control = new ListBox(); + using var control = new ListBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -251,25 +445,60 @@ public void ListBox_BackColor_SetWithHandler_CallsBackColorChanged() Assert.Equal(2, callCount); } - [Theory] + [WinFormsFact] + public void ListBox_BackColor_ResetValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.BackColor)]; + using var control = new ListBox(); + Assert.False(property.CanResetValue(control)); + + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.True(property.CanResetValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.Window, control.BackColor); + Assert.False(property.CanResetValue(control)); + } + + [WinFormsFact] + public void ListBox_BackColor_ShouldSerializeValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.BackColor)]; + using var control = new ListBox(); + Assert.False(property.ShouldSerializeValue(control)); + + control.BackColor = Color.Red; + Assert.Equal(Color.Red, control.BackColor); + Assert.True(property.ShouldSerializeValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.Window, control.BackColor); + Assert.False(property.ShouldSerializeValue(control)); + } + + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetImageTheoryData))] - public void BackgroundImage_Set_GetReturnsExpected(Image value) + public void ListBox_BackgroundImage_Set_GetReturnsExpected(Image value) { - var control = new ListBox + using var control = new ListBox { BackgroundImage = value }; Assert.Equal(value, control.BackgroundImage); + Assert.False(control.IsHandleCreated); // Set same. control.BackgroundImage = value; Assert.Equal(value, control.BackgroundImage); + Assert.False(control.IsHandleCreated); + Assert.False(control.IsHandleCreated); } - [Fact] - public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() + [WinFormsFact] + public void ListBox_BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() { - var control = new ListBox(); + using var control = new ListBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -280,7 +509,7 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() control.BackgroundImageChanged += handler; // Set different. - var image1 = new Bitmap(10, 10); + using var image1 = new Bitmap(10, 10); control.BackgroundImage = image1; Assert.Same(image1, control.BackgroundImage); Assert.Equal(1, callCount); @@ -291,7 +520,7 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() Assert.Equal(1, callCount); // Set different. - var image2 = new Bitmap(10, 10); + using var image2 = new Bitmap(10, 10); control.BackgroundImage = image2; Assert.Same(image2, control.BackgroundImage); Assert.Equal(2, callCount); @@ -308,25 +537,27 @@ public void BackgroundImage_SetWithHandler_CallsBackgroundImageChanged() Assert.Equal(3, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(ImageLayout))] - public void BackgroundImageLayout_Set_GetReturnsExpected(ImageLayout value) + public void ListBox_BackgroundImageLayout_Set_GetReturnsExpected(ImageLayout value) { - var control = new ListBox + using var control = new ListBox { BackgroundImageLayout = value }; Assert.Equal(value, control.BackgroundImageLayout); + Assert.False(control.IsHandleCreated); // Set same. control.BackgroundImageLayout = value; Assert.Equal(value, control.BackgroundImageLayout); + Assert.False(control.IsHandleCreated); } - [Fact] - public void BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChanged() + [WinFormsFact] + public void ListBox_BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChanged() { - var control = new ListBox(); + using var control = new ListBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -358,68 +589,259 @@ public void BackgroundImageLayout_SetWithHandler_CallsBackgroundImageLayoutChang Assert.Equal(2, callCount); } - [Theory] + [WinFormsTheory] [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(ImageLayout))] - public void BackgroundImageLayout_SetInvalid_ThrowsInvalidEnumArgumentException(ImageLayout value) + public void ListBox_BackgroundImageLayout_SetInvalid_ThrowsInvalidEnumArgumentException(ImageLayout value) { - var control = new ListBox(); + using var control = new ListBox(); Assert.Throws("value", () => control.BackgroundImageLayout = value); } - public static IEnumerable DataSource_Set_TestData() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(BorderStyle))] + public void ListBox_BorderStyle_Set_GetReturnsExpected(BorderStyle value) { - yield return new object[] { null }; - yield return new object[] { new List() }; - yield return new object[] { Array.Empty() }; + using var control = new ListBox() + { + BorderStyle = value + }; + Assert.Equal(value, control.BorderStyle); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); - var mockSource = new Mock(MockBehavior.Strict); - mockSource - .Setup(s => s.GetList()) - .Returns(new int[] { 1 }); - yield return new object[] { mockSource.Object }; + // Set same. + control.BorderStyle = value; + Assert.Equal(value, control.BorderStyle); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); } - [Theory] - [MemberData(nameof(DataSource_Set_TestData))] - public void DataSource_Set_GetReturnsExpected(object value) + [WinFormsTheory] + [InlineData(BorderStyle.Fixed3D, 0)] + [InlineData(BorderStyle.FixedSingle, 1)] + [InlineData(BorderStyle.None, 1)] + public void ListBox_BorderStyle_SetWithHandle_GetReturnsExpected(BorderStyle value, int expectedCreatedCallCount) { - var control = new SubListBox - { - DataSource = value - }; - Assert.Same(value, control.DataSource); - Assert.Empty(control.DisplayMember); - Assert.Null(control.DataManager); + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.BorderStyle = value; + Assert.Equal(value, control.BorderStyle); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); // Set same. - control.DataSource = value; - Assert.Same(value, control.DataSource); - Assert.Empty(control.DisplayMember); - Assert.Null(control.DataManager); + control.BorderStyle = value; + Assert.Equal(value, control.BorderStyle); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); } - [Fact] - public void DataSource_SetWithHandler_CallsDataSourceChanged() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(BorderStyle))] + public void ListBox_BorderStyle_SetInvalid_ThrowsInvalidEnumArgumentException(BorderStyle value) { - var control = new ListBox(); - int dataSourceCallCount = 0; - int displayMemberCallCount = 0; - EventHandler dataSourceHandler = (sender, e) => - { - Assert.Same(control, sender); - Assert.Same(EventArgs.Empty, e); - dataSourceCallCount++; - }; - EventHandler displayMemberHandler = (sender, e) => + using var control = new ListBox(); + Assert.Throws("value", () => control.BorderStyle = value); + } + + [WinFormsTheory] + [InlineData(0)] + [InlineData(1)] + [InlineData(60)] + [InlineData(int.MaxValue)] + public void ListBox_ColumnWidth_Set_GetReturnsExpected(int value) + { + using var control = new ListBox { - Assert.Same(control, sender); - Assert.Same(EventArgs.Empty, e); - displayMemberCallCount++; + ColumnWidth = value }; - control.DataSourceChanged += dataSourceHandler; - control.DisplayMemberChanged += displayMemberHandler; + Assert.Equal(value, control.ColumnWidth); + Assert.False(control.IsHandleCreated); - // Set different. + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(0)] + [InlineData(1)] + [InlineData(60)] + [InlineData(int.MaxValue)] + public void ListBox_ColumnWidth_SetWithCustomOldValue_GetReturnsExpected(int value) + { + using var control = new ListBox + { + ColumnWidth = 10 + }; + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.False(control.IsHandleCreated); + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(0)] + [InlineData(1)] + [InlineData(60)] + [InlineData(int.MaxValue)] + public void ListBox_ColumnWidth_SetWithHandle_GetReturnsExpected(int value) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(0, 1)] + [InlineData(1, 0)] + [InlineData(60, 0)] + [InlineData(int.MaxValue, 0)] + public void ListBox_ColumnWidth_SetWithCustomOldValueWithHandle_GetReturnsExpected(int value, int expectedCreatedCallCount) + { + using var control = new ListBox + { + ColumnWidth = 10 + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + control.ColumnWidth = value; + Assert.Equal(value, control.ColumnWidth); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + } + + [WinFormsFact] + public void ListBox_ColumnWidth_GetItemRect_ReturnsExpected() + { + using var control = new ListBox + { + MultiColumn = true + }; + control.Items.Add("Value"); + + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.ColumnWidth = 123; + + RECT rc = default; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETITEMRECT, (IntPtr)0, ref rc)); + Assert.Equal(123, ((Rectangle)rc).Width); + } + + [WinFormsFact] + public void ListBox_ColumnWidth_SetNegative_ThrowsArgumentOutOfRangeException() + { + using var control = new ListBox(); + Assert.Throws("value", () => control.ColumnWidth = -1); + } + + public static IEnumerable DataSource_Set_TestData() + { + yield return new object[] { null }; + yield return new object[] { new List() }; + yield return new object[] { Array.Empty() }; + + var mockSource = new Mock(MockBehavior.Strict); + mockSource + .Setup(s => s.GetList()) + .Returns(new int[] { 1 }); + yield return new object[] { mockSource.Object }; + } + + [WinFormsTheory] + [MemberData(nameof(DataSource_Set_TestData))] + public void ListBox_DataSource_Set_GetReturnsExpected(object value) + { + using var control = new SubListBox + { + DataSource = value + }; + Assert.Same(value, control.DataSource); + Assert.Empty(control.DisplayMember); + Assert.Null(control.DataManager); + Assert.False(control.IsHandleCreated); + + // Set same. + control.DataSource = value; + Assert.Same(value, control.DataSource); + Assert.Empty(control.DisplayMember); + Assert.Null(control.DataManager); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_DataSource_SetWithHandler_CallsDataSourceChanged() + { + using var control = new ListBox(); + int dataSourceCallCount = 0; + int displayMemberCallCount = 0; + EventHandler dataSourceHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + dataSourceCallCount++; + }; + EventHandler displayMemberHandler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + displayMemberCallCount++; + }; + control.DataSourceChanged += dataSourceHandler; + control.DisplayMemberChanged += displayMemberHandler; + + // Set different. var dataSource1 = new List(); control.DataSource = dataSource1; Assert.Same(dataSource1, control.DataSource); @@ -454,107 +876,129 @@ public void DataSource_SetWithHandler_CallsDataSourceChanged() Assert.Equal(0, displayMemberCallCount); } - [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetFontTheoryData))] - public void Font_Set_GetReturnsExpected(Font value) + public static IEnumerable DrawMode_Set_TestData() { - using var control = new SubListBox + foreach (bool autoSize in new bool[] { true, false }) { - Font = value - }; - Assert.Equal(value ?? Control.DefaultFont, control.Font); - Assert.Equal(control.Font.Height, control.FontHeight); - Assert.False(control.IsHandleCreated); + yield return new object[] { autoSize, true, DrawMode.Normal }; + yield return new object[] { autoSize, false, DrawMode.Normal }; - // Set same. - control.Font = value; - Assert.Equal(value ?? Control.DefaultFont, control.Font); - Assert.Equal(control.Font.Height, control.FontHeight); - Assert.False(control.IsHandleCreated); + yield return new object[] { autoSize, true, DrawMode.OwnerDrawFixed }; + yield return new object[] { autoSize, false, DrawMode.OwnerDrawFixed }; + + yield return new object[] { autoSize, false, DrawMode.OwnerDrawVariable }; + } } - [WinFormsFact] - public void ListBox_Font_SetWithHandler_CallsFontChanged() + [WinFormsTheory] + [MemberData(nameof(DrawMode_Set_TestData))] + public void ListBox_DrawMode_Set_GetReturnsExpected(bool autoSize, bool multiColumn, DrawMode value) { - using var control = new ListBox(); - int callCount = 0; - EventHandler handler = (sender, e) => + using var control = new ListBox { - Assert.Same(control, sender); - Assert.Same(EventArgs.Empty, e); - callCount++; + AutoSize = autoSize, + MultiColumn = multiColumn }; - control.FontChanged += handler; + int layoutCallCount = 0; + control.Layout += (sender, e) => layoutCallCount++; - // Set different. - using var font1 = new Font("Arial", 8.25f); - control.Font = font1; - Assert.Same(font1, control.Font); - Assert.Equal(1, callCount); + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(0, layoutCallCount); + Assert.False(control.IsHandleCreated); // Set same. - control.Font = font1; - Assert.Same(font1, control.Font); - Assert.Equal(1, callCount); - - // Set different. - using var font2 = SystemFonts.DialogFont; - control.Font = font2; - Assert.Same(font2, control.Font); - Assert.Equal(2, callCount); - - // Set null. - control.Font = null; - Assert.Equal(Control.DefaultFont, control.Font); - Assert.Equal(3, callCount); - - // Remove handler. - control.FontChanged -= handler; - control.Font = font1; - Assert.Same(font1, control.Font); - Assert.Equal(3, callCount); + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(0, layoutCallCount); + Assert.False(control.IsHandleCreated); } - public static IEnumerable ForeColor_Set_TestData() + public static IEnumerable DrawMode_SetWithParent_TestData() { - yield return new object[] { Color.Empty, SystemColors.WindowText }; - yield return new object[] { Color.FromArgb(254, 1, 2, 3), Color.FromArgb(254, 1, 2, 3) }; - yield return new object[] { Color.White, Color.White }; - yield return new object[] { Color.Black, Color.Black }; - yield return new object[] { Color.Red, Color.Red }; + yield return new object[] { true, true, DrawMode.Normal, 0 }; + yield return new object[] { true, false, DrawMode.Normal, 0 }; + yield return new object[] { false, true, DrawMode.Normal, 0 }; + yield return new object[] { false, false, DrawMode.Normal, 0 }; + + yield return new object[] { true, true, DrawMode.OwnerDrawFixed, 0 }; + yield return new object[] { true, false, DrawMode.OwnerDrawFixed, 0 }; + yield return new object[] { false, true, DrawMode.OwnerDrawFixed, 0 }; + yield return new object[] { false, false, DrawMode.OwnerDrawFixed, 0 }; + + yield return new object[] { true, false, DrawMode.OwnerDrawVariable, 1 }; + yield return new object[] { false, false, DrawMode.OwnerDrawVariable, 0 }; } - [Theory] - [MemberData(nameof(ForeColor_Set_TestData))] - public void ListBox_ForeColor_Set_GetReturnsExpected(Color value, Color expected) + [WinFormsTheory] + [MemberData(nameof(DrawMode_SetWithParent_TestData))] + public void ListBox_DrawMode_SetWithParent_GetReturnsExpected(bool autoSize, bool multiColumn, DrawMode value, int expectedParentLayoutCallCount) { - var control = new ListBox + using var parent = new Control(); + using var control = new ListBox { - ForeColor = value + AutoSize = autoSize, + MultiColumn = multiColumn, + Parent = parent }; - Assert.Equal(expected, control.ForeColor); - Assert.False(control.IsHandleCreated); + int layoutCallCount = 0; + control.Layout += (sender, e) => layoutCallCount++; + int parentLayoutCallCount = 0; + void parentHandler(object sender, LayoutEventArgs e) + { + Assert.Same(parent, sender); + Assert.Same(control, e.AffectedControl); + Assert.Equal("DrawMode", e.AffectedProperty); + parentLayoutCallCount++; + }; + parent.Layout += parentHandler; - // Set same. - control.ForeColor = value; - Assert.Equal(expected, control.ForeColor); - Assert.False(control.IsHandleCreated); + try + { + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); + Assert.False(control.IsHandleCreated); + Assert.False(parent.IsHandleCreated); + + // Set same. + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(0, layoutCallCount); + Assert.Equal(expectedParentLayoutCallCount, parentLayoutCallCount); + Assert.False(control.IsHandleCreated); + Assert.False(parent.IsHandleCreated); + } + finally + { + parent.Layout -= parentHandler; + } } - public static IEnumerable ForeColor_SetWithHandle_TestData() + public static IEnumerable DrawMode_SetWithHandle_TestData() { - yield return new object[] { Color.Empty, SystemColors.WindowText, 0 }; - yield return new object[] { Color.FromArgb(254, 1, 2, 3), Color.FromArgb(254, 1, 2, 3), 1 }; - yield return new object[] { Color.White, Color.White, 1 }; - yield return new object[] { Color.Black, Color.Black, 1 }; - yield return new object[] { Color.Red, Color.Red, 1 }; + foreach (bool autoSize in new bool[] { true, false }) + { + yield return new object[] { autoSize, true, DrawMode.Normal, 0 }; + yield return new object[] { autoSize, false, DrawMode.Normal, 0 }; + + yield return new object[] { autoSize, true, DrawMode.OwnerDrawFixed, 1 }; + yield return new object[] { autoSize, false, DrawMode.OwnerDrawFixed, 1 }; + + yield return new object[] { autoSize, false, DrawMode.OwnerDrawVariable, 1 }; + } } - [Theory] - [MemberData(nameof(ForeColor_SetWithHandle_TestData))] - public void ListBox_ForeColor_SetWithHandle_GetReturnsExpected(Color value, Color expected, int expectedInvalidatedCallCount) + [WinFormsTheory] + [MemberData(nameof(DrawMode_SetWithHandle_TestData))] + public void ListBox_DrawMode_SetWithHandle_GetReturnsExpected(bool autoSize, bool multiColumn, DrawMode value, int expectedCreatedCallCount) { - var control = new ListBox(); + using var control = new ListBox + { + AutoSize = autoSize, + MultiColumn = multiColumn + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -562,80 +1006,122 @@ public void ListBox_ForeColor_SetWithHandle_GetReturnsExpected(Color value, Colo control.StyleChanged += (sender, e) => styleChangedCallCount++; int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; + int layoutCallCount = 0; + control.Layout += (sender, e) => layoutCallCount++; - control.ForeColor = value; - Assert.Equal(expected, control.ForeColor); + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(expectedCreatedCallCount * 2, layoutCallCount); Assert.True(control.IsHandleCreated); - Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); // Set same. - control.ForeColor = value; - Assert.Equal(expected, control.ForeColor); + control.DrawMode = value; + Assert.Equal(value, control.DrawMode); + Assert.Equal(expectedCreatedCallCount * 2, layoutCallCount); Assert.True(control.IsHandleCreated); - Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); - Assert.Equal(0, createdCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); } - [Fact] - public void ListBox_ForeColor_SetWithHandler_CallsForeColorChanged() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(DrawMode))] + public void ListBox_DrawMode_SetInvalidValue_ThrowsInvalidEnumArgumentException(DrawMode value) { - var control = new ListBox(); - int callCount = 0; - EventHandler handler = (sender, e) => + using var control = new ListBox(); + Assert.Throws("value", () => control.DrawMode = value); + } + + [WinFormsFact] + public void ListBox_DrawMode_SetMultiColumnOwnerDrawVariable_ThrowsArgumentException() + { + using var control = new ListBox { - Assert.Same(control, sender); - Assert.Same(EventArgs.Empty, e); - callCount++; + MultiColumn = true }; - control.ForeColorChanged += handler; + Assert.Throws("value", () => control.DrawMode = DrawMode.OwnerDrawVariable); + } - // Set different. - control.ForeColor = Color.Red; - Assert.Equal(Color.Red, control.ForeColor); - Assert.Equal(1, callCount); + public static IEnumerable Font_Set_TestData() + { + foreach (bool integralHeight in new bool[] { true, false }) + { + yield return new object[] { integralHeight, null }; + yield return new object[] { integralHeight, new Font("Arial", 8.25f) }; + } + } - // Set same. - control.ForeColor = Color.Red; - Assert.Equal(Color.Red, control.ForeColor); - Assert.Equal(1, callCount); - - // Set different. - control.ForeColor = Color.Empty; - Assert.Equal(SystemColors.WindowText, control.ForeColor); - Assert.Equal(2, callCount); + [WinFormsTheory] + [MemberData(nameof(Font_Set_TestData))] + public void ListBox_Font_Set_GetReturnsExpected(bool integralHeight, Font value) + { + using var control = new SubListBox + { + IntegralHeight = integralHeight, + Font = value + }; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.Equal(96, control.Height); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); - // Remove handler. - control.ForeColorChanged -= handler; - control.ForeColor = Color.Red; - Assert.Equal(Color.Red, control.ForeColor); - Assert.Equal(2, callCount); + // Set same. + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.Equal(96, control.Height); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); } [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] - public void ListBox_Padding_Set_GetReturnsExpected(Padding value, Padding expected) + [MemberData(nameof(Font_Set_TestData))] + public void ListBox_Font_SetWithItems_GetReturnsExpected(bool integralHeight, Font value) { - using var control = new ListBox + using var control = new SubListBox { - Padding = value + IntegralHeight = integralHeight }; - Assert.Equal(expected, control.Padding); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.Equal(96, control.Height); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); Assert.False(control.IsHandleCreated); // Set same. - control.Padding = value; - Assert.Equal(expected, control.Padding); + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.Equal(96, control.Height); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); Assert.False(control.IsHandleCreated); } + public static IEnumerable Font_SetWithHandle_TestData() + { + yield return new object[] { true, null, 0, 0 }; + yield return new object[] { false, null, 0, 1 }; + yield return new object[] { true, new Font("Arial", 8.25f), 1, 1 }; + yield return new object[] { false, new Font("Arial", 8.25f), 1, 2 }; + } + [WinFormsTheory] - [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] - public void ListBox_Padding_SetWithHandle_GetReturnsExpected(Padding value, Padding expected) + [MemberData(nameof(Font_SetWithHandle_TestData))] + public void ListBox_Font_SetWithHandle_GetReturnsExpected(bool integralHeight, Font value, int expectedInvalidatedCallCount1, int expectedInvalidatedCallCount2) { - using var control = new ListBox(); + using var control = new SubListBox + { + IntegralHeight = integralHeight + }; Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -644,78 +1130,187 @@ public void ListBox_Padding_SetWithHandle_GetReturnsExpected(Padding value, Padd int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; - control.Padding = value; - Assert.Equal(expected, control.Padding); + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.True(control.Height > 0); + Assert.Empty(control.Items); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); // Set same. - control.Padding = value; - Assert.Equal(expected, control.Padding); + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.True(control.Height > 0); + Assert.Empty(control.Items); Assert.True(control.IsHandleCreated); - Assert.Equal(0, invalidatedCallCount); + Assert.Equal(expectedInvalidatedCallCount2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable Font_SetHandleWithItems_TestData() + { + yield return new object[] { true, null, 0, 0 }; + yield return new object[] { false, null, 1, 2 }; + yield return new object[] { true, new Font("Arial", 8.25f), 1, 1 }; + yield return new object[] { false, new Font("Arial", 8.25f), 2, 3 }; + } + + [WinFormsTheory] + [MemberData(nameof(Font_SetHandleWithItems_TestData))] + public void ListBox_Font_SetWithItemsWithHandle_GetReturnsExpected(bool integralHeight, Font value, int expectedInvalidatedCallCount1, int expectedInvalidatedCallCount2) + { + using var control = new SubListBox + { + IntegralHeight = integralHeight + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.True(control.Height > 0); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Font = value; + Assert.Equal(value ?? Control.DefaultFont, control.Font); + Assert.Equal(control.Font.Height, control.FontHeight); + Assert.True(control.Height > 0); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount2, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } [WinFormsFact] - public void ListBox_Padding_SetWithHandler_CallsPaddingChanged() + public void ListBox_Font_SetWithHandler_CallsFontChanged() { using var control = new ListBox(); int callCount = 0; EventHandler handler = (sender, e) => { - Assert.Equal(control, sender); - Assert.Equal(EventArgs.Empty, e); + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); callCount++; }; - control.PaddingChanged += handler; + control.FontChanged += handler; // Set different. - var padding1 = new Padding(1); - control.Padding = padding1; - Assert.Equal(padding1, control.Padding); + using var font1 = new Font("Arial", 8.25f); + control.Font = font1; + Assert.Same(font1, control.Font); Assert.Equal(1, callCount); // Set same. - control.Padding = padding1; - Assert.Equal(padding1, control.Padding); + control.Font = font1; + Assert.Same(font1, control.Font); Assert.Equal(1, callCount); // Set different. - var padding2 = new Padding(2); - control.Padding = padding2; - Assert.Equal(padding2, control.Padding); + using var font2 = SystemFonts.DialogFont; + control.Font = font2; + Assert.Same(font2, control.Font); Assert.Equal(2, callCount); + // Set null. + control.Font = null; + Assert.Equal(Control.DefaultFont, control.Font); + Assert.Equal(3, callCount); + // Remove handler. - control.PaddingChanged -= handler; - control.Padding = padding1; - Assert.Equal(padding1, control.Padding); - Assert.Equal(2, callCount); + control.FontChanged -= handler; + control.Font = font1; + Assert.Same(font1, control.Font); + Assert.Equal(3, callCount); } - [Theory] - [CommonMemberData(nameof(CommonTestHelper.GetRightToLeftTheoryData))] - public void RightToLeft_Set_GetReturnsExpected(RightToLeft value, RightToLeft expected) + public static IEnumerable ForeColor_Set_TestData() + { + yield return new object[] { Color.Empty, SystemColors.WindowText }; + yield return new object[] { Color.FromArgb(254, 1, 2, 3), Color.FromArgb(254, 1, 2, 3) }; + yield return new object[] { Color.White, Color.White }; + yield return new object[] { Color.Black, Color.Black }; + yield return new object[] { Color.Red, Color.Red }; + } + + [WinFormsTheory] + [MemberData(nameof(ForeColor_Set_TestData))] + public void ListBox_ForeColor_Set_GetReturnsExpected(Color value, Color expected) { - var control = new ListBox + using var control = new ListBox { - RightToLeft = value + ForeColor = value }; - Assert.Equal(expected, control.RightToLeft); + Assert.Equal(expected, control.ForeColor); + Assert.False(control.IsHandleCreated); // Set same. - control.RightToLeft = value; - Assert.Equal(expected, control.RightToLeft); + control.ForeColor = value; + Assert.Equal(expected, control.ForeColor); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable ForeColor_SetWithHandle_TestData() + { + yield return new object[] { Color.Empty, SystemColors.WindowText, 0 }; + yield return new object[] { Color.FromArgb(254, 1, 2, 3), Color.FromArgb(254, 1, 2, 3), 1 }; + yield return new object[] { Color.White, Color.White, 1 }; + yield return new object[] { Color.Black, Color.Black, 1 }; + yield return new object[] { Color.Red, Color.Red, 1 }; + } + + [WinFormsTheory] + [MemberData(nameof(ForeColor_SetWithHandle_TestData))] + public void ListBox_ForeColor_SetWithHandle_GetReturnsExpected(Color value, Color expected, int expectedInvalidatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ForeColor = value; + Assert.Equal(expected, control.ForeColor); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.ForeColor = value; + Assert.Equal(expected, control.ForeColor); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); } - [Fact] - public void RightToLeft_SetWithHandler_CallsRightToLeftChanged() + [WinFormsFact] + public void ListBox_ForeColor_SetWithHandler_CallsForeColorChanged() { - var control = new ListBox(); + using var control = new ListBox(); int callCount = 0; EventHandler handler = (sender, e) => { @@ -723,312 +1318,4365 @@ public void RightToLeft_SetWithHandler_CallsRightToLeftChanged() Assert.Same(EventArgs.Empty, e); callCount++; }; - control.RightToLeftChanged += handler; + control.ForeColorChanged += handler; // Set different. - control.RightToLeft = RightToLeft.Yes; - Assert.Equal(RightToLeft.Yes, control.RightToLeft); + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); Assert.Equal(1, callCount); // Set same. - control.RightToLeft = RightToLeft.Yes; - Assert.Equal(RightToLeft.Yes, control.RightToLeft); + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); Assert.Equal(1, callCount); // Set different. - control.RightToLeft = RightToLeft.Inherit; - Assert.Equal(RightToLeft.No, control.RightToLeft); + control.ForeColor = Color.Empty; + Assert.Equal(SystemColors.WindowText, control.ForeColor); Assert.Equal(2, callCount); // Remove handler. - control.RightToLeftChanged -= handler; - control.RightToLeft = RightToLeft.Yes; - Assert.Equal(RightToLeft.Yes, control.RightToLeft); + control.ForeColorChanged -= handler; + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); Assert.Equal(2, callCount); } - [Theory] - [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(RightToLeft))] - public void RightToLeft_SetInvalid_ThrowsInvalidEnumArgumentException(RightToLeft value) + [WinFormsFact] + public void ListBox_ForeColor_ResetValue_Success() { - var control = new ListBox(); - Assert.Throws("value", () => control.RightToLeft = value); + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.ForeColor)]; + using var control = new ListBox(); + Assert.False(property.CanResetValue(control)); + + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); + Assert.True(property.CanResetValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.WindowText, control.ForeColor); + Assert.False(property.CanResetValue(control)); } [WinFormsFact] - public void ListBox_GetAutoSizeMode_Invoke_ReturnsExpected() + public void ListBox_ForeColor_ShouldSerializeValue_Success() { - using var control = new SubListBox(); - Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode()); + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.ForeColor)]; + using var control = new ListBox(); + Assert.False(property.ShouldSerializeValue(control)); + + control.ForeColor = Color.Red; + Assert.Equal(Color.Red, control.ForeColor); + Assert.True(property.ShouldSerializeValue(control)); + + property.ResetValue(control); + Assert.Equal(SystemColors.WindowText, control.ForeColor); + Assert.False(property.ShouldSerializeValue(control)); + } + + public static IEnumerable HorizontalExtent_Set_TestData() + { + foreach (bool multiColumn in new bool[] { true, false }) + { + foreach (bool horizontalScrollbar in new bool[] { true, false }) + { + yield return new object[] { multiColumn, horizontalScrollbar, -1 }; + yield return new object[] { multiColumn, horizontalScrollbar, 0 }; + yield return new object[] { multiColumn, horizontalScrollbar, 120 }; + } + } } [WinFormsTheory] - [InlineData(ControlStyles.ContainerControl, false)] - [InlineData(ControlStyles.UserPaint, false)] - [InlineData(ControlStyles.Opaque, false)] - [InlineData(ControlStyles.ResizeRedraw, false)] - [InlineData(ControlStyles.FixedWidth, false)] - [InlineData(ControlStyles.FixedHeight, false)] - [InlineData(ControlStyles.StandardClick, false)] - [InlineData(ControlStyles.Selectable, true)] - [InlineData(ControlStyles.UserMouse, false)] - [InlineData(ControlStyles.SupportsTransparentBackColor, false)] - [InlineData(ControlStyles.StandardDoubleClick, true)] - [InlineData(ControlStyles.AllPaintingInWmPaint, true)] - [InlineData(ControlStyles.CacheText, false)] - [InlineData(ControlStyles.EnableNotifyMessage, false)] - [InlineData(ControlStyles.DoubleBuffer, false)] - [InlineData(ControlStyles.OptimizedDoubleBuffer, false)] - [InlineData(ControlStyles.UseTextForAccessibility, false)] - [InlineData((ControlStyles)0, true)] - [InlineData((ControlStyles)int.MaxValue, false)] - [InlineData((ControlStyles)(-1), false)] - public void ListBox_GetStyle_Invoke_ReturnsExpected(ControlStyles flag, bool expected) + [MemberData(nameof(HorizontalExtent_Set_TestData))] + public void ListBox_HorizontalExtent_Set_GetReturnsExpected(bool multiColumn, bool horizontalScrollBar, int value) { - using var control = new SubListBox(); - Assert.Equal(expected, control.GetStyle(flag)); + using var control = new ListBox + { + MultiColumn = multiColumn, + HorizontalScrollbar = horizontalScrollBar, + HorizontalExtent = value + }; + Assert.Equal(value, control.HorizontalExtent); + Assert.False(control.IsHandleCreated); - // Call again to test caching. - Assert.Equal(expected, control.GetStyle(flag)); + // Set same. + control.HorizontalExtent = value; + Assert.Equal(value, control.HorizontalExtent); + Assert.False(control.IsHandleCreated); } - public static IEnumerable FindString_TestData() + public static IEnumerable HorizontalExtent_SetWithHandle_TestData() { - foreach (int startIndex in new int[] { -2, -1, 0, 1 }) + foreach (bool multiColumn in new bool[] { true, false }) { - yield return new object[] { new ListBox(), null, startIndex, -1 }; - yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; - yield return new object[] { new ListBox(), "s", startIndex, -1 }; - - var controlWithNoItems = new ListBox(); - Assert.Empty(controlWithNoItems.Items); - yield return new object[] { new ListBox(), null, startIndex, -1 }; - yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; - yield return new object[] { new ListBox(), "s", startIndex, -1 }; + foreach (bool horizontalScrollbar in new bool[] { true, false }) + { + yield return new object[] { multiColumn, horizontalScrollbar, -1, 0 }; + yield return new object[] { multiColumn, horizontalScrollbar, 0, 0 }; + yield return new object[] { multiColumn, horizontalScrollbar, 120, !multiColumn && horizontalScrollbar ? 1 : 0 }; + } } + } - var controlWithItems = new ListBox + [WinFormsTheory] + [MemberData(nameof(HorizontalExtent_SetWithHandle_TestData))] + public void ListBox_HorizontalExtent_SetWithHandle_GetReturnsExpected(bool multiColumn, bool horizontalScrollBar, int value, int expectedInvalidatedCallCount) + { + using var control = new ListBox { - DisplayMember = "Value" + MultiColumn = multiColumn, + HorizontalScrollbar = horizontalScrollBar }; - controlWithItems.Items.Add(new DataClass { Value = "abc" }); - controlWithItems.Items.Add(new DataClass { Value = "abc" }); - controlWithItems.Items.Add(new DataClass { Value = "ABC" }); - controlWithItems.Items.Add(new DataClass { Value = "def" }); - controlWithItems.Items.Add(new DataClass { Value = "" }); - controlWithItems.Items.Add(new DataClass { Value = null }); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { controlWithItems, "abc", -1, 0 }; - yield return new object[] { controlWithItems, "abc", 0, 1 }; - yield return new object[] { controlWithItems, "abc", 1, 2 }; - yield return new object[] { controlWithItems, "abc", 2, 0 }; - yield return new object[] { controlWithItems, "abc", 5, 0 }; + control.HorizontalExtent = value; + Assert.Equal(value, control.HorizontalExtent); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); - yield return new object[] { controlWithItems, "ABC", -1, 0 }; - yield return new object[] { controlWithItems, "ABC", 0, 1 }; - yield return new object[] { controlWithItems, "ABC", 1, 2 }; - yield return new object[] { controlWithItems, "ABC", 2, 0 }; - yield return new object[] { controlWithItems, "ABC", 5, 0 }; + // Set same. + control.HorizontalExtent = value; + Assert.Equal(value, control.HorizontalExtent); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } - yield return new object[] { controlWithItems, "a", -1, 0 }; - yield return new object[] { controlWithItems, "a", 0, 1 }; - yield return new object[] { controlWithItems, "a", 1, 2 }; - yield return new object[] { controlWithItems, "a", 2, 0 }; - yield return new object[] { controlWithItems, "a", 5, 0 }; + [WinFormsTheory] + [InlineData(true, true, 0)] + [InlineData(true, false, 0)] + [InlineData(false, true, 10)] + [InlineData(false, false, 0)] + public void ListBox_HorizontalExtent_GetHorizontalExtent_Success(bool multiColumn, bool horizontalScrollBar, int expected) + { + using var control = new ListBox + { + MultiColumn = multiColumn, + HorizontalScrollbar = horizontalScrollBar + }; - yield return new object[] { controlWithItems, "A", -1, 0 }; - yield return new object[] { controlWithItems, "A", 0, 1 }; - yield return new object[] { controlWithItems, "A", 1, 2 }; - yield return new object[] { controlWithItems, "A", 2, 0 }; - yield return new object[] { controlWithItems, "A", 5, 0 }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(0, control.HorizontalExtent); + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETHORIZONTALEXTENT)); - yield return new object[] { controlWithItems, "abcd", -1, -1 }; - yield return new object[] { controlWithItems, "abcd", 0, -1 }; - yield return new object[] { controlWithItems, "abcd", 1, -1 }; - yield return new object[] { controlWithItems, "abcd", 2, -1 }; - yield return new object[] { controlWithItems, "abcd", 5, -1 }; + control.HorizontalExtent = 10; + Assert.Equal((IntPtr)expected, SendMessageW(control.Handle, (WindowMessage)LB.GETHORIZONTALEXTENT)); + } - yield return new object[] { controlWithItems, "def", -1, 3 }; - yield return new object[] { controlWithItems, "def", 0, 3 }; - yield return new object[] { controlWithItems, "def", 1, 3 }; - yield return new object[] { controlWithItems, "def", 2, 3 }; - yield return new object[] { controlWithItems, "def", 5, 3 }; + public static IEnumerable HorizontalScrollbar_Set_TestData() + { + foreach (bool multiColumn in new bool[] { true, false }) + { + yield return new object[] { multiColumn, true }; + } + } - yield return new object[] { controlWithItems, null, -1, -1 }; - yield return new object[] { controlWithItems, null, 0, -1 }; - yield return new object[] { controlWithItems, null, 1, -1 }; - yield return new object[] { controlWithItems, null, 2, -1 }; - yield return new object[] { controlWithItems, null, 5, -1 }; + [WinFormsTheory] + [MemberData(nameof(HorizontalScrollbar_Set_TestData))] + public void ListBox_HorizontalScrollbar_Set_GetReturnsExpected(bool multiColumn, bool value) + { + using var control = new ListBox + { + MultiColumn = multiColumn, + HorizontalScrollbar = value + }; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); - yield return new object[] { controlWithItems, string.Empty, -1, 0 }; - yield return new object[] { controlWithItems, string.Empty, 0, 1 }; - yield return new object[] { controlWithItems, string.Empty, 1, 2 }; - yield return new object[] { controlWithItems, string.Empty, 2, 3 }; - yield return new object[] { controlWithItems, string.Empty, 5, 0 }; + // Set same. + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); - yield return new object[] { controlWithItems, "NoSuchItem", -1, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 0, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 1, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 2, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 5, -1 }; + // Set different. + control.HorizontalScrollbar = !value; + Assert.Equal(!value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); } - [Theory] - [MemberData(nameof(FindString_TestData))] - public void FindString_Invoke_ReturnsExpected(ListBox control, string s, int startIndex, int expected) + [WinFormsTheory] + [MemberData(nameof(HorizontalScrollbar_Set_TestData))] + public void ListBox_HorizontalScrollbar_SetWithItems_GetReturnsExpected(bool multiColumn, bool value) { - if (startIndex == -1) + using var control = new ListBox { - Assert.Equal(expected, control.FindString(s)); - } + MultiColumn = multiColumn + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); - Assert.Equal(expected, control.FindString(s, startIndex)); + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Set same. + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Set different. + control.HorizontalScrollbar = !value; + Assert.Equal(!value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); } - [Theory] - [InlineData(-2)] - [InlineData(1)] - [InlineData(2)] - public void FindString_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + public static IEnumerable HorizontalScrollbar_SetWithHandle_TestData() { - var control = new ListBox(); - control.Items.Add("item"); - Assert.Throws("startIndex", () => control.FindString("s", startIndex)); + yield return new object[] { true, true, 0, 0, 1, 0 }; + yield return new object[] { true, false, 0, 0, 1, 0 }; + yield return new object[] { false, true, 2, 1, 3, 2 }; + yield return new object[] { false, false, 0, 0, 3, 1 }; } - public static IEnumerable FindStringExact_TestData() + [WinFormsTheory] + [MemberData(nameof(HorizontalScrollbar_SetWithHandle_TestData))] + public void ListBox_HorizontalScrollbar_SetWithHandle_GetReturnsExpected(bool multiColumn, bool value, int expectedInvalidatedCallCount1, int expectedCreatedCallCount1, int expectedInvalidatedCallCount2, int expectedCreatedCallCount2) { - foreach (int startIndex in new int[] { -2, -1, 0, 1 }) + using var control = new ListBox { - yield return new object[] { new ListBox(), null, startIndex, -1 }; - yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; - yield return new object[] { new ListBox(), "s", startIndex, -1 }; + MultiColumn = multiColumn + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - var controlWithNoItems = new ListBox(); - Assert.Empty(controlWithNoItems.Items); - yield return new object[] { new ListBox(), null, startIndex, -1 }; - yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; - yield return new object[] { new ListBox(), "s", startIndex, -1 }; - } + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount1, createdCallCount); - var controlWithItems = new ListBox + // Set same. + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount1, createdCallCount); + + // Set different. + control.HorizontalScrollbar = !value; + Assert.Equal(!value, control.HorizontalScrollbar); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount2, createdCallCount); + } + + public static IEnumerable HorizontalScrollbar_SetWithItemsWithHandle_TestData() + { + yield return new object[] { true, true, 1, 0, 2, 0 }; + yield return new object[] { true, false, 0, 0, 1, 0 }; + yield return new object[] { false, true, 3, 1, 4, 2 }; + yield return new object[] { false, false, 0, 0, 3, 1 }; + } + + [WinFormsTheory] + [MemberData(nameof(HorizontalScrollbar_SetWithItemsWithHandle_TestData))] + public void ListBox_HorizontalScrollbar_SetWithItemsWithHandle_GetReturnsExpected(bool multiColumn, bool value, int expectedInvalidatedCallCount1, int expectedCreatedCallCount1, int expectedInvalidatedCallCount2, int expectedCreatedCallCount2) + { + using var control = new ListBox { - DisplayMember = "Value" + MultiColumn = multiColumn }; - controlWithItems.Items.Add(new DataClass { Value = "abc" }); - controlWithItems.Items.Add(new DataClass { Value = "abc" }); - controlWithItems.Items.Add(new DataClass { Value = "ABC" }); - controlWithItems.Items.Add(new DataClass { Value = "def" }); - controlWithItems.Items.Add(new DataClass { Value = "" }); - controlWithItems.Items.Add(new DataClass { Value = null }); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { controlWithItems, "abc", -1, 0 }; - yield return new object[] { controlWithItems, "abc", 0, 1 }; - yield return new object[] { controlWithItems, "abc", 1, 2 }; - yield return new object[] { controlWithItems, "abc", 2, 0 }; - yield return new object[] { controlWithItems, "abc", 5, 0 }; + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount1, createdCallCount); - yield return new object[] { controlWithItems, "ABC", -1, 0 }; - yield return new object[] { controlWithItems, "ABC", 0, 1 }; - yield return new object[] { controlWithItems, "ABC", 1, 2 }; - yield return new object[] { controlWithItems, "ABC", 2, 0 }; - yield return new object[] { controlWithItems, "ABC", 5, 0 }; + // Set same. + control.HorizontalScrollbar = value; + Assert.Equal(value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount1, createdCallCount); - yield return new object[] { controlWithItems, "a", -1, -1 }; - yield return new object[] { controlWithItems, "a", 0, -1 }; - yield return new object[] { controlWithItems, "a", 1, -1 }; - yield return new object[] { controlWithItems, "a", 2, -1 }; - yield return new object[] { controlWithItems, "a", 5, -1 }; + // Set different. + control.HorizontalScrollbar = !value; + Assert.Equal(!value, control.HorizontalScrollbar); + Assert.Equal(new string[] { "item1", "item2", "item1" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount2, createdCallCount); + } - yield return new object[] { controlWithItems, "A", -1, -1 }; - yield return new object[] { controlWithItems, "A", 0, -1 }; - yield return new object[] { controlWithItems, "A", 1, -1 }; - yield return new object[] { controlWithItems, "A", 2, -1 }; - yield return new object[] { controlWithItems, "A", 5, -1 }; + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_IntegralHeight_Set_GetReturnsExpected(bool value) + { + using var control = new ListBox + { + IntegralHeight = value + }; + Assert.Equal(value, control.IntegralHeight); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); - yield return new object[] { controlWithItems, "abcd", -1, -1 }; - yield return new object[] { controlWithItems, "abcd", 0, -1 }; - yield return new object[] { controlWithItems, "abcd", 1, -1 }; - yield return new object[] { controlWithItems, "abcd", 2, -1 }; - yield return new object[] { controlWithItems, "abcd", 5, -1 }; + // Set same. + control.IntegralHeight = value; + Assert.Equal(value, control.IntegralHeight); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); - yield return new object[] { controlWithItems, "def", -1, 3 }; - yield return new object[] { controlWithItems, "def", 0, 3 }; - yield return new object[] { controlWithItems, "def", 1, 3 }; - yield return new object[] { controlWithItems, "def", 2, 3 }; - yield return new object[] { controlWithItems, "def", 5, 3 }; + // Set different. + control.IntegralHeight = !value; + Assert.Equal(!value, control.IntegralHeight); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0)] + [InlineData(false, 1)] + public void ListBox_IntegralHeight_SetWithHandle_GetReturnsExpected(bool value, int expectedCreatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.IntegralHeight = value; + Assert.Equal(value, control.IntegralHeight); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.IntegralHeight = value; + Assert.Equal(value, control.IntegralHeight); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set different. + control.IntegralHeight = !value; + Assert.Equal(!value, control.IntegralHeight); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount + 1, createdCallCount); + } + + public static IEnumerable ItemHeight_Set_TestData() + { + foreach (Enum drawMode in Enum.GetValues(typeof(DrawMode))) + { + foreach (bool integralHeight in new bool[] { true, false }) + { + yield return new object[] { drawMode, integralHeight, 1 }; + yield return new object[] { drawMode, integralHeight, 13 }; + yield return new object[] { drawMode, integralHeight, 255 }; + } + } + } + + [WinFormsTheory] + [MemberData(nameof(ItemHeight_Set_TestData))] + public void ListBox_ItemHeight_Set_GetReturnsExpected(DrawMode drawMode, bool integralHeight, int value) + { + using var control = new ListBox + { + DrawMode = drawMode, + IntegralHeight = integralHeight, + ItemHeight = value + }; + Assert.Equal(value, control.ItemHeight); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); + + // Set same. + control.ItemHeight = value; + Assert.Equal(value, control.ItemHeight); + Assert.Equal(96, control.Height); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable ItemHeight_SetWithHandle_TestData() + { + foreach (bool integralHeight in new bool[] { true, false }) + { + yield return new object[] { DrawMode.Normal, integralHeight, 1, 0 }; + yield return new object[] { DrawMode.Normal, integralHeight, 13, 0 }; + yield return new object[] { DrawMode.Normal, integralHeight, 255, 0 }; + yield return new object[] { DrawMode.OwnerDrawFixed, integralHeight, 1, 1 }; + yield return new object[] { DrawMode.OwnerDrawFixed, integralHeight, 13, 0 }; + yield return new object[] { DrawMode.OwnerDrawFixed, integralHeight, 255, 1 }; + yield return new object[] { DrawMode.OwnerDrawVariable, integralHeight, 1, 0 }; + yield return new object[] { DrawMode.OwnerDrawVariable, integralHeight, 13, 0 }; + yield return new object[] { DrawMode.OwnerDrawVariable, integralHeight, 255, 0 }; + } + } + + [WinFormsTheory] + [MemberData(nameof(ItemHeight_SetWithHandle_TestData))] + public void ListBox_ItemHeight_SetWithHandle_GetReturnsExpected(DrawMode drawMode, bool integralHeight, int value, int expectedInvalidatedCallCount) + { + using var control = new ListBox + { + DrawMode = drawMode, + IntegralHeight = integralHeight + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ItemHeight = value; + Assert.True(control.ItemHeight > 0); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.ItemHeight = value; + Assert.True(control.ItemHeight > 0); + Assert.True(control.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(expectedInvalidatedCallCount, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(DrawMode.Normal, false)] + [InlineData(DrawMode.OwnerDrawFixed, true)] + [InlineData(DrawMode.OwnerDrawVariable, false)] + public void ListBox_ItemHeight_Set_GetItemHeight_ReturnsExpected(DrawMode drawMode, bool expected) + { + using var control = new ListBox + { + DrawMode = drawMode, + ItemHeight = 25 + }; + + Assert.NotEqual(IntPtr.Zero, control.Handle); + Assert.Equal(expected, SendMessageW(control.Handle, (WindowMessage)LB.GETITEMHEIGHT) == (IntPtr)25); + } + + [WinFormsTheory] + [InlineData(0)] + [InlineData(256)] + public void ListBox_ItemHeight_SetInvalidValue_ThrowsArgumentOutOfRangeException(int value) + { + using var control = new ListBox(); + Assert.Throws("value", () => control.ItemHeight = value); + } + + [WinFormsFact] + public void ListBox_ItemHeight_ResetValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.ItemHeight)]; + using var control = new ListBox(); + Assert.False(property.CanResetValue(control)); + + control.ItemHeight = 15; + Assert.Equal(15, control.ItemHeight); + Assert.True(property.CanResetValue(control)); + + property.ResetValue(control); + Assert.Equal(13, control.ItemHeight); + Assert.False(property.CanResetValue(control)); + } + + [WinFormsFact] + public void ListBox_ItemHeight_ShouldSerializeValue_Success() + { + PropertyDescriptor property = TypeDescriptor.GetProperties(typeof(ListBox))[nameof(ListBox.ItemHeight)]; + using var control = new ListBox(); + Assert.False(property.ShouldSerializeValue(control)); + + control.ItemHeight = 15; + Assert.Equal(15, control.ItemHeight); + Assert.True(property.ShouldSerializeValue(control)); + + property.ResetValue(control); + Assert.Equal(13, control.ItemHeight); + Assert.False(property.ShouldSerializeValue(control)); + } + + public static IEnumerable Items_CustomCreateItemCollection_TestData() + { + yield return new object[] { null }; + yield return new object[] { new ListBox.ObjectCollection(new ListBox()) }; + } + + [WinFormsTheory] + [MemberData(nameof(Items_CustomCreateItemCollection_TestData))] + public void ListBox_Items_GetCustomCreateItemCollection_ReturnsExpected(ListBox.ObjectCollection result) + { + using var control = new CustomCreateItemCollectionListBox + { + CreateListBoxResult = result + }; + Assert.Same(result, control.Items); + Assert.Same(control.Items, control.Items); + Assert.False(control.IsHandleCreated); + } + + private class CustomCreateItemCollectionListBox : ListBox + { + public ListBox.ObjectCollection CreateListBoxResult { get; set; } + + protected override ListBox.ObjectCollection CreateItemCollection() => CreateListBoxResult; + } + + public static IEnumerable MultiColumn_Set_TestData() + { + yield return new object[] { DrawMode.Normal, true }; + yield return new object[] { DrawMode.Normal, false }; + yield return new object[] { DrawMode.OwnerDrawFixed, true }; + yield return new object[] { DrawMode.OwnerDrawFixed, false }; + } + + [WinFormsTheory] + [MemberData(nameof(MultiColumn_Set_TestData))] + public void ListBox_MultiColumn_Set_GetReturnsExpected(DrawMode drawMode, bool value) + { + using var control = new ListBox + { + DrawMode = drawMode, + MultiColumn = value + }; + Assert.Equal(value, control.MultiColumn); + Assert.False(control.IsHandleCreated); + + // Set same. + control.MultiColumn = value; + Assert.Equal(value, control.MultiColumn); + Assert.False(control.IsHandleCreated); + + // Set different. + control.MultiColumn = !value; + Assert.Equal(!value, control.MultiColumn); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable MultiColumn_SetWithHandle_TestData() + { + yield return new object[] { DrawMode.Normal, true, 1 }; + yield return new object[] { DrawMode.Normal, false, 0 }; + yield return new object[] { DrawMode.OwnerDrawFixed, true, 1 }; + yield return new object[] { DrawMode.OwnerDrawFixed, false, 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(MultiColumn_SetWithHandle_TestData))] + public void ListBox_MultiColumn_SetWithHandle_GetReturnsExpected(DrawMode drawMode, bool value, int expectedCreatedCallCount) + { + using var control = new ListBox + { + DrawMode = drawMode + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.MultiColumn = value; + Assert.Equal(value, control.MultiColumn); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.MultiColumn = value; + Assert.Equal(value, control.MultiColumn); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set different. + control.MultiColumn = !value; + Assert.Equal(!value, control.MultiColumn); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount + 1, createdCallCount); + } + + [WinFormsFact] + public void ListBox_MultiColumn_SetOwnerDrawVariable_ThrowsArgumentException() + { + using var control = new ListBox + { + DrawMode = DrawMode.OwnerDrawVariable + }; + control.MultiColumn = false; + Assert.False(control.MultiColumn); + + Assert.Throws("value", () => control.MultiColumn = true); + Assert.False(control.MultiColumn); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] + public void ListBox_Padding_Set_GetReturnsExpected(Padding value, Padding expected) + { + using var control = new ListBox + { + Padding = value + }; + Assert.Equal(expected, control.Padding); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Padding = value; + Assert.Equal(expected, control.Padding); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetPaddingNormalizedTheoryData))] + public void ListBox_Padding_SetWithHandle_GetReturnsExpected(Padding value, Padding expected) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Padding = value; + Assert.Equal(expected, control.Padding); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Padding = value; + Assert.Equal(expected, control.Padding); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_Padding_SetWithHandler_CallsPaddingChanged() + { + using var control = new ListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Equal(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.PaddingChanged += handler; + + // Set different. + var padding1 = new Padding(1); + control.Padding = padding1; + Assert.Equal(padding1, control.Padding); + Assert.Equal(1, callCount); + + // Set same. + control.Padding = padding1; + Assert.Equal(padding1, control.Padding); + Assert.Equal(1, callCount); + + // Set different. + var padding2 = new Padding(2); + control.Padding = padding2; + Assert.Equal(padding2, control.Padding); + Assert.Equal(2, callCount); + + // Remove handler. + control.PaddingChanged -= handler; + control.Padding = padding1; + Assert.Equal(padding1, control.Padding); + Assert.Equal(2, callCount); + } + + public static IEnumerable PreferredHeight_GetEmpty_TestData() + { + int extra = SystemInformation.BorderSize.Height * 4 + 3; + yield return new object[] { DrawMode.Normal, BorderStyle.Fixed3D, 13 + extra }; + yield return new object[] { DrawMode.Normal, BorderStyle.FixedSingle, 13 + extra }; + yield return new object[] { DrawMode.Normal, BorderStyle.None, 13 }; + + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.Fixed3D, 13 + extra }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.FixedSingle, 13 + extra }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.None, 13 }; + + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.Fixed3D, extra }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.FixedSingle, extra }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.None, 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(PreferredHeight_GetEmpty_TestData))] + public void ListBox_PreferredHeight_GetEmpty_ReturnsExpected(DrawMode drawMode, BorderStyle borderStyle, int expected) + { + using var control = new ListBox + { + DrawMode = drawMode, + BorderStyle = borderStyle + }; + Assert.Equal(expected, control.PreferredHeight); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable PreferredHeight_GetNotEmpty_TestData() + { + int extra = SystemInformation.BorderSize.Height * 4 + 3; + yield return new object[] { DrawMode.Normal, BorderStyle.Fixed3D, 26 + extra }; + yield return new object[] { DrawMode.Normal, BorderStyle.FixedSingle, 26 + extra }; + yield return new object[] { DrawMode.Normal, BorderStyle.None, 26 }; + + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.Fixed3D, 26 + extra }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.FixedSingle, 26 + extra }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.None, 26 }; + + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.Fixed3D, 26 + extra }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.FixedSingle, 26 + extra }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.None, 26 }; + } + + [WinFormsTheory] + [MemberData(nameof(PreferredHeight_GetNotEmpty_TestData))] + public void ListBox_PreferredHeight_GetNotEmpty_ReturnsExpected(DrawMode drawMode, BorderStyle borderStyle, int expected) + { + using var control = new ListBox + { + DrawMode = drawMode, + BorderStyle = borderStyle + }; + control.Items.Add("Item1"); + control.Items.Add("Item2"); + Assert.Equal(expected, control.PreferredHeight); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable PreferredHeight_GetWithHandle_TestData() + { + yield return new object[] { DrawMode.Normal, BorderStyle.Fixed3D }; + yield return new object[] { DrawMode.Normal, BorderStyle.FixedSingle }; + yield return new object[] { DrawMode.Normal, BorderStyle.None }; + + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.Fixed3D }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.FixedSingle }; + yield return new object[] { DrawMode.OwnerDrawFixed, BorderStyle.None }; + + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.Fixed3D }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.FixedSingle }; + yield return new object[] { DrawMode.OwnerDrawVariable, BorderStyle.None }; + } + + [WinFormsTheory] + [MemberData(nameof(PreferredHeight_GetWithHandle_TestData))] + public void ListBox_PreferredHeight_GetEmptyWithHandle_ReturnsExpected(DrawMode drawMode, BorderStyle borderStyle) + { + using var control = new ListBox + { + DrawMode = drawMode, + BorderStyle = borderStyle + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.True(control.PreferredHeight >= 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(PreferredHeight_GetWithHandle_TestData))] + public void ListBox_PreferredHeight_GetNotEmptyWithHandle_ReturnsExpected(DrawMode drawMode, BorderStyle borderStyle) + { + using var control = new ListBox + { + DrawMode = drawMode, + BorderStyle = borderStyle + }; + control.Items.Add("Item1"); + control.Items.Add("Item2"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.True(control.PreferredHeight > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetRightToLeftTheoryData))] + public void ListBox_RightToLeft_Set_GetReturnsExpected(RightToLeft value, RightToLeft expected) + { + using var control = new ListBox + { + RightToLeft = value + }; + Assert.Equal(expected, control.RightToLeft); + Assert.False(control.IsHandleCreated); + + // Set same. + control.RightToLeft = value; + Assert.Equal(expected, control.RightToLeft); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_RightToLeft_SetWithHandler_CallsRightToLeftChanged() + { + using var control = new ListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.RightToLeftChanged += handler; + + // Set different. + control.RightToLeft = RightToLeft.Yes; + Assert.Equal(RightToLeft.Yes, control.RightToLeft); + Assert.Equal(1, callCount); + + // Set same. + control.RightToLeft = RightToLeft.Yes; + Assert.Equal(RightToLeft.Yes, control.RightToLeft); + Assert.Equal(1, callCount); + + // Set different. + control.RightToLeft = RightToLeft.Inherit; + Assert.Equal(RightToLeft.No, control.RightToLeft); + Assert.Equal(2, callCount); + + // Remove handler. + control.RightToLeftChanged -= handler; + control.RightToLeft = RightToLeft.Yes; + Assert.Equal(RightToLeft.Yes, control.RightToLeft); + Assert.Equal(2, callCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(RightToLeft))] + public void ListBox_RightToLeft_SetInvalid_ThrowsInvalidEnumArgumentException(RightToLeft value) + { + using var control = new ListBox(); + Assert.Throws("value", () => control.RightToLeft = value); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_ScrollAlwaysVisible_Set_GetReturnsExpected(bool value) + { + using var control = new ListBox + { + ScrollAlwaysVisible = value + }; + Assert.Equal(value, control.ScrollAlwaysVisible); + Assert.False(control.IsHandleCreated); + + // Set same. + control.ScrollAlwaysVisible = value; + Assert.Equal(value, control.ScrollAlwaysVisible); + Assert.False(control.IsHandleCreated); + + // Set different. + control.ScrollAlwaysVisible = !value; + Assert.Equal(!value, control.ScrollAlwaysVisible); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 1)] + [InlineData(false, 0)] + public void ListBox_ScrollAlwaysVisible_SetWithHandle_GetReturnsExpected(bool value, int expectedCreatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.ScrollAlwaysVisible = value; + Assert.Equal(value, control.ScrollAlwaysVisible); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.ScrollAlwaysVisible = value; + Assert.Equal(value, control.ScrollAlwaysVisible); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set different. + control.ScrollAlwaysVisible = !value; + Assert.Equal(!value, control.ScrollAlwaysVisible); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount + 1, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(SelectionMode))] + public void ListBox_SelectedIndex_GetEmptyWithHandle_ReturnsMinusOne(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Equal(-1, control.SelectedIndex); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(SelectionMode))] + public void ListBox_SelectedIndex_GetNotEmptyWithHandle_ReturnsMinusOne(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Equal(-1, control.SelectedIndex); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + [InlineData(SelectionMode.One)] + public void ListBox_SelectedIndex_SetEmpty_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode, + SelectedIndex = -1 + }; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_SelectedIndex_SetSelectionModeOne_GetReturnsExpected() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select end. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedIndex_SetSelectionModeMultiple_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select end. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0)] + [InlineData(true, 1)] + [InlineData(false, 0)] + [InlineData(false, 1)] + public void ListBox_SelectedIndex_SetWithDataManager_SetsDataManagerPosition(bool formattingEnabled, int position) + { + var bindingContext = new BindingContext(); + var dataSource = new List { "item1", "item2", "item3" }; + using var control = new SubListBox + { + BindingContext = bindingContext, + DataSource = dataSource, + FormattingEnabled = formattingEnabled + }; + control.DataManager.Position = position; + + // Select end. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.Equal(1, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.Equal(1, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.Equal(0, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.Equal(0, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_SelectedIndex_SetSelectionModeOneWithHandle_GetReturnsExpected() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // Select end. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedIndex_SetSelectionModeMultipleWithHandle_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // Select end. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_SelectedIndex_GetCurSelOne_Success() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select last. + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.SelectedIndex = 1; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal((IntPtr)(-1), SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedIndex_GetCurSelMultiple_Success(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select last. + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.SelectedIndex = 1; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Span buffer = stackalloc int[5]; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 1, 0, 0, 0, 0 }, buffer.ToArray()); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Assert.Equal((IntPtr)2, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 0, 1, 0, 0, 0 }, buffer.ToArray()); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 0, 1, 0, 0, 0 }, buffer.ToArray()); + } + + [WinFormsTheory] + [InlineData(SelectionMode.One)] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedIndex_SetWithHandler_CallsSelectedIndexChanged(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.SelectedIndexChanged += handler; + + // Select last. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, callCount); + + // Select same. + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, callCount); + + // Select first. + control.SelectedIndex = 0; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(2, callCount); + + // Clear selection. + control.SelectedIndex = -1; + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal(3, callCount); + + // Remove handler. + control.SelectedIndexChanged -= handler; + control.SelectedIndex = 1; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal(3, callCount); + } + + [WinFormsTheory] + [InlineData(-2)] + [InlineData(0)] + [InlineData(1)] + public void ListBox_SelectedIndex_SetInvalidValueEmpty_ThrowsArgumentOutOfRangeException(int value) + { + using var control = new ListBox(); + Assert.Throws("value", () => control.SelectedIndex = value); + } + + [WinFormsTheory] + [InlineData(-2)] + [InlineData(1)] + public void ListBox_SelectedIndex_SetInvalidValueNotEmpty_ThrowsArgumentOutOfRangeException(int value) + { + using var control = new ListBox(); + control.Items.Add("Item"); + Assert.Throws("value", () => control.SelectedIndex = value); + } + + [WinFormsFact] + public void ListBox_SelectedIndex_SetNoSelection_ThrowsArgumentException() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.None + }; + Assert.Throws("value", () => control.SelectedIndex = -1); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(SelectionMode))] + public void ListBox_SelectedItem_GetEmptyWithHandle_ReturnsNull(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Null(control.SelectedItem); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(SelectionMode))] + public void ListBox_SelectedItem_GetNotEmptyWithHandle_ReturnsNull(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Null(control.SelectedItem); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended, null)] + [InlineData(SelectionMode.MultiSimple, null)] + [InlineData(SelectionMode.One, null)] + [InlineData(SelectionMode.MultiExtended, "item")] + [InlineData(SelectionMode.MultiSimple, "item")] + [InlineData(SelectionMode.One, "item")] + public void ListBox_SelectedItem_SetEmpty_GetReturnsExpected(SelectionMode selectionMode, string value) + { + using var control = new ListBox + { + SelectionMode = selectionMode, + SelectedItem = value + }; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectedItem = value; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_SelectedItem_SetSelectionModeOne_GetReturnsExpected() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select end. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedItem_SetSelectionModeMultiple_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select end. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0)] + [InlineData(true, 1)] + [InlineData(false, 0)] + [InlineData(false, 1)] + public void ListBox_SelectedItem_SetWithDataManager_SetsDataManagerPosition(bool formattingEnabled, int position) + { + var bindingContext = new BindingContext(); + var dataSource = new List { "item1", "item2", "item3" }; + using var control = new SubListBox + { + BindingContext = bindingContext, + DataSource = dataSource, + FormattingEnabled = formattingEnabled + }; + control.DataManager.Position = position; + + // Select end. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.Equal(1, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.Equal(1, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.Equal(1, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.Equal(0, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.Equal(0, control.DataManager.Position); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_SelectedItem_SetSelectionModeOneWithHandle_GetReturnsExpected() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // Select end. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(0, Assert.Single(control.SelectedIndices)); + Assert.Equal("item1", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedItem_SetSelectionModeMultipleWithHandle_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // Select end. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_SelectedItem_GetCurSelOne_Success() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.One + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select last. + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.SelectedItem = "item2"; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal((IntPtr)(-1), SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedItem_GetCurSelMultiple_Success(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + // Select last. + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.SelectedItem = "item2"; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Span buffer = stackalloc int[5]; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 1, 0, 0, 0, 0 }, buffer.ToArray()); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + buffer = stackalloc int[5]; + Assert.Equal((IntPtr)1, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 1, 0, 0, 0, 0 }, buffer.ToArray()); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Assert.Equal((IntPtr)2, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 0, 1, 0, 0, 0 }, buffer.ToArray()); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETCURSEL)); + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETSELITEMS, (IntPtr)buffer.Length, ref buffer[0])); + Assert.Equal(new int[] { 0, 1, 0, 0, 0 }, buffer.ToArray()); + } + + [WinFormsTheory] + [InlineData(SelectionMode.One)] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectedItem_SetWithHandler_CallsSelectedIndexChanged(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(EventArgs.Empty, e); + callCount++; + }; + control.SelectedIndexChanged += handler; + + // Select last. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, callCount); + + // Select same. + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, callCount); + + // Select invalid. + control.SelectedItem = "NoSuchItem"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, callCount); + + // Select first. + control.SelectedItem = "item1"; + Assert.Equal(0, control.SelectedIndex); + Assert.Equal(2, callCount); + + // Clear selection. + control.SelectedItem = null; + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal(3, callCount); + + // Remove handler. + control.SelectedIndexChanged -= handler; + control.SelectedItem = "item2"; + Assert.Equal(1, control.SelectedIndex); + Assert.Equal(3, callCount); + } + + [WinFormsTheory] + [InlineData(null)] + [InlineData("NoSuchItem")] + public void ListBox_SelectedItem_SetNoSelectionEmpty_Nop(object value) + { + using var control = new ListBox + { + SelectionMode = SelectionMode.None + }; + control.SelectedItem = value; + Assert.Null(control.SelectedItem); + } + + [WinFormsFact] + public void ListBox_SelectedItem_SetNoSelectionNotEmpty_ThrowsArgumentException() + { + using var control = new ListBox + { + SelectionMode = SelectionMode.None + }; + control.Items.Add("item"); + AssertExtensions.Throws("value", () => control.SelectedItem = "item"); + Assert.Null(control.SelectedItem); + + control.SelectedItem = "NoSuchItem"; + Assert.Null(control.SelectedItem); + + AssertExtensions.Throws("value", () => control.SelectedItem = null); + Assert.Null(control.SelectedItem); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(SelectionMode))] + public void ListBox_SelectionMode_SetEmpty_GetReturnsExpected(SelectionMode value) + { + using var control = new ListBox + { + SelectionMode = value + }; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable SelectionMode_SetWithCustomOldValue_TestData() + { + foreach (SelectionMode selectionMode in Enum.GetValues(typeof(SelectionMode))) + { + foreach (SelectionMode value in Enum.GetValues(typeof(SelectionMode))) + { + yield return new object[] { selectionMode, value }; + } + } + } + + [WinFormsTheory] + [MemberData(nameof(SelectionMode_SetWithCustomOldValue_TestData))] + public void ListBox_SelectionMode_SetEmptyWithCustomOldValue_GetReturnsExpected(SelectionMode selectionMode, SelectionMode value) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiSimple)] + [InlineData(SelectionMode.MultiExtended)] + public void ListBox_SelectionMode_SetWithItemsOneSelectedToMulti_GetReturnsExpected(SelectionMode value) + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 1; + + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Set back to one. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_SelectionMode_SetWithItemsOneSelectedToNone_GetReturnsExpected() + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 1; + + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + + // Set back to one. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectionMode_SetWithItemsMultiSelectedToOne_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 0; + control.SelectedIndex = 1; + + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Set back to multi. + control.SelectionMode = selectionMode; + Assert.Equal(selectionMode, control.SelectionMode); + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectionMode_SetWithItemsMultiSelectedToNone_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 0; + control.SelectedIndex = 1; + + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Set same. + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + + // Set back to multi. + control.SelectionMode = selectionMode; + Assert.Equal(selectionMode, control.SelectionMode); + Assert.Equal(0, control.SelectedIndex); + Assert.Equal("item1", control.SelectedItem); + Assert.Equal(new int[] { 0, 1 }, control.SelectedIndices.Cast()); + Assert.Equal(new string[] { "item1", "item2" }, control.SelectedItems.Cast()); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(SelectionMode.None, 1)] + [InlineData(SelectionMode.MultiExtended, 1)] + [InlineData(SelectionMode.MultiSimple, 1)] + [InlineData(SelectionMode.One, 0)] + public void ListBox_SelectionMode_SetEmptyWithHandle_GetReturnsExpected(SelectionMode value, int expectedCreatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + } + + public static IEnumerable SelectionMode_SetWithCustomOldValueWithHandle_TestData() + { + yield return new object[] { SelectionMode.None, SelectionMode.None, 0 }; + yield return new object[] { SelectionMode.None, SelectionMode.MultiExtended, 1 }; + yield return new object[] { SelectionMode.None, SelectionMode.MultiSimple, 1 }; + yield return new object[] { SelectionMode.None, SelectionMode.One, 1 }; + + yield return new object[] { SelectionMode.MultiExtended, SelectionMode.None, 1 }; + yield return new object[] { SelectionMode.MultiExtended, SelectionMode.MultiExtended, 0 }; + yield return new object[] { SelectionMode.MultiExtended, SelectionMode.MultiSimple, 1 }; + yield return new object[] { SelectionMode.MultiExtended, SelectionMode.One, 1 }; + + yield return new object[] { SelectionMode.MultiSimple, SelectionMode.None, 1 }; + yield return new object[] { SelectionMode.MultiSimple, SelectionMode.MultiExtended, 1 }; + yield return new object[] { SelectionMode.MultiSimple, SelectionMode.MultiSimple, 0 }; + yield return new object[] { SelectionMode.MultiSimple, SelectionMode.One, 1 }; + + yield return new object[] { SelectionMode.One, SelectionMode.None, 1 }; + yield return new object[] { SelectionMode.One, SelectionMode.MultiExtended, 1 }; + yield return new object[] { SelectionMode.One, SelectionMode.MultiSimple, 1 }; + yield return new object[] { SelectionMode.One, SelectionMode.One, 0 }; + } + + [WinFormsTheory] + [MemberData(nameof(SelectionMode_SetWithCustomOldValueWithHandle_TestData))] + public void ListBox_SelectionMode_SetEmptyWithCustomOldValueWithHandle_GetReturnsExpected(SelectionMode selectionMode, SelectionMode value, int expectedCreatedCallCount) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiSimple)] + [InlineData(SelectionMode.MultiExtended)] + public void ListBox_SelectionMode_SetWithItemsOneSelectedToMultiWithHandle_GetReturnsExpected(SelectionMode value) + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 1; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set same. + control.SelectionMode = value; + Assert.Equal(value, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set back to one. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(2, createdCallCount); + } + + [WinFormsFact] + public void ListBox_SelectionMode_SetWithItemsOneSelectedToNoneWithHandle_GetReturnsExpected() + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 1; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set same. + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set back to one. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(2, createdCallCount); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectionMode_SetWithItemsMultiSelectedToOneWithHandle_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 0; + control.SelectedIndex = 1; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set same. + control.SelectionMode = SelectionMode.One; + Assert.Equal(SelectionMode.One, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set back to multi. + control.SelectionMode = selectionMode; + Assert.Equal(selectionMode, control.SelectionMode); + Assert.Equal(1, control.SelectedIndex); + Assert.Equal("item2", control.SelectedItem); + Assert.Equal(1, Assert.Single(control.SelectedIndices)); + Assert.Equal("item2", Assert.Single(control.SelectedItems)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(2, createdCallCount); + } + + [WinFormsTheory] + [InlineData(SelectionMode.MultiExtended)] + [InlineData(SelectionMode.MultiSimple)] + public void ListBox_SelectionMode_SetWithItemsMultiSelectedToNoneWithHandle_GetReturnsExpected(SelectionMode selectionMode) + { + using var control = new ListBox + { + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 0; + control.SelectedIndex = 1; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set same. + control.SelectionMode = SelectionMode.None; + Assert.Equal(SelectionMode.None, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(1, createdCallCount); + + // Set back to multi. + control.SelectionMode = selectionMode; + Assert.Equal(selectionMode, control.SelectionMode); + Assert.Equal(-1, control.SelectedIndex); + Assert.Null(control.SelectedItem); + Assert.Empty(control.SelectedIndices); + Assert.Empty(control.SelectedItems); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(2, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryDataInvalid), typeof(SelectionMode))] + public void ListBox_SelectionMode_SetInvalidValue_ThrowsInvalidEnumArgumentException(SelectionMode value) + { + using var control = new ListBox(); + Assert.Throws("value", () => control.SelectionMode = value); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_Sorted_SetWithoutItems_GetReturnsExpected(bool value) + { + using var control = new ListBox + { + Sorted = value + }; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_Sorted_SetWithEmptyItems_GetReturnsExpected(bool value) + { + using var control = new ListBox(); + Assert.Empty(control.Items); + + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Empty(control.Items); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable Sorted_SetWithItems_TestData() + { + yield return new object[] { true, new string[] { "item1", "item2" } }; + yield return new object[] { false, new string[] { "item2", "item1" } }; + } + + [WinFormsTheory] + [MemberData(nameof(Sorted_SetWithItems_TestData))] + public void ListBox_Sorted_SetWithItems_GetReturnsExpected(bool value, string[] expected) + { + using var control = new ListBox(); + control.Items.Add("item2"); + control.Items.Add("item1"); + + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Equal(expected, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Equal(expected, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Equal(new string[] { "item1", "item2" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_Sorted_SetWithoutItemsWithHandle_GetReturnsExpected(bool value) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_Sorted_SetWithEmptyItemsWithHandle_GetReturnsExpected(bool value) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + Assert.Empty(control.Items); + + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Empty(control.Items); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(Sorted_SetWithItems_TestData))] + public void ListBox_Sorted_SetWithItemsWithHandle_GetReturnsExpected(bool value, string[] expected) + { + using var control = new ListBox(); + control.Items.Add("item2"); + control.Items.Add("item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Equal(expected, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Sorted = value; + Assert.Equal(value, control.Sorted); + Assert.Equal(expected, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set different. + control.Sorted = !value; + Assert.Equal(!value, control.Sorted); + Assert.Equal(new string[] { "item1", "item2" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] + public void ListBox_Text_Set_GetReturnsExpected(string value, string expected) + { + using var control = new ListBox + { + Text = value + }; + Assert.Equal(expected, control.Text); + Assert.Equal(-1, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(-1, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable Text_SetWithItems_TestData() + { + foreach (bool formattingEnabled in new bool[] { true, false }) + { + yield return new object[] { formattingEnabled, SelectionMode.None, null, string.Empty, -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, string.Empty, string.Empty, -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "NoSuchItem", "NoSuchItem", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "item1", "item1", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "ITEM1", "ITEM1", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "item2", "item2", -1 }; + + foreach (SelectionMode selectionMode in new SelectionMode[] { SelectionMode.MultiExtended, SelectionMode.MultiSimple, SelectionMode.One }) + { + yield return new object[] { formattingEnabled, selectionMode, null, string.Empty, -1 }; + yield return new object[] { formattingEnabled, selectionMode, string.Empty, string.Empty, -1 }; + yield return new object[] { formattingEnabled, selectionMode, "NoSuchItem", "NoSuchItem", -1 }; + yield return new object[] { formattingEnabled, selectionMode, "item1", "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, "ITEM1", "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, "item2", "item2", 1 }; + } + } + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithItems_TestData))] + public void ListBox_Text_SetWithItems_GetReturnsExpected(bool formattingEnabled, SelectionMode selectionMode, string value, string expected, int expectedSelectedIndex) + { + using var control = new ListBox + { + FormattingEnabled = formattingEnabled, + SelectionMode = selectionMode + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expectedSelectedIndex, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expectedSelectedIndex, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable Text_SetWithItemsWithSelection_TestData() + { + foreach (bool formattingEnabled in new bool[] { true, false }) + { + yield return new object[] { formattingEnabled, SelectionMode.None, null, string.Empty, -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, string.Empty, string.Empty, -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "NoSuchItem", "NoSuchItem", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "item1", "item1", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "ITEM1", "ITEM1", -1 }; + yield return new object[] { formattingEnabled, SelectionMode.None, "item2", "item2", -1 }; + + foreach (SelectionMode selectionMode in new SelectionMode[] { SelectionMode.MultiExtended, SelectionMode.MultiSimple, SelectionMode.One }) + { + yield return new object[] { formattingEnabled, selectionMode, null, "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, string.Empty, "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, "NoSuchItem", "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, "item1", "item1", 0 }; + yield return new object[] { formattingEnabled, selectionMode, "ITEM1", "item1", 0 }; + } + + yield return new object[] { formattingEnabled, SelectionMode.MultiExtended, "item2", "item1", 0 }; + yield return new object[] { formattingEnabled, SelectionMode.MultiSimple, "item2", "item1", 0 }; + yield return new object[] { formattingEnabled, SelectionMode.One, "item2", "item2", 1 }; + } + } + + [WinFormsTheory] + [MemberData(nameof(Text_SetWithItemsWithSelection_TestData))] + public void ListBox_Text_SetWithItemsWithSelection_GetReturnsExpected(bool formattingEnabled, SelectionMode selectionMode, string value, string expected, int expectedSelectedIndex) + { + using var control = new ListBox + { + FormattingEnabled = formattingEnabled + }; + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + control.SelectedIndex = 0; + control.SelectionMode = selectionMode; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expectedSelectedIndex, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(expectedSelectedIndex, control.SelectedIndex); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))] + public void ListBox_Text_SetWithHandle_GetReturnsExpected(string value, string expected) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(-1, control.SelectedIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.Text = value; + Assert.Equal(expected, control.Text); + Assert.Equal(-1, control.SelectedIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_Text_SetWithHandler_CallsTextChanged() + { + using var control = new ListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Equal(EventArgs.Empty, e); + callCount++; + }; + control.TextChanged += handler; + + // Set different. + control.Text = "text"; + Assert.Same("text", control.Text); + Assert.Equal(1, callCount); + + // Set same. + control.Text = "text"; + Assert.Same("text", control.Text); + Assert.Equal(1, callCount); + + // Set different. + control.Text = null; + Assert.Empty(control.Text); + Assert.Equal(2, callCount); + + // Remove handler. + control.TextChanged -= handler; + control.Text = "text"; + Assert.Same("text", control.Text); + Assert.Equal(2, callCount); + } + + [WinFormsFact] + public void ListBox_TopIndex_GetWithHandle_ReturnsExpected() + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Equal(0, control.TopIndex); + } + + [WinFormsTheory] + [InlineData(int.MinValue)] + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void ListBox_TopIndex_SetEmpty_GetReturnsExpected(int value) + { + using var control = new ListBox + { + TopIndex = value + }; + Assert.Equal(value, control.TopIndex); + Assert.False(control.IsHandleCreated); + + // Set same. + control.TopIndex = value; + Assert.Equal(value, control.TopIndex); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(int.MinValue)] + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void ListBox_TopIndex_SetNotEmpty_GetReturnsExpected(int value) + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + control.TopIndex = value; + Assert.Equal(value, control.TopIndex); + Assert.False(control.IsHandleCreated); + + // Set same. + control.TopIndex = value; + Assert.Equal(value, control.TopIndex); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(int.MinValue)] + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(int.MaxValue)] + public void ListBox_TopIndex_SetWithHandleEmpty_GetReturnsExpected(int value) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.TopIndex = value; + Assert.Equal(0, control.TopIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.TopIndex = value; + Assert.Equal(0, control.TopIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(int.MinValue)] + [InlineData(-1)] + [InlineData(0)] + [InlineData(1)] + [InlineData(2)] + [InlineData(3)] + [InlineData(int.MaxValue)] + public void ListBox_TopIndex_SetWithHandleNotEmpty_GetReturnsExpected(int value) + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.TopIndex = value; + Assert.Equal(0, control.TopIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Set same. + control.TopIndex = value; + Assert.Equal(0, control.TopIndex); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_TopIndex_GetTopIndex_ReturnsExpected() + { + using var control = new ListBox(); + control.Items.Add("item1"); + control.Items.Add("item2"); + control.Items.Add("item1"); + + Assert.NotEqual(IntPtr.Zero, control.Handle); + control.TopIndex = 1; + Assert.Equal((IntPtr)0, SendMessageW(control.Handle, (WindowMessage)LB.GETTOPINDEX)); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_UseCustomTabOffsets_Set_GetReturnsExpected(bool value) + { + using var control = new ListBox + { + UseCustomTabOffsets = value + }; + Assert.Equal(value, control.UseCustomTabOffsets); + Assert.False(control.IsHandleCreated); + + // Set same. + control.UseCustomTabOffsets = value; + Assert.Equal(value, control.UseCustomTabOffsets); + Assert.False(control.IsHandleCreated); + + // Set different. + control.UseCustomTabOffsets = !value; + Assert.Equal(!value, control.UseCustomTabOffsets); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 1)] + [InlineData(false, 0)] + public void ListBox_UseCustomTabOffsets_SetWithHandle_GetReturnsExpected(bool value, int expectedCreatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.UseCustomTabOffsets = value; + Assert.Equal(value, control.UseCustomTabOffsets); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.UseCustomTabOffsets = value; + Assert.Equal(value, control.UseCustomTabOffsets); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set different. + control.UseCustomTabOffsets = !value; + Assert.Equal(!value, control.UseCustomTabOffsets); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount + 1, createdCallCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))] + public void ListBox_UseTabStops_Set_GetReturnsExpected(bool value) + { + using var control = new ListBox + { + UseTabStops = value + }; + Assert.Equal(value, control.UseTabStops); + Assert.False(control.IsHandleCreated); + + // Set same. + control.UseTabStops = value; + Assert.Equal(value, control.UseTabStops); + Assert.False(control.IsHandleCreated); + + // Set different. + control.UseTabStops = !value; + Assert.Equal(!value, control.UseTabStops); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(true, 0)] + [InlineData(false, 1)] + public void ListBox_UseTabStops_SetWithHandle_GetReturnsExpected(bool value, int expectedCreatedCallCount) + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.UseTabStops = value; + Assert.Equal(value, control.UseTabStops); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set same. + control.UseTabStops = value; + Assert.Equal(value, control.UseTabStops); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount, createdCallCount); + + // Set different. + control.UseTabStops = !value; + Assert.Equal(!value, control.UseTabStops); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(expectedCreatedCallCount + 1, createdCallCount); + } + + [WinFormsFact] + public void ListBox_AddItemsCore_Invoke_Success() + { + using var control = new SubListBox(); + + // Add multiple. + control.AddItemsCore(new object[] { "item1", "item2" }); + Assert.Equal(new string[] { "item1", "item2" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Add another. + control.AddItemsCore(new object[] { "item3" }); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Add empty. + control.AddItemsCore(new object[0]); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + + // Add null. + control.AddItemsCore(null); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_AddItemsCore_InvokeWithHandle_Success() + { + using var control = new SubListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // Add multiple. + control.AddItemsCore(new object[] { "item1", "item2" }); + Assert.Equal(new string[] { "item1", "item2" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Add another. + control.AddItemsCore(new object[] { "item3" }); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Add empty. + control.AddItemsCore(new object[0]); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Add null. + control.AddItemsCore(null); + Assert.Equal(new string[] { "item1", "item2", "item3" }, control.Items.Cast()); + Assert.True(control.IsHandleCreated); + Assert.Equal(2, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_BeginUpdate_InvokeWithoutHandle_Nop() + { + using var control = new ListBox(); + control.BeginUpdate(); + Assert.False(control.IsHandleCreated); + + // Call again. + control.BeginUpdate(); + Assert.False(control.IsHandleCreated); + + // End once. + control.EndUpdate(); + Assert.False(control.IsHandleCreated); + + // End twice. + control.EndUpdate(); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_BeginUpdate_InvokeWithHandle_Nop() + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + control.BeginUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Call again. + control.BeginUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // End once. + control.EndUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // End twice. + control.EndUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_EndUpdate_InvokeWithoutHandle_Success() + { + using var control = new ListBox(); + + // End without beginning. + control.EndUpdate(); + Assert.False(control.IsHandleCreated); + + // Begin. + control.BeginUpdate(); + Assert.False(control.IsHandleCreated); + + // End. + control.EndUpdate(); + Assert.False(control.IsHandleCreated); + + // End again. + control.EndUpdate(); + Assert.False(control.IsHandleCreated); + } + + [WinFormsFact] + public void ListBox_EndUpdate_InvokeWithHandle_Success() + { + using var control = new ListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + // End without beginning. + control.EndUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Begin. + control.BeginUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // End. + control.EndUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // End again. + control.EndUpdate(); + Assert.True(control.IsHandleCreated); + Assert.Equal(1, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsFact] + public void ListBox_CreateAccessibilityInstance_Invoke_ReturnsExpected() + { + using var control = new SubListBox(); + Control.ControlAccessibleObject instance = Assert.IsAssignableFrom(control.CreateAccessibilityInstance()); + Assert.NotNull(instance); + Assert.Same(control, instance.Owner); + Assert.Equal(AccessibleRole.List, instance.Role); + Assert.NotSame(control.CreateAccessibilityInstance(), instance); + Assert.NotSame(control.AccessibilityObject, instance); + } + + [WinFormsFact] + public void ListBox_CreateControlsInstance_Invoke_ReturnsExpected() + { + using var control = new SubListBox(); + ListBox.ObjectCollection items = Assert.IsType(control.CreateItemCollection()); + Assert.Empty(items); + Assert.False(items.IsReadOnly); + Assert.NotSame(items, control.CreateItemCollection()); + } + + [WinFormsFact] + public void ListBox_GetAutoSizeMode_Invoke_ReturnsExpected() + { + using var control = new SubListBox(); + Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode()); + } + + public static IEnumerable GetPreferredSize_TestData() + { + foreach (BorderStyle borderStyle in Enum.GetValues(typeof(BorderStyle))) + { + yield return new object[] { borderStyle, Size.Empty }; + yield return new object[] { borderStyle, new Size(-1, -2) }; + yield return new object[] { borderStyle, new Size(10, 20) }; + yield return new object[] { borderStyle, new Size(30, 40) }; + yield return new object[] { borderStyle, new Size(int.MaxValue, int.MaxValue) }; + } + } + + [WinFormsTheory] + [MemberData(nameof(GetPreferredSize_TestData))] + public void ListBox_GetPreferredSize_Invoke_ReturnsExpected(BorderStyle borderStyle, Size proposedSize) + { + using var control = new ListBox + { + BorderStyle = borderStyle + }; + Assert.Equal(new Size(120, 96), control.GetPreferredSize(proposedSize)); + Assert.False(control.IsHandleCreated); + + // Call again. + Assert.Equal(new Size(120, 96), control.GetPreferredSize(proposedSize)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(GetPreferredSize_TestData))] + public void ListBox_GetPreferredSize_InvokeWithPadding_ReturnsExpected(BorderStyle borderStyle, Size proposedSize) + { + using var control = new ListBox + { + BorderStyle = borderStyle, + Padding = new Padding(1, 2, 3, 4) + }; + Assert.Equal(new Size(120, 96), control.GetPreferredSize(proposedSize)); + Assert.False(control.IsHandleCreated); + + // Call again. + Assert.Equal(new Size(120, 96), control.GetPreferredSize(proposedSize)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [MemberData(nameof(GetPreferredSize_TestData))] + public void ListBox_GetPreferredSize_InvokeWithHandle_ReturnsExpected(BorderStyle borderStyle, Size proposedSize) + { + using var control = new ListBox + { + BorderStyle = borderStyle + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Size result = control.GetPreferredSize(proposedSize); + Assert.True(result.Width > 0 && result.Width < 120); + Assert.Equal(control.PreferredHeight, result.Height); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Call again. + Assert.Equal(result, control.GetPreferredSize(proposedSize)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(GetPreferredSize_TestData))] + public void ListBox_GetPreferredSize_InvokeWithHandleWithPadding_ReturnsExpected(BorderStyle borderStyle, Size proposedSize) + { + using var control = new ListBox + { + BorderStyle = borderStyle, + Padding = new Padding(1, 2, 3, 4) + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Size result = control.GetPreferredSize(proposedSize); + Assert.True(result.Width > 0 && result.Width < 120); + Assert.Equal(control.PreferredHeight + 6, result.Height); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Call again. + Assert.Equal(result, control.GetPreferredSize(proposedSize)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [InlineData(ControlStyles.ContainerControl, false)] + [InlineData(ControlStyles.UserPaint, false)] + [InlineData(ControlStyles.Opaque, false)] + [InlineData(ControlStyles.ResizeRedraw, false)] + [InlineData(ControlStyles.FixedWidth, false)] + [InlineData(ControlStyles.FixedHeight, false)] + [InlineData(ControlStyles.StandardClick, false)] + [InlineData(ControlStyles.Selectable, true)] + [InlineData(ControlStyles.UserMouse, false)] + [InlineData(ControlStyles.SupportsTransparentBackColor, false)] + [InlineData(ControlStyles.StandardDoubleClick, true)] + [InlineData(ControlStyles.AllPaintingInWmPaint, true)] + [InlineData(ControlStyles.CacheText, false)] + [InlineData(ControlStyles.EnableNotifyMessage, false)] + [InlineData(ControlStyles.DoubleBuffer, false)] + [InlineData(ControlStyles.OptimizedDoubleBuffer, false)] + [InlineData(ControlStyles.UseTextForAccessibility, false)] + [InlineData((ControlStyles)0, true)] + [InlineData((ControlStyles)int.MaxValue, false)] + [InlineData((ControlStyles)(-1), false)] + public void ListBox_GetStyle_Invoke_ReturnsExpected(ControlStyles flag, bool expected) + { + using var control = new SubListBox(); + Assert.Equal(expected, control.GetStyle(flag)); + + // Call again to test caching. + Assert.Equal(expected, control.GetStyle(flag)); + } + + public static IEnumerable FindString_TestData() + { + foreach (int startIndex in new int[] { -2, -1, 0, 1 }) + { + yield return new object[] { new ListBox(), null, startIndex, -1 }; + yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; + yield return new object[] { new ListBox(), "s", startIndex, -1 }; + + using var controlWithNoItems = new ListBox(); + Assert.Empty(controlWithNoItems.Items); + yield return new object[] { new ListBox(), null, startIndex, -1 }; + yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; + yield return new object[] { new ListBox(), "s", startIndex, -1 }; + } + + using var controlWithItems = new ListBox + { + DisplayMember = "Value" + }; + controlWithItems.Items.Add(new DataClass { Value = "abc" }); + controlWithItems.Items.Add(new DataClass { Value = "abc" }); + controlWithItems.Items.Add(new DataClass { Value = "ABC" }); + controlWithItems.Items.Add(new DataClass { Value = "def" }); + controlWithItems.Items.Add(new DataClass { Value = "" }); + controlWithItems.Items.Add(new DataClass { Value = null }); + + yield return new object[] { controlWithItems, "abc", -1, 0 }; + yield return new object[] { controlWithItems, "abc", 0, 1 }; + yield return new object[] { controlWithItems, "abc", 1, 2 }; + yield return new object[] { controlWithItems, "abc", 2, 0 }; + yield return new object[] { controlWithItems, "abc", 5, 0 }; + + yield return new object[] { controlWithItems, "ABC", -1, 0 }; + yield return new object[] { controlWithItems, "ABC", 0, 1 }; + yield return new object[] { controlWithItems, "ABC", 1, 2 }; + yield return new object[] { controlWithItems, "ABC", 2, 0 }; + yield return new object[] { controlWithItems, "ABC", 5, 0 }; + + yield return new object[] { controlWithItems, "a", -1, 0 }; + yield return new object[] { controlWithItems, "a", 0, 1 }; + yield return new object[] { controlWithItems, "a", 1, 2 }; + yield return new object[] { controlWithItems, "a", 2, 0 }; + yield return new object[] { controlWithItems, "a", 5, 0 }; + + yield return new object[] { controlWithItems, "A", -1, 0 }; + yield return new object[] { controlWithItems, "A", 0, 1 }; + yield return new object[] { controlWithItems, "A", 1, 2 }; + yield return new object[] { controlWithItems, "A", 2, 0 }; + yield return new object[] { controlWithItems, "A", 5, 0 }; + + yield return new object[] { controlWithItems, "abcd", -1, -1 }; + yield return new object[] { controlWithItems, "abcd", 0, -1 }; + yield return new object[] { controlWithItems, "abcd", 1, -1 }; + yield return new object[] { controlWithItems, "abcd", 2, -1 }; + yield return new object[] { controlWithItems, "abcd", 5, -1 }; + + yield return new object[] { controlWithItems, "def", -1, 3 }; + yield return new object[] { controlWithItems, "def", 0, 3 }; + yield return new object[] { controlWithItems, "def", 1, 3 }; + yield return new object[] { controlWithItems, "def", 2, 3 }; + yield return new object[] { controlWithItems, "def", 5, 3 }; + + yield return new object[] { controlWithItems, null, -1, -1 }; + yield return new object[] { controlWithItems, null, 0, -1 }; + yield return new object[] { controlWithItems, null, 1, -1 }; + yield return new object[] { controlWithItems, null, 2, -1 }; + yield return new object[] { controlWithItems, null, 5, -1 }; + + yield return new object[] { controlWithItems, string.Empty, -1, 0 }; + yield return new object[] { controlWithItems, string.Empty, 0, 1 }; + yield return new object[] { controlWithItems, string.Empty, 1, 2 }; + yield return new object[] { controlWithItems, string.Empty, 2, 3 }; + yield return new object[] { controlWithItems, string.Empty, 5, 0 }; + + yield return new object[] { controlWithItems, "NoSuchItem", -1, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 0, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 1, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 2, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 5, -1 }; + } + + [WinFormsTheory] + [MemberData(nameof(FindString_TestData))] + public void ListBox_FindString_Invoke_ReturnsExpected(ListBox control, string s, int startIndex, int expected) + { + if (startIndex == -1) + { + Assert.Equal(expected, control.FindString(s)); + } + + Assert.Equal(expected, control.FindString(s, startIndex)); + } + + [WinFormsTheory] + [InlineData(-2)] + [InlineData(1)] + [InlineData(2)] + public void ListBox_FindString_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + { + using var control = new ListBox(); + control.Items.Add("item"); + Assert.Throws("startIndex", () => control.FindString("s", startIndex)); + } + + public static IEnumerable FindStringExact_TestData() + { + foreach (int startIndex in new int[] { -2, -1, 0, 1 }) + { + yield return new object[] { new ListBox(), null, startIndex, -1 }; + yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; + yield return new object[] { new ListBox(), "s", startIndex, -1 }; + + using var controlWithNoItems = new ListBox(); + Assert.Empty(controlWithNoItems.Items); + yield return new object[] { new ListBox(), null, startIndex, -1 }; + yield return new object[] { new ListBox(), string.Empty, startIndex, -1 }; + yield return new object[] { new ListBox(), "s", startIndex, -1 }; + } + + using var controlWithItems = new ListBox + { + DisplayMember = "Value" + }; + controlWithItems.Items.Add(new DataClass { Value = "abc" }); + controlWithItems.Items.Add(new DataClass { Value = "abc" }); + controlWithItems.Items.Add(new DataClass { Value = "ABC" }); + controlWithItems.Items.Add(new DataClass { Value = "def" }); + controlWithItems.Items.Add(new DataClass { Value = "" }); + controlWithItems.Items.Add(new DataClass { Value = null }); + + yield return new object[] { controlWithItems, "abc", -1, 0 }; + yield return new object[] { controlWithItems, "abc", 0, 1 }; + yield return new object[] { controlWithItems, "abc", 1, 2 }; + yield return new object[] { controlWithItems, "abc", 2, 0 }; + yield return new object[] { controlWithItems, "abc", 5, 0 }; + + yield return new object[] { controlWithItems, "ABC", -1, 0 }; + yield return new object[] { controlWithItems, "ABC", 0, 1 }; + yield return new object[] { controlWithItems, "ABC", 1, 2 }; + yield return new object[] { controlWithItems, "ABC", 2, 0 }; + yield return new object[] { controlWithItems, "ABC", 5, 0 }; + + yield return new object[] { controlWithItems, "a", -1, -1 }; + yield return new object[] { controlWithItems, "a", 0, -1 }; + yield return new object[] { controlWithItems, "a", 1, -1 }; + yield return new object[] { controlWithItems, "a", 2, -1 }; + yield return new object[] { controlWithItems, "a", 5, -1 }; + + yield return new object[] { controlWithItems, "A", -1, -1 }; + yield return new object[] { controlWithItems, "A", 0, -1 }; + yield return new object[] { controlWithItems, "A", 1, -1 }; + yield return new object[] { controlWithItems, "A", 2, -1 }; + yield return new object[] { controlWithItems, "A", 5, -1 }; + + yield return new object[] { controlWithItems, "abcd", -1, -1 }; + yield return new object[] { controlWithItems, "abcd", 0, -1 }; + yield return new object[] { controlWithItems, "abcd", 1, -1 }; + yield return new object[] { controlWithItems, "abcd", 2, -1 }; + yield return new object[] { controlWithItems, "abcd", 5, -1 }; + + yield return new object[] { controlWithItems, "def", -1, 3 }; + yield return new object[] { controlWithItems, "def", 0, 3 }; + yield return new object[] { controlWithItems, "def", 1, 3 }; + yield return new object[] { controlWithItems, "def", 2, 3 }; + yield return new object[] { controlWithItems, "def", 5, 3 }; + + yield return new object[] { controlWithItems, null, -1, -1 }; + yield return new object[] { controlWithItems, null, 0, -1 }; + yield return new object[] { controlWithItems, null, 1, -1 }; + yield return new object[] { controlWithItems, null, 2, -1 }; + yield return new object[] { controlWithItems, null, 5, -1 }; + + yield return new object[] { controlWithItems, string.Empty, -1, 4 }; + yield return new object[] { controlWithItems, string.Empty, 0, 4 }; + yield return new object[] { controlWithItems, string.Empty, 1, 4 }; + yield return new object[] { controlWithItems, string.Empty, 2, 4 }; + yield return new object[] { controlWithItems, string.Empty, 5, 4 }; + + yield return new object[] { controlWithItems, "NoSuchItem", -1, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 0, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 1, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 2, -1 }; + yield return new object[] { controlWithItems, "NoSuchItem", 5, -1 }; + } + + [WinFormsTheory] + [MemberData(nameof(FindStringExact_TestData))] + public void ListBox_FindStringExact_Invoke_ReturnsExpected(ListBox control, string s, int startIndex, int expected) + { + if (startIndex == -1) + { + Assert.Equal(expected, control.FindStringExact(s)); + } + + Assert.Equal(expected, control.FindStringExact(s, startIndex)); + } + + [WinFormsTheory] + [InlineData(-2)] + [InlineData(1)] + [InlineData(2)] + public void ListBox_FindStringExact_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + { + using var control = new ListBox(); + control.Items.Add("item"); + Assert.Throws("startIndex", () => control.FindStringExact("s", startIndex)); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEnumTypeTheoryData), typeof(DrawMode))] + public void ListBox_GetItemHeight_InvokeEmptyWithoutHandle_ReturnsExpected(DrawMode drawMode) + { + using var control = new ListBox + { + DrawMode = drawMode + }; + Assert.Equal(13, control.GetItemHeight(0)); + Assert.False(control.IsHandleCreated); + } + + public static IEnumerable GetItemHeight_NotEmpty_TestData() + { + foreach (DrawMode drawMode in Enum.GetValues(typeof(DrawMode))) + { + yield return new object[] { drawMode, 0 }; + yield return new object[] { drawMode, 1 }; + } + } + + [WinFormsTheory] + [MemberData(nameof(GetItemHeight_NotEmpty_TestData))] + public void ListBox_GetItemHeight_InvokeNotEmptyWithoutHandle_ReturnsExpected(DrawMode drawMode, int index) + { + using var control = new ListBox + { + DrawMode = drawMode + }; + control.Items.Add("Item1"); + control.Items.Add("Item2"); + Assert.Equal(13, control.GetItemHeight(index)); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [InlineData(DrawMode.Normal)] + [InlineData(DrawMode.OwnerDrawFixed)] + [InlineData(DrawMode.OwnerDrawVariable)] + public void ListBox_GetItemHeight_InvokeEmptyWithHandle_ReturnsExpected(DrawMode drawMode) + { + using var control = new ListBox + { + DrawMode = drawMode + }; + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.True(control.GetItemHeight(0) > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + [WinFormsTheory] + [MemberData(nameof(GetItemHeight_NotEmpty_TestData))] + public void ListBox_GetItemHeight_InvokeNotEmptyWithHandle_ReturnsExpected(DrawMode drawMode, int index) + { + using var control = new ListBox + { + DrawMode = drawMode + }; + control.Items.Add("Item1"); + control.Items.Add("Item2"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + + Assert.True(control.GetItemHeight(index) > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable GetItemHeight_CustomGetItemHeight_TestData() + { + yield return new object[] { DrawMode.Normal, 0, 0, 0, 0 }; + yield return new object[] { DrawMode.Normal, 1, 0, -2, -2 }; + yield return new object[] { DrawMode.Normal, 0, 0, 10, 10 }; + yield return new object[] { DrawMode.OwnerDrawFixed, 0, 0, 0, 0 }; + yield return new object[] { DrawMode.OwnerDrawFixed, 1, 0, -2, -2 }; + yield return new object[] { DrawMode.OwnerDrawFixed, 0, 0, 10, 10 }; + yield return new object[] { DrawMode.OwnerDrawVariable, 0, 0, 0, 0 }; + yield return new object[] { DrawMode.OwnerDrawVariable, 1, 1, -2, -2 }; + yield return new object[] { DrawMode.OwnerDrawVariable, 0, 0, 10, 10 }; + } + + [WinFormsTheory] + [MemberData(nameof(GetItemHeight_CustomGetItemHeight_TestData))] + public void ListBox_GetItemHeight_InvokeCustomGetItemHeight_ReturnsExpected(DrawMode drawMode, int index, int expectedIndex, int getItemRectResult, int expected) + { + using var control = new CustomGetItemHeightListBox + { + DrawMode = drawMode, + ExpectedIndex = expectedIndex, + GetItemHeightResult = (IntPtr)getItemRectResult + }; + control.Items.Add("Item1"); + control.Items.Add("Item2"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + control.MakeCustom = true; + Assert.Equal(expected, control.GetItemHeight(index)); + } + + private class CustomGetItemHeightListBox : ListBox + { + public bool MakeCustom { get; set; } + public int ExpectedIndex { get; set; } + public IntPtr GetItemHeightResult { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (MakeCustom && m.Msg == (int)LB.GETITEMHEIGHT) + { + Assert.Equal(ExpectedIndex, (int)m.WParam); + m.Result = GetItemHeightResult; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsFact] + public void ListBox_GetItemHeight_InvokeInvalidGetItemHeight_ThrowsWin32Exception() + { + using var control = new InvalidGetItemHeightListBox(); + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + control.MakeInvalid = true; + Assert.Throws(() => control.GetItemHeight(0)); + } + + private class InvalidGetItemHeightListBox : ListBox + { + public bool MakeInvalid { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (MakeInvalid && m.Msg == (int)LB.GETITEMHEIGHT) + { + m.Result = (IntPtr)(-1); + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsTheory] + [InlineData(-1)] + [InlineData(1)] + public void ListBox_GetItemHeight_InvalidIndexEmpty_ThrowsArgumentOutOfRangeException(int index) + { + using var control = new ListBox(); + Assert.Throws("index", () => control.GetItemHeight(index)); + } + + [WinFormsTheory] + [InlineData(-1)] + [InlineData(1)] + [InlineData(2)] + public void ListBox_GetItemHeight_InvalidIndexNotEmpty_ThrowsArgumentOutOfRangeException(int index) + { + using var control = new ListBox(); + control.Items.Add("Item"); + Assert.Throws("index", () => control.GetItemHeight(index)); + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvokeWithoutHandle_ReturnsExpectedAndCreatedHandle() + { + using var control = new ListBox(); + control.Items.Add("Item1"); + control.Items.Add("Item1"); + + Rectangle rect1 = control.GetItemRectangle(0); + Assert.True(rect1.X >= 0); + Assert.True(rect1.Y >= 0); + Assert.True(rect1.Width > 0); + Assert.True(rect1.Height > 0); + Assert.Equal(rect1, control.GetItemRectangle(0)); + Assert.True(control.IsHandleCreated); + + Rectangle rect2 = control.GetItemRectangle(1); + Assert.Equal(rect2.X, rect1.X); + Assert.True(rect2.Y >= rect1.Y + rect1.Height); + Assert.True(rect2.Width > 0); + Assert.True(rect2.Height > 0); + Assert.True(control.IsHandleCreated); + } - yield return new object[] { controlWithItems, null, -1, -1 }; - yield return new object[] { controlWithItems, null, 0, -1 }; - yield return new object[] { controlWithItems, null, 1, -1 }; - yield return new object[] { controlWithItems, null, 2, -1 }; - yield return new object[] { controlWithItems, null, 5, -1 }; + [WinFormsFact] + public void ListBox_GetItemRectangle_InvokeWithHandle_ReturnsExpected() + { + using var control = new ListBox(); + control.Items.Add("Item1"); + control.Items.Add("Item1"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; - yield return new object[] { controlWithItems, string.Empty, -1, 4 }; - yield return new object[] { controlWithItems, string.Empty, 0, 4 }; - yield return new object[] { controlWithItems, string.Empty, 1, 4 }; - yield return new object[] { controlWithItems, string.Empty, 2, 4 }; - yield return new object[] { controlWithItems, string.Empty, 5, 4 }; + Rectangle rect1 = control.GetItemRectangle(0); + Assert.True(rect1.X >= 0); + Assert.True(rect1.Y >= 0); + Assert.True(rect1.Width > 0); + Assert.True(rect1.Height > 0); + Assert.Equal(rect1, control.GetItemRectangle(0)); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + Rectangle rect2 = control.GetItemRectangle(1); + Assert.Equal(rect2.X, rect1.X); + Assert.True(rect2.Y >= rect1.Y + rect1.Height); + Assert.True(rect2.Width > 0); + Assert.True(rect2.Height > 0); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } + + public static IEnumerable GetItemRectangle_CustomGetItemRect_TestData() + { + yield return new object[] { new RECT(), Rectangle.Empty }; + yield return new object[] { new RECT(1, 2, 3, 4), new Rectangle(1, 2, 2, 2) }; + } + + [WinFormsTheory] + [MemberData(nameof(GetItemRectangle_CustomGetItemRect_TestData))] + public void ListBox_GetItemRectangle_InvokeCustomGetItemRect_ReturnsExpected(object getItemRectResult, Rectangle expected) + { + using var control = new CustomGetItemRectListBox + { + GetItemRectResult = (RECT)getItemRectResult + }; + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Equal(expected, control.GetItemRectangle(0)); + } + + private class CustomGetItemRectListBox : ListBox + { + public RECT GetItemRectResult { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (m.Msg == (int)LB.GETITEMRECT) + { + RECT* pRect = (RECT*)m.LParam; + *pRect = GetItemRectResult; + m.Result = (IntPtr)1; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvokeInvalidGetItemRect_ReturnsExpected() + { + using var control = new InvalidGetItemRectListBox(); + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + control.MakeInvalid = true; + Assert.Equal(Rectangle.Empty, control.GetItemRectangle(0)); + } + + private class InvalidGetItemRectListBox : ListBox + { + public bool MakeInvalid { get; set; } + + protected unsafe override void WndProc(ref Message m) + { + if (MakeInvalid && m.Msg == (int)LB.GETITEMRECT) + { + RECT* pRect = (RECT*)m.LParam; + *pRect = new RECT(1, 2, 3, 4); + m.Result = IntPtr.Zero; + return; + } + + base.WndProc(ref m); + } + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvalidIndexEmpty_ThrowsArgumentOutOfRangeException() + { + using var control = new ListBox(); + Assert.Throws("index", () => control.GetItemRectangle(-1)); + Assert.Throws("index", () => control.GetItemRectangle(0)); + Assert.Throws("index", () => control.GetItemRectangle(1)); + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvalidIndexNotEmpty_ThrowsArgumentOutOfRangeException() + { + using var control = new ListBox(); + control.Items.Add("Item"); + + Assert.Throws("index", () => control.GetItemRectangle(-1)); + Assert.Throws("index", () => control.GetItemRectangle(1)); + Assert.Throws("index", () => control.GetItemRectangle(2)); + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvalidIndexWithHandleEmpty_ThrowsArgumentOutOfRangeException() + { + using var control = new ListBox(); + Assert.Throws("index", () => control.GetItemRectangle(-1)); + Assert.Throws("index", () => control.GetItemRectangle(0)); + Assert.Throws("index", () => control.GetItemRectangle(1)); + } + + [WinFormsFact] + public void ListBox_GetItemRectangle_InvalidIndexWithHandleNotEmpty_ThrowsArgumentOutOfRangeException() + { + using var control = new ListBox(); + control.Items.Add("Item"); + Assert.NotEqual(IntPtr.Zero, control.Handle); + + Assert.Throws("index", () => control.GetItemRectangle(-1)); + Assert.Throws("index", () => control.GetItemRectangle(1)); + Assert.Throws("index", () => control.GetItemRectangle(2)); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnClick_Invoke_CallsClick(EventArgs eventArgs) + { + using var control = new SubListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.Click += handler; + control.OnClick(eventArgs); + Assert.Equal(1, callCount); + + // Remove handler. + control.Click -= handler; + control.OnClick(eventArgs); + Assert.Equal(1, callCount); + } + + public static IEnumerable OnDrawItem_TestData() + { + using var bitmap = new Bitmap(10, 10); + using Graphics graphics = Graphics.FromImage(bitmap); + yield return new object[] { null }; + yield return new object[] { new DrawItemEventArgs(graphics, null, new Rectangle(1, 2, 3, 4), 0, DrawItemState.Checked) }; + } + + [WinFormsTheory] + [MemberData(nameof(OnDrawItem_TestData))] + public void ListBox_OnDrawItem_Invoke_CallsDrawItem(DrawItemEventArgs eventArgs) + { + using var control = new SubListBox(); + int callCount = 0; + void handler(object sender, DrawItemEventArgs e) + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + } + + // Call with handler. + control.DrawItem += handler; + control.OnDrawItem(eventArgs); + Assert.Equal(1, callCount); + + // Remove handler. + control.DrawItem -= handler; + control.OnDrawItem(eventArgs); + Assert.Equal(1, callCount); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnFontChanged_Invoke_CallsFontChanged(EventArgs eventArgs) + { + using var control = new SubListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.FontChanged += handler; + control.OnFontChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(96, control.Height); + + // Remove handler. + control.FontChanged -= handler; + control.OnFontChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(96, control.Height); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnGotFocus_Invoke_CallsGotFocus(EventArgs eventArgs) + { + using var control = new SubListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.GotFocus += handler; + control.OnGotFocus(eventArgs); + Assert.Equal(1, callCount); + Assert.False(control.IsHandleCreated); + + // Remove handler. + control.GotFocus -= handler; + control.OnGotFocus(eventArgs); + Assert.Equal(1, callCount); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnGotFocus_InvokeWithHandle_CallsGotFocus(EventArgs eventArgs) + { + using var control = new SubListBox(); + Assert.NotEqual(IntPtr.Zero, control.Handle); + int invalidatedCallCount = 0; + control.Invalidated += (sender, e) => invalidatedCallCount++; + int styleChangedCallCount = 0; + control.StyleChanged += (sender, e) => styleChangedCallCount++; + int createdCallCount = 0; + control.HandleCreated += (sender, e) => createdCallCount++; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.GotFocus += handler; + control.OnGotFocus(eventArgs); + Assert.Equal(1, callCount); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + + // Remove handler. + control.GotFocus -= handler; + control.OnGotFocus(eventArgs); + Assert.True(control.IsHandleCreated); + Assert.Equal(0, invalidatedCallCount); + Assert.Equal(0, styleChangedCallCount); + Assert.Equal(0, createdCallCount); + } - yield return new object[] { controlWithItems, "NoSuchItem", -1, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 0, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 1, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 2, -1 }; - yield return new object[] { controlWithItems, "NoSuchItem", 5, -1 }; + public static IEnumerable OnMeasureItem_TestData() + { + using var bitmap = new Bitmap(10, 10); + using Graphics graphics = Graphics.FromImage(bitmap); + yield return new object[] { null }; + yield return new object[] { new MeasureItemEventArgs(graphics, 0, 0) }; } - [Theory] - [MemberData(nameof(FindStringExact_TestData))] - public void FindStringExact_Invoke_ReturnsExpected(ListBox control, string s, int startIndex, int expected) + [WinFormsTheory] + [MemberData(nameof(OnMeasureItem_TestData))] + public void ListBox_OnMeasureItem_Invoke_CallsMeasureItem(MeasureItemEventArgs eventArgs) { - if (startIndex == -1) + using var control = new SubListBox(); + int callCount = 0; + void handler(object sender, MeasureItemEventArgs e) { - Assert.Equal(expected, control.FindStringExact(s)); + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; } - Assert.Equal(expected, control.FindStringExact(s, startIndex)); + // Call with handler. + control.MeasureItem += handler; + control.OnMeasureItem(eventArgs); + Assert.Equal(1, callCount); + + // Remove handler. + control.MeasureItem -= handler; + control.OnMeasureItem(eventArgs); + Assert.Equal(1, callCount); } - [Theory] - [InlineData(-2)] - [InlineData(1)] - [InlineData(2)] - public void FindStringExact_InvalidStartIndex_ThrowsArgumentOutOfRangeException(int startIndex) + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetMouseEventArgsTheoryData))] + public void ListBox_OnMouseClick_Invoke_CallsMouseClick(MouseEventArgs eventArgs) { - var control = new ListBox(); - control.Items.Add("item"); - Assert.Throws("startIndex", () => control.FindStringExact("s", startIndex)); + using var control = new SubListBox(); + int callCount = 0; + MouseEventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; + + // Call with handler. + control.MouseClick += handler; + control.OnMouseClick(eventArgs); + Assert.Equal(1, callCount); + + // Remove handler. + control.MouseClick -= handler; + control.OnMouseClick(eventArgs); + Assert.Equal(1, callCount); } - [WinFormsFact] - public void ListBox_GetItemRectangle_InvokeWithoutHandle_ReturnsExpectedAndCreatedHandle() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetPaintEventArgsTheoryData))] + public void ListBox_OnPaint_Invoke_CallsPaint(PaintEventArgs eventArgs) { - using var control = new ListBox(); - control.Items.Add("Item1"); - control.Items.Add("Item1"); + using var control = new SubListBox(); + int callCount = 0; + PaintEventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; - Rectangle rect1 = control.GetItemRectangle(0); - Assert.True(rect1.X >= 0); - Assert.True(rect1.Y >= 0); - Assert.True(rect1.Width > 0); - Assert.True(rect1.Height > 0); - Assert.Equal(rect1, control.GetItemRectangle(0)); - Assert.True(control.IsHandleCreated); + // Call with handler. + control.Paint += handler; + control.OnPaint(eventArgs); + Assert.Equal(1, callCount); - Rectangle rect2 = control.GetItemRectangle(1); - Assert.Equal(rect2.X, rect1.X); - Assert.True(rect2.Y >= rect1.Y + rect1.Height); - Assert.True(rect2.Width > 0); - Assert.True(rect2.Height > 0); - Assert.True(control.IsHandleCreated); + // Remove handler. + control.Paint -= handler; + control.OnPaint(eventArgs); + Assert.Equal(1, callCount); } - [WinFormsFact] - public void ListBox_GetItemRectangle_InvokeWithHandle_ReturnsExpected() + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnSelectedIndexChanged_Invoke_CallsSelectedIndexChanged(EventArgs eventArgs) { - using var control = new ListBox(); - control.Items.Add("Item1"); - control.Items.Add("Item1"); + using var control = new SubListBox(); + int selectedValueChangedCallCount = 0; + control.SelectedValueChanged += (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + selectedValueChangedCallCount++; + }; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + Assert.True(callCount < selectedValueChangedCallCount); + callCount++; + }; + + // Call with handler. + control.SelectedIndexChanged += handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(1, selectedValueChangedCallCount); + Assert.False(control.IsHandleCreated); + + // Remove handler. + control.SelectedIndexChanged -= handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(2, selectedValueChangedCallCount); + Assert.False(control.IsHandleCreated); + } + + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnSelectedIndexChanged_InvokeWithHandle_CallsSelectedIndexChanged(EventArgs eventArgs) + { + using var control = new SubListBox(); Assert.NotEqual(IntPtr.Zero, control.Handle); int invalidatedCallCount = 0; control.Invalidated += (sender, e) => invalidatedCallCount++; @@ -1036,135 +5684,191 @@ public void ListBox_GetItemRectangle_InvokeWithHandle_ReturnsExpected() control.StyleChanged += (sender, e) => styleChangedCallCount++; int createdCallCount = 0; control.HandleCreated += (sender, e) => createdCallCount++; + int selectedValueChangedCallCount = 0; + control.SelectedValueChanged += (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + selectedValueChangedCallCount++; + }; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + Assert.True(callCount < selectedValueChangedCallCount); + callCount++; + }; - Rectangle rect1 = control.GetItemRectangle(0); - Assert.True(rect1.X >= 0); - Assert.True(rect1.Y >= 0); - Assert.True(rect1.Width > 0); - Assert.True(rect1.Height > 0); - Assert.Equal(rect1, control.GetItemRectangle(0)); + // Call with handler. + control.SelectedIndexChanged += handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(1, selectedValueChangedCallCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); - Rectangle rect2 = control.GetItemRectangle(1); - Assert.Equal(rect2.X, rect1.X); - Assert.True(rect2.Y >= rect1.Y + rect1.Height); - Assert.True(rect2.Width > 0); - Assert.True(rect2.Height > 0); + // Remove handler. + control.SelectedIndexChanged -= handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(2, selectedValueChangedCallCount); Assert.True(control.IsHandleCreated); Assert.Equal(0, invalidatedCallCount); Assert.Equal(0, styleChangedCallCount); Assert.Equal(0, createdCallCount); } - public static IEnumerable GetItemRectangle_CustomGetItemRect_TestData() + public static IEnumerable OnSelectedIndexChanged_WithDataManager_TestData() { - yield return new object[] { new RECT(), Rectangle.Empty }; - yield return new object[] { new RECT(1, 2, 3, 4), new Rectangle(1, 2, 2, 2) }; + foreach (bool formattingEnabled in new bool[] { true, false }) + { + foreach (int position in new int[] { 0, 1 }) + { + yield return new object[] { formattingEnabled, position, null }; + yield return new object[] { formattingEnabled, position, new EventArgs() }; + } + } } [WinFormsTheory] - [MemberData(nameof(GetItemRectangle_CustomGetItemRect_TestData))] - public void ListBox_GetItemRectangle_InvokeCustomGetItemRect_ReturnsExpected(object getItemRectResult, Rectangle expected) + [MemberData(nameof(OnSelectedIndexChanged_WithDataManager_TestData))] + public void ListBox_OnSelectedIndexChanged_InvokeWithDataManager_CallsSelectedIndexChanged(bool formattingEnabled, int position, EventArgs eventArgs) { - using var control = new CustomGetItemRectListBox + var bindingContext = new BindingContext(); + var dataSource = new List { "item1", "item2", "item3" }; + using var control = new SubListBox { - GetItemRectResult = (RECT)getItemRectResult + BindingContext = bindingContext, + DataSource = dataSource, + FormattingEnabled = formattingEnabled + }; + control.DataManager.Position = position; + int selectedValueChangedCallCount = 0; + control.SelectedValueChanged += (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + selectedValueChangedCallCount++; + }; + int callCount = 0; + EventHandler handler = (sender, e) => + { + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + Assert.True(callCount < selectedValueChangedCallCount); + callCount++; }; - control.Items.Add("Item"); - Assert.NotEqual(IntPtr.Zero, control.Handle); - Assert.Equal(expected, control.GetItemRectangle(0)); + // Call with handler. + control.SelectedIndexChanged += handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(1, selectedValueChangedCallCount); + Assert.Equal(position, control.DataManager.Position); + + // Remove handler. + control.SelectedIndexChanged -= handler; + control.OnSelectedIndexChanged(eventArgs); + Assert.Equal(1, callCount); + Assert.Equal(2, selectedValueChangedCallCount); + Assert.Equal(position, control.DataManager.Position); } - private class CustomGetItemRectListBox : ListBox + [WinFormsTheory] + [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))] + public void ListBox_OnSelectedValueChanged_Invoke_CallsSelectedValueChanged(EventArgs eventArgs) { - public RECT GetItemRectResult { get; set; } - - protected unsafe override void WndProc(ref Message m) + using var control = new SubListBox(); + int callCount = 0; + EventHandler handler = (sender, e) => { - if (m.Msg == (int)User32.LB.GETITEMRECT) - { - RECT* pRect = (RECT*)m.LParam; - *pRect = GetItemRectResult; - m.Result = (IntPtr)1; - return; - } + Assert.Same(control, sender); + Assert.Same(eventArgs, e); + callCount++; + }; - base.WndProc(ref m); - } + // Call with handler. + control.SelectedValueChanged += handler; + control.OnSelectedValueChanged(eventArgs); + Assert.Equal(1, callCount); + + // Remove handler. + control.SelectedValueChanged -= handler; + control.OnSelectedValueChanged(eventArgs); + Assert.Equal(1, callCount); } [WinFormsFact] - public void ListBox_GetItemRectangle_InvokeInvalidGetItemRect_ReturnsExpected() + public void ListBox_ResetBackColor_Invoke_Success() { - using var control = new InvalidGetItemRectListBox(); - control.Items.Add("Item"); - Assert.NotEqual(IntPtr.Zero, control.Handle); + using var control = new ListBox(); - control.MakeInvalid = true; - Assert.Equal(Rectangle.Empty, control.GetItemRectangle(0)); + // Reset without value. + control.ResetBackColor(); + Assert.Equal(SystemColors.Window, control.BackColor); + + // Reset with value. + control.BackColor = Color.Black; + control.ResetBackColor(); + Assert.Equal(SystemColors.Window, control.BackColor); + + // Reset again. + control.ResetBackColor(); + Assert.Equal(SystemColors.Window, control.BackColor); } - private class InvalidGetItemRectListBox : ListBox + [WinFormsFact] + public void ListBox_ResetForeColor_Invoke_Success() { - public bool MakeInvalid { get; set; } + using var control = new ListBox(); - protected unsafe override void WndProc(ref Message m) - { - if (MakeInvalid && m.Msg == (int)User32.LB.GETITEMRECT) - { - RECT* pRect = (RECT*)m.LParam; - *pRect = new RECT(1, 2, 3, 4); - m.Result = IntPtr.Zero; - return; - } + // Reset without value. + control.ResetForeColor(); + Assert.Equal(SystemColors.WindowText, control.ForeColor); - base.WndProc(ref m); - } + // Reset with value. + control.ForeColor = Color.Black; + control.ResetForeColor(); + Assert.Equal(SystemColors.WindowText, control.ForeColor); + + // Reset again. + control.ResetForeColor(); + Assert.Equal(SystemColors.WindowText, control.ForeColor); } [WinFormsFact] - public void ListBox_GetItemRectangle_InvalidIndexEmpty_ThrowsArgumentOutOfRangeException() + public void ListBox_ToString_InvokeWithoutItems_ReturnsExpected() { using var control = new ListBox(); - Assert.Throws("index", () => control.GetItemRectangle(-1)); - Assert.Throws("index", () => control.GetItemRectangle(0)); - Assert.Throws("index", () => control.GetItemRectangle(1)); + Assert.Equal("System.Windows.Forms.ListBox", control.ToString()); } [WinFormsFact] - public void ListBox_GetItemRectangle_InvalidIndexNotEmpty_ThrowsArgumentOutOfRangeException() + public void ListBox_ToString_InvokeWithEmptyItems_ReturnsExpected() { using var control = new ListBox(); - control.Items.Add("Item"); - - Assert.Throws("index", () => control.GetItemRectangle(-1)); - Assert.Throws("index", () => control.GetItemRectangle(1)); - Assert.Throws("index", () => control.GetItemRectangle(2)); + Assert.Empty(control.Items); + Assert.Equal("System.Windows.Forms.ListBox, Items.Count: 0", control.ToString()); } - [WinFormsFact] - public void ListBox_GetItemRectangle_InvalidIndexWithHandleEmpty_ThrowsArgumentOutOfRangeException() + public static IEnumerable ToString_WithItems_TestData() { - using var control = new ListBox(); - Assert.Throws("index", () => control.GetItemRectangle(-1)); - Assert.Throws("index", () => control.GetItemRectangle(0)); - Assert.Throws("index", () => control.GetItemRectangle(1)); + yield return new object[] { string.Empty, "System.Windows.Forms.ListBox, Items.Count: 2, Items[0]: " }; + yield return new object[] { "abc", "System.Windows.Forms.ListBox, Items.Count: 2, Items[0]: abc" }; + yield return new object[] { new string('a', 41), "System.Windows.Forms.ListBox, Items.Count: 2, Items[0]: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" }; } - [WinFormsFact] - public void ListBox_GetItemRectangle_InvalidIndexWithHandleNotEmpty_ThrowsArgumentOutOfRangeException() + [WinFormsTheory] + [MemberData(nameof(ToString_WithItems_TestData))] + public void ListBox_ToString_InvokeWithItems_ReturnsExpected(string item1, string expected) { using var control = new ListBox(); - control.Items.Add("Item"); - Assert.NotEqual(IntPtr.Zero, control.Handle); - - Assert.Throws("index", () => control.GetItemRectangle(-1)); - Assert.Throws("index", () => control.GetItemRectangle(1)); - Assert.Throws("index", () => control.GetItemRectangle(2)); + control.Items.Add(item1); + control.Items.Add("item2"); + Assert.Equal(expected, control.ToString()); } private class SubListBox : ListBox @@ -1225,9 +5929,69 @@ public new bool ResizeRedraw public new bool ShowKeyboardCues => base.ShowKeyboardCues; +#pragma warning disable 0618 + public new void AddItemsCore(object[] value) => base.AddItemsCore(value); +#pragma warning restore 0618 + + public new AccessibleObject CreateAccessibilityInstance() => base.CreateAccessibilityInstance(); + + public new ObjectCollection CreateItemCollection() => base.CreateItemCollection(); + public new AutoSizeMode GetAutoSizeMode() => base.GetAutoSizeMode(); public new bool GetStyle(ControlStyles flag) => base.GetStyle(flag); + + public new void OnChangeUICues(UICuesEventArgs e) => base.OnChangeUICues(e); + + public new void OnClick(EventArgs e) => base.OnClick(e); + + public new void OnDataSourceChanged(EventArgs e) => base.OnDataSourceChanged(e); + + public new void OnDisplayMemberChanged(EventArgs e) => base.OnDisplayMemberChanged(e); + + public new void OnDrawItem(DrawItemEventArgs e) => base.OnDrawItem(e); + + public new void OnFontChanged(EventArgs e) => base.OnFontChanged(e); + + public new void OnGotFocus(EventArgs e) => base.OnGotFocus(e); + + public new void OnHandleCreated(EventArgs e) => base.OnHandleCreated(e); + + public new void OnHandleDestroyed(EventArgs e) => base.OnHandleDestroyed(e); + + public new void OnMeasureItem(MeasureItemEventArgs e) => base.OnMeasureItem(e); + + public new void OnMouseClick(MouseEventArgs e) => base.OnMouseClick(e); + + public new void OnPaint(PaintEventArgs e) => base.OnPaint(e); + + public new void OnParentChanged(EventArgs e) => base.OnParentChanged(e); + + public new void OnResize(EventArgs e) => base.OnResize(e); + + public new void OnSelectedIndexChanged(EventArgs e) => base.OnSelectedIndexChanged(e); + + public new void OnSelectedValueChanged(EventArgs e) => base.OnSelectedValueChanged(e); + + public new void RefreshItem(int index) => base.RefreshItem(index); + + public new void RefreshItems() => base.RefreshItems(); + + public new void RescaleConstantsForDpi(int deviceDpiOld, int deviceDpiNew) => base.RescaleConstantsForDpi(deviceDpiOld, deviceDpiNew); + + public new void ScaleControl(SizeF factor, BoundsSpecified specified) => base.ScaleControl(factor, specified); + + public new void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified) => base.SetBoundsCore(x, y, width, height, specified); + + public new void SetItemCore(int index, object value) => base.SetItemCore(index, value); + + public new void SetItemsCore(IList value) => base.SetItemsCore(value); + + public new void Sort() => base.Sort(); + + public new void WmReflectCommand(ref Message m) => base.WmReflectCommand(ref m); + + public new void WndProc(ref Message m) => base.WndProc(ref m); } private class DataClass