// Licensed to the .NET Foundation under one or more agreements.
// 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.Globalization;
using Moq;
using WinForms.Common.Tests;
using Xunit;

namespace System.Windows.Forms.Tests
{
    using Point = System.Drawing.Point;
    using Size = System.Drawing.Size;

    public class ListControlTests : IClassFixture<ThreadExceptionFixture>
    {
        [WinFormsFact]
        public void ListControl_Ctor_Default()
        {
            using var control = new SubListControl();
            Assert.Null(control.AccessibleDefaultActionDescription);
            Assert.Null(control.AccessibleDescription);
            Assert.Null(control.AccessibleName);
            Assert.Equal(AccessibleRole.Default, control.AccessibleRole);
            Assert.False(control.AllowDrop);
            Assert.True(control.AllowSelectionEntry);
            Assert.Equal(AnchorStyles.Top | AnchorStyles.Left, control.Anchor);
            Assert.False(control.AutoSize);
            Assert.Equal(Control.DefaultBackColor, control.BackColor);
            Assert.Null(control.BackgroundImage);
            Assert.Equal(ImageLayout.Tile, control.BackgroundImageLayout);
            Assert.Null(control.BindingContext);
            Assert.Equal(0, control.Bottom);
            Assert.Equal(Rectangle.Empty, control.Bounds);
            Assert.True(control.CanEnableIme);
            Assert.False(control.CanFocus);
            Assert.True(control.CanRaiseEvents);
            Assert.True(control.CanSelect);
            Assert.False(control.Capture);
            Assert.True(control.CausesValidation);
            Assert.Equal(Size.Empty, control.ClientSize);
            Assert.Equal(Rectangle.Empty, control.ClientRectangle);
            Assert.Null(control.Container);
            Assert.False(control.ContainsFocus);
            Assert.Null(control.ContextMenuStrip);
            Assert.Empty(control.Controls);
            Assert.Same(control.Controls, control.Controls);
            Assert.False(control.Created);
            Assert.Same(Cursors.Default, control.Cursor);
            Assert.Null(control.DataManager);
            Assert.Null(control.DataSource);
            Assert.Same(Cursors.Default, control.DefaultCursor);
            Assert.Equal(ImeMode.Inherit, control.DefaultImeMode);
            Assert.Equal(new Padding(3), control.DefaultMargin);
            Assert.Equal(Size.Empty, control.DefaultMaximumSize);
            Assert.Equal(Size.Empty, control.DefaultMinimumSize);
            Assert.Equal(Padding.Empty, control.DefaultPadding);
            Assert.Equal(Size.Empty, control.DefaultSize);
            Assert.False(control.DesignMode);
            Assert.Empty(control.DisplayMember);
            Assert.Equal(Rectangle.Empty, control.DisplayRectangle);
            Assert.Equal(DockStyle.None, control.Dock);
            Assert.False(control.DoubleBuffered);
            Assert.True(control.Enabled);
            Assert.NotNull(control.Events);
            Assert.Same(control.Events, control.Events);
            Assert.False(control.Focused);
            Assert.Equal(Control.DefaultFont, control.Font);
            Assert.Equal(control.Font.Height, control.FontHeight);
            Assert.Equal(Control.DefaultForeColor, control.ForeColor);
            Assert.Null(control.FormatInfo);
            Assert.Empty(control.FormatString);
            Assert.False(control.FormattingEnabled);
            Assert.False(control.HasChildren);
            Assert.Equal(0, control.Height);
            Assert.Equal(ImeMode.NoControl, control.ImeMode);
            Assert.Equal(ImeMode.NoControl, control.ImeModeBase);
            Assert.False(control.IsAccessible);
            Assert.False(control.IsMirrored);
            Assert.NotNull(control.LayoutEngine);
            Assert.Same(control.LayoutEngine, control.LayoutEngine);
            Assert.Equal(0, control.Left);
            Assert.Equal(Point.Empty, control.Location);
            Assert.Equal(new Padding(3), control.Margin);
            Assert.Equal(Size.Empty, control.MaximumSize);
            Assert.Equal(Size.Empty, control.MinimumSize);
            Assert.Equal(Padding.Empty, control.Padding);
            Assert.Null(control.Parent);
            Assert.Equal("Microsoft\u00AE .NET", control.ProductName);
            Assert.Equal(Size.Empty, control.PreferredSize);
            Assert.False(control.RecreatingHandle);
            Assert.Null(control.Region);
            Assert.False(control.ResizeRedraw);
            Assert.Equal(0, control.Right);
            Assert.Equal(RightToLeft.No, control.RightToLeft);
            Assert.Null(control.SelectedValue);
            Assert.Equal(0, control.SelectedIndex);
            Assert.True(control.ShowFocusCues);
            Assert.True(control.ShowKeyboardCues);
            Assert.Null(control.Site);
            Assert.Equal(Size.Empty, control.Size);
            Assert.Equal(0, control.TabIndex);
            Assert.True(control.TabStop);
            Assert.Empty(control.Text);
            Assert.Equal(0, control.Top);
            Assert.Null(control.TopLevelControl);
            Assert.False(control.UseWaitCursor);
            Assert.Empty(control.ValueMember);
            Assert.True(control.Visible);
            Assert.Equal(0, control.Width);

            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_CreateParams_GetDefault_ReturnsExpected()
        {
            using var control = new SubListControl();
            CreateParams createParams = control.CreateParams;
            Assert.Null(createParams.Caption);
            Assert.Null(createParams.ClassName);
            Assert.Equal(0x8, createParams.ClassStyle);
            Assert.Equal(0, createParams.ExStyle);
            Assert.Equal(0, createParams.Height);
            Assert.Equal(IntPtr.Zero, createParams.Parent);
            Assert.Null(createParams.Param);
            Assert.Equal(0x56010000, createParams.Style);
            Assert.Equal(0, createParams.Width);
            Assert.Equal(0, createParams.X);
            Assert.Equal(0, createParams.Y);
            Assert.Same(createParams, control.CreateParams);
            Assert.False(control.IsHandleCreated);
        }

        public static IEnumerable<object[]> BindingContext_Set_TestData()
        {
            yield return new object[] { null };
            yield return new object[] { new BindingContext() };
        }

        [WinFormsTheory]
        [MemberData(nameof(BindingContext_Set_TestData))]
        public void ListControl_BindingContext_Set_GetReturnsExpected(BindingContext value)
        {
            using var control = new SubListControl
            {
                BindingContext = value
            };
            Assert.Same(value, control.BindingContext);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [MemberData(nameof(BindingContext_Set_TestData))]
        public void ListControl_BindingContext_SetWithNonNullBindingContext_GetReturnsExpected(BindingContext value)
        {
            using var control = new SubListControl
            {
                BindingContext = new BindingContext()
            };

            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_BindingContext_SetWithDataSource_GetReturnsExpected()
        {
            var value = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                DataSource = dataSource
            };

            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_BindingContext_SetWithDataSourceAndDisplayMember_GetReturnsExpected()
        {
            var value = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                DataSource = dataSource,
                DisplayMember = "Value"
            };

            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_BindingContext_SetWithDataSourceWithBindingContext_GetReturnsExpected()
        {
            var originalValue = new BindingContext();
            var value = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = originalValue,
                DataSource = dataSource
            };

            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_BindingContext_SetWithDataSourceAndDisplayMemberWithBindingContext_GetReturnsExpected()
        {
            var originalValue = new BindingContext();
            var value = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = originalValue,
                DataSource = dataSource,
                DisplayMember = "Value"
            };

            control.BindingContext = value;
            Assert.Same(value, control.BindingContext);
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.BindingContext = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(value[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_BindingContext_SetWithHandler_CallsBindingContextChanged()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                callCount++;
            };
            control.BindingContextChanged += handler;

            // Set different.
            var context1 = new BindingContext();
            control.BindingContext = context1;
            Assert.Same(context1, control.BindingContext);
            Assert.Equal(1, callCount);

            // Set same.
            control.BindingContext = context1;
            Assert.Same(context1, control.BindingContext);
            Assert.Equal(1, callCount);

            // Set different.
            var context2 = new BindingContext();
            control.BindingContext = context2;
            Assert.Same(context2, control.BindingContext);
            Assert.Equal(2, callCount);

            // Set null.
            control.BindingContext = null;
            Assert.Null(control.BindingContext);
            Assert.Equal(3, callCount);

            // Remove handler.
            control.BindingContextChanged -= handler;
            control.BindingContext = context1;
            Assert.Same(context1, control.BindingContext);
            Assert.Equal(3, callCount);
        }

        [WinFormsFact]
        public void ListControl_DataManager_ChangePosition_UpdatesSelectionIndex()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            control.DataManager.Position = 1;
            Assert.Equal(1, control.SelectedIndex);
        }

        [WinFormsFact]
        public void ListControl_DataManager_ChangePositionDoesNotAllowSelection_DoesNotUpdateSelectionIndex()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new AllowSelectionFalseListControl
            {
                SelectedIndex = -2,
                BindingContext = context,
                DataSource = dataSource,
            };

            control.DataManager.Position = 1;
            Assert.Equal(-2, control.SelectedIndex);
        }

        [WinFormsFact]
        public void ListControl_DataManager_SuspendResumeBinding_CallsSetItemsCore()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new SubListControl
            {
                SelectedIndex = -1,
                BindingContext = context,
                DataSource = dataSource
            };
            int callCount = 0;
            control.SetItemsCoreHandler += (items) =>
            {
                Assert.Same(dataSource, items);
                callCount++;
            };

            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(0, control.DataManager.Position);

            // Supsending should call.
            control.DataManager.SuspendBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Suspending again should be a nop.
            control.DataManager.SuspendBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Resuming should call.
            control.DataManager.ResumeBinding();
            Assert.Equal(0, control.SelectedIndex);
            Assert.Equal(2, callCount);

            // Resuming again should be a nop.
            control.DataManager.ResumeBinding();
            Assert.Equal(0, control.SelectedIndex);
            Assert.Equal(2, callCount);

            // Should not call if the DataSource is changed.
            control.DataSource = new List<DataClass>();
        }

        [WinFormsFact]
        public void ListControl_DataManager_SuspendResumeBindingAfterDataManagerChanged_DoesNotCallSetItemsCore()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new SubListControl
            {
                SelectedIndex = -1,
                BindingContext = context,
                DataSource = dataSource
            };
            int callCount = 0;
            control.SetItemsCoreHandler += (items) =>
            {
                Assert.Same(dataSource, items);
                callCount++;
            };

            CurrencyManager dataManger = control.DataManager;
            dataManger.SuspendBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Should not call if the DataSource is changed.
            control.DataSource = new List<DataClass>();
            Assert.NotSame(dataManger, control.DataManager);
            dataManger.ResumeBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);
        }

        [WinFormsFact]
        public void ListControl_DataManager_SuspendResumeBindingDoesNotAllowSelection_CallsSetItemsCore()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new AllowSelectionFalseListControl
            {
                SelectedIndex = -1,
                BindingContext = context,
                DataSource = dataSource
            };
            int callCount = 0;
            control.SetItemsCoreHandler += (items) =>
            {
                Assert.Same(dataSource, items);
                callCount++;
            };

            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(0, control.DataManager.Position);

            // Supsending should call.
            control.DataManager.SuspendBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Suspending again should be a nop.
            control.DataManager.SuspendBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Resuming should call.
            control.DataManager.ResumeBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(2, callCount);

            // Resuming again should be a nop.
            control.DataManager.ResumeBinding();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(2, callCount);
        }

        [WinFormsFact]
        public void ListControl_DataManager_CancelCurrentEdit_CallsSetItemCore()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new SubListControl
            {
                SelectedIndex = -1,
                BindingContext = context,
                DataSource = dataSource
            };
            int callCount = 0;
            control.SetItemCoreHandler += (index, value) =>
            {
                Assert.Equal(0, index);
                Assert.Same(dataSource[0], value);
                callCount++;
            };

            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(0, control.DataManager.Position);

            control.DataManager.CancelCurrentEdit();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);
        }

        [WinFormsFact]
        public void ListControl_DataManager_CancelCurrentEditAfterDataManagerChanged_DoesNotCallSetItemCore()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass(), new DataClass() };
            using var control = new SubListControl
            {
                SelectedIndex = -1,
                BindingContext = context,
                DataSource = dataSource
            };
            int callCount = 0;
            control.SetItemCoreHandler += (index, value) =>
            {
                Assert.Equal(0, index);
                Assert.Same(dataSource[0], value);
                callCount++;
            };

            CurrencyManager dataManger = control.DataManager;
            dataManger.CancelCurrentEdit();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);

            // Should not call if the DataSource is changed.
            control.DataSource = new List<DataClass>();
            Assert.NotSame(dataManger, control.DataManager);
            dataManger.CancelCurrentEdit();
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Equal(1, callCount);
        }

        public static IEnumerable<object[]> DataSource_Set_TestData()
        {
            yield return new object[] { null };
            yield return new object[] { new List<int>() };
            yield return new object[] { Array.Empty<int>() };

            var mockSource = new Mock<IListSource>(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 ListControl_DataSource_Set_GetReturnsExpected(object value)
        {
            using var control = new SubListControl
            {
                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);
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithDataSourceNoDisplayMember_GetReturnsExpected(object value)
        {
            using var control = new SubListControl
            {
                DataSource = new List<int>()
            };

            control.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);
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithDisplayMember_GetReturnsExpected(object value)
        {
            using var control = new SubListControl
            {
                DisplayMember = "Capacity"
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal("Capacity", control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal("Capacity", control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithDataSourceNoSuchDisplayMemberAnymore_GetReturnsExpected(object value)
        {
            var originalValue = new List<int>();
            using var control = new SubListControl
            {
                DataSource = originalValue,
                DisplayMember = "Capacity"
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal(value is null ? string.Empty : "Capacity", control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal(value is null ? string.Empty : "Capacity", control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetComponent_DisposeValue_Removes()
        {
            var value = new ComponentList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.Dispose();
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetComponent_DisposeValueDifferentSender_Removes()
        {
            var value = new ComponentList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnDisposed(new object(), EventArgs.Empty);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetComponent_DisposeValueNullSender_Removes()
        {
            var value = new ComponentList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnDisposed(null, null);
            Assert.Null(control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetOverridenComponent_DisposeValue_DoesNotRemove()
        {
            var originalValue = new ComponentList();
            var value = new List<int>();
            using var control = new SubListControl
            {
                DataSource = originalValue,
                DisplayMember = "Count"
            };
            Assert.Same(originalValue, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            control.DataSource = value;
            originalValue.Dispose();
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetSupportInitializeNotification_InitializeValueNotInitializedSetsInitialized_Success()
        {
            var value = new SupportInitializeNotificationList();
            value.Initialized += (sender, e) =>
            {
                value.IsInitialized = true;
            };

            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnInitialized(value, EventArgs.Empty);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetSupportInitializeNotification_InitializeValueNotInitialized_Success()
        {
            var value = new SupportInitializeNotificationList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnInitialized(value, EventArgs.Empty);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetSupportInitializeNotification_InitializeValueInitialized_Success()
        {
            var value = new SupportInitializeNotificationList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnInitialized(value, EventArgs.Empty);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetSupportInitializeNotification_InitializeValueDifferentSender_Success()
        {
            var value = new SupportInitializeNotificationList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnInitialized(new object(), EventArgs.Empty);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetSupportInitializeNotification_InitializeValueNullSender_Succes()
        {
            var value = new SupportInitializeNotificationList();
            using var control = new SubListControl
            {
                DataSource = value,
                DisplayMember = "Count"
            };
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            value.OnInitialized(null, null);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))]
        public void ListControl_DataSource_SetOverridenSupportInitializeNotification_InitializeValue_Success(bool isInitialized)
        {
            var originalValue = new SupportInitializeNotificationList();
            var value = new List<int>();
            using var control = new SubListControl
            {
                DataSource = originalValue,
                DisplayMember = "Count"
            };
            Assert.Same(originalValue, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);

            originalValue.IsInitialized = isInitialized;
            control.DataSource = value;
            originalValue.OnInitialized(originalValue, EventArgs.Empty);
            Assert.Same(value, control.DataSource);
            Assert.Equal("Count", control.DisplayMember);
            Assert.Null(control.DataManager);
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithBindingContext_GetReturnsExpected(object value)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                BindingContext = context
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithBindingContextWithDataSource_GetReturnsExpected(object value)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = new List<int>()
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetWithBindingContextWithDisplayMemberCanCreate_GetReturnsExpected()
        {
            var context = new BindingContext();
            var value = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DisplayMember = "Value"
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(context[value], control.DataManager);

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal("Value", control.DisplayMember);
            Assert.Same(context[value], control.DataManager);
        }

        [WinFormsTheory]
        [MemberData(nameof(DataSource_Set_TestData))]
        public void ListControl_DataSource_SetWithBindingContextWithDisplayMemberCantCreate_GetReturnsExpected(object value)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                BindingContext = context,
                DisplayMember = "NoSuchDisplayMember"
            };

            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal(value is null ? "NoSuchDisplayMember" : string.Empty, control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }

            // Set same.
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Equal(value is null ? "NoSuchDisplayMember" : string.Empty, control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[value], control.DataManager);
            }
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetWithHandler_CallsDataSourceChanged()
        {
            using var control = new SubListControl();
            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<int>();
            control.DataSource = dataSource1;
            Assert.Same(dataSource1, control.DataSource);
            Assert.Equal(1, dataSourceCallCount);
            Assert.Equal(0, displayMemberCallCount);

            // Set same.
            control.DataSource = dataSource1;
            Assert.Same(dataSource1, control.DataSource);
            Assert.Equal(1, dataSourceCallCount);
            Assert.Equal(0, displayMemberCallCount);

            // Set different.
            var dataSource2 = new List<int>();
            control.DataSource = dataSource2;
            Assert.Same(dataSource2, control.DataSource);
            Assert.Equal(2, dataSourceCallCount);
            Assert.Equal(0, displayMemberCallCount);

            // Set null.
            control.DataSource = null;
            Assert.Null(control.DataSource);
            Assert.Equal(3, dataSourceCallCount);
            Assert.Equal(0, displayMemberCallCount);

            // Remove handler.
            control.DataSourceChanged -= dataSourceHandler;
            control.DisplayMemberChanged -= displayMemberHandler;
            control.DataSource = dataSource1;
            Assert.Same(dataSource1, control.DataSource);
            Assert.Equal(3, dataSourceCallCount);
            Assert.Equal(0, displayMemberCallCount);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetInsideDataSourceChanged_Nop()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                control.DataSource = Array.Empty<int>();
                callCount++;
            };
            control.DataSourceChanged += handler;

            var value = new List<int>();
            control.DataSource = value;
            Assert.Same(value, control.DataSource);
            Assert.Empty(control.DisplayMember);
            Assert.Equal(1, callCount);
        }

        [WinFormsFact]
        public void ListControl_DataSource_SetInvalid_ThrowsArgumentException()
        {
            using var control = new SubListControl();
            Assert.Throws<ArgumentException>("value", () => control.DataSource = new object());
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_DisplayMember_Set_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                DisplayMember = value
            };
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_DataMember_SetWithDisplayMember_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                DisplayMember = "DataMember"
            };

            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))]
        public void ListControl_DisplayMember_SetWithDataSource_GetReturnsExpected(string value)
        {
            var dataSource = new List<int>();
            using var control = new SubListControl
            {
                DataSource = dataSource
            };

            control.DisplayMember = value;
            Assert.Equal(value, control.DisplayMember);
            Assert.Same(dataSource, control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Equal(value, control.DisplayMember);
            Assert.Same(dataSource, control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_DisplayMember_SetWithBindingContext_GetReturnsExpected(string value, string expected)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                BindingContext = context
            };

            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Null(control.DataSource);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))]
        public void ListControl_DisplayMember_SetWithBindingContextWithDataSource_GetReturnsExpected(string value)
        {
            var context = new BindingContext();
            var dataSource = new List<int>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            control.DisplayMember = value;
            Assert.Empty(control.DisplayMember);
            Assert.Same(dataSource, control.DataSource);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Empty(control.DisplayMember);
            Assert.Same(dataSource, control.DataSource);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [InlineData(null, "")]
        [InlineData("", "")]
        [InlineData("Value", "Value")]
        [InlineData("value", "value")]
        public void ListControl_DisplayMember_SetWithBindingContextWithDataSourceCanCreate_GetReturnsExpected(string value, string expected)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(dataSource, control.DataSource);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(dataSource, control.DataSource);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringTheoryData))]
        [InlineData("ListValue")]
        public void ListControl_DisplayMember_SetWithBindingContextWithDataSourceCantCreate_GetReturnsExpected(string value)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            control.DisplayMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[dataSource], control.DataManager);
            }

            Assert.False(control.IsHandleCreated);

            // Set same.
            control.DisplayMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Empty(control.DisplayMember);
            if (value is null)
            {
                Assert.Null(control.DataManager);
            }
            else
            {
                Assert.Same(context[dataSource], control.DataManager);
            }

            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_DisplayMember_SetWithHandler_CallsDisplayMemberChanged()
        {
            using var control = new SubListControl();
            int displayMemberCallCount = 0;
            int dataSourceCallCount = 0;
            EventHandler displayMemberHandler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                displayMemberCallCount++;
            };
            EventHandler dataSourceHandler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                dataSourceCallCount++;
            };
            control.DisplayMemberChanged += displayMemberHandler;
            control.DataSourceChanged += dataSourceHandler;

            // Set different.
            control.DisplayMember = "Value1";
            Assert.Equal("Value1", control.DisplayMember);
            Assert.Equal(1, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);

            // Set same.
            control.DisplayMember = "Value1";
            Assert.Equal("Value1", control.DisplayMember);
            Assert.Equal(1, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);

            // Set different.
            control.DisplayMember = "Value2";
            Assert.Equal("Value2", control.DisplayMember);
            Assert.Equal(2, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);

            // Set null.
            control.DisplayMember = null;
            Assert.Empty(control.DisplayMember);
            Assert.Equal(3, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);

            // Set empty.
            control.DisplayMember = string.Empty;
            Assert.Empty(control.DisplayMember);
            Assert.Equal(3, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);

            // Remove handler.
            control.DisplayMemberChanged -= displayMemberHandler;
            control.DataSourceChanged -= dataSourceHandler;
            control.DisplayMember = "Value1";
            Assert.Equal("Value1", control.DisplayMember);
            Assert.Equal(3, displayMemberCallCount);
            Assert.Equal(0, dataSourceCallCount);
        }

        [WinFormsFact]
        public void ListControl_DisplayMember_SetInsideDisplayMemberChanged_Nop()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                control.DisplayMember = "Value2";
                callCount++;
            };
            control.DisplayMemberChanged += handler;

            control.DisplayMember = "Value1";
            Assert.Equal("Value1", control.DisplayMember);
            Assert.Equal(1, callCount);
        }

        [WinFormsFact]
        public void ListControl_Format_AddRemove_CallsRefreshItems()
        {
            using var control = new SubListControl();
            int callCount = 0;
            control.RefreshItemsHandler = () => callCount++;
            ListControlConvertEventHandler handler = (sender, e) => { };

            // Add.
            control.Format += handler;
            Assert.Equal(1, callCount);

            // Remove.
            control.Format -= handler;
            Assert.Equal(2, callCount);
        }

        public static IEnumerable<object[]> FormatInfo_Set_TestData()
        {
            yield return new object[] { null };
            yield return new object[] { CultureInfo.CurrentCulture };
        }

        [WinFormsTheory]
        [MemberData(nameof(FormatInfo_Set_TestData))]
        public void ListControl_FormatInfo_Set_GetReturnsExpected(IFormatProvider value)
        {
            using var control = new SubListControl
            {
                FormatInfo = value
            };
            Assert.Same(value, control.FormatInfo);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormatInfo = value;
            Assert.Same(value, control.FormatInfo);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [MemberData(nameof(FormatInfo_Set_TestData))]
        public void ListControl_FormatInfo_SetWithCustomOldValue_GetReturnsExpected(IFormatProvider value)
        {
            using var control = new SubListControl
            {
                FormatInfo = CultureInfo.InvariantCulture
            };

            control.FormatInfo = value;
            Assert.Same(value, control.FormatInfo);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormatInfo = value;
            Assert.Same(value, control.FormatInfo);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_FormatInfo_Set_CallsRefreshItems()
        {
            using var control = new SubListControl();
            int callCount = 0;
            control.RefreshItemsHandler = () => callCount++;

            // Set different.
            control.FormatInfo = CultureInfo.CurrentCulture;
            Assert.Same(CultureInfo.CurrentCulture, control.FormatInfo);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormatInfo = CultureInfo.CurrentCulture;
            Assert.Same(CultureInfo.CurrentCulture, control.FormatInfo);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormatInfo = CultureInfo.InvariantCulture;
            Assert.Same(CultureInfo.InvariantCulture, control.FormatInfo);
            Assert.Equal(2, callCount);

            // Set null.
            control.FormatInfo = null;
            Assert.Null(control.FormatInfo);
            Assert.Equal(3, callCount);
        }

        [WinFormsFact]
        public void ListControl_FormatInfo_SetWithHandler_CallsOnFormatInfoChanged()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                callCount++;
            };
            control.FormatInfoChanged += handler;

            // Set different.
            control.FormatInfo = CultureInfo.CurrentCulture;
            Assert.Same(CultureInfo.CurrentCulture, control.FormatInfo);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormatInfo = CultureInfo.CurrentCulture;
            Assert.Same(CultureInfo.CurrentCulture, control.FormatInfo);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormatInfo = CultureInfo.InvariantCulture;
            Assert.Same(CultureInfo.InvariantCulture, control.FormatInfo);
            Assert.Equal(2, callCount);

            // Set null.
            control.FormatInfo = null;
            Assert.Null(control.FormatInfo);
            Assert.Equal(3, callCount);

            // Remove handler.
            control.FormatInfoChanged -= handler;
            control.FormatInfo = CultureInfo.CurrentCulture;
            Assert.Same(CultureInfo.CurrentCulture, control.FormatInfo);
            Assert.Equal(3, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_FormatString_Set_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                FormatString = value
            };
            Assert.Equal(expected, control.FormatString);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormatString = value;
            Assert.Equal(expected, control.FormatString);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_FormatString_SetWithCustomOldValue_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                FormatString = "FormatString"
            };

            control.FormatString = value;
            Assert.Equal(expected, control.FormatString);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormatString = value;
            Assert.Equal(expected, control.FormatString);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_FormatString_Set_CallsRefreshItems()
        {
            using var control = new SubListControl();
            int callCount = 0;
            control.RefreshItemsHandler = () => callCount++;

            // Set different.
            control.FormatString = "Value1";
            Assert.Equal("Value1", control.FormatString);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormatString = "Value1";
            Assert.Equal("Value1", control.FormatString);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormatString = "Value2";
            Assert.Equal("Value2", control.FormatString);
            Assert.Equal(2, callCount);

            // Set null.
            control.FormatString = null;
            Assert.Empty(control.FormatString);
            Assert.Equal(3, callCount);

            // Set empty.
            control.FormatString = string.Empty;
            Assert.Empty(control.FormatString);
            Assert.Equal(3, callCount);
        }

        [WinFormsFact]
        public void ListControl_FormatString_SetWithHandler_CallsOnFormatStringChanged()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                callCount++;
            };
            control.FormatStringChanged += handler;

            // Set different.
            control.FormatString = "Value1";
            Assert.Equal("Value1", control.FormatString);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormatString = "Value1";
            Assert.Equal("Value1", control.FormatString);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormatString = "Value2";
            Assert.Equal("Value2", control.FormatString);
            Assert.Equal(2, callCount);

            // Set null.
            control.FormatString = null;
            Assert.Empty(control.FormatString);
            Assert.Equal(3, callCount);

            // Set empty.
            control.FormatString = string.Empty;
            Assert.Empty(control.FormatString);
            Assert.Equal(3, callCount);

            // Remove handler.
            control.FormatStringChanged -= handler;
            control.FormatString = "Value1";
            Assert.Equal("Value1", control.FormatString);
            Assert.Equal(3, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))]
        public void ListControl_FormattingEnabled_Set_GetReturnsExpected(bool value)
        {
            using var control = new SubListControl
            {
                FormattingEnabled = value
            };
            Assert.Equal(value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormattingEnabled = value;
            Assert.Equal(value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);

            // Set different.
            control.FormattingEnabled = !value;
            Assert.Equal(!value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetBoolTheoryData))]
        public void ListControl_FormattingEnabled_SetWithFormattingEnabled_GetReturnsExpected(bool value)
        {
            using var control = new SubListControl
            {
                FormattingEnabled = true
            };

            control.FormattingEnabled = value;
            Assert.Equal(value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.FormattingEnabled = value;
            Assert.Equal(value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);

            // Set different.
            control.FormattingEnabled = !value;
            Assert.Equal(!value, control.FormattingEnabled);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_FormattingEnabled_Set_CallsRefreshItems()
        {
            using var control = new SubListControl();
            int callCount = 0;
            control.RefreshItemsHandler = () => callCount++;

            // Set different.
            control.FormattingEnabled = true;
            Assert.True(control.FormattingEnabled);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormattingEnabled = true;
            Assert.True(control.FormattingEnabled);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormattingEnabled = false;
            Assert.False(control.FormattingEnabled);
            Assert.Equal(2, callCount);
        }

        [WinFormsFact]
        public void ListControl_FormattingEnabled_SetWithHandler_CallsOnFormattingEnabledChanged()
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                callCount++;
            };
            control.FormattingEnabledChanged += handler;

            // Set different.
            control.FormattingEnabled = true;
            Assert.True(control.FormattingEnabled);
            Assert.Equal(1, callCount);

            // Set same.
            control.FormattingEnabled = true;
            Assert.True(control.FormattingEnabled);
            Assert.Equal(1, callCount);

            // Set different.
            control.FormattingEnabled = false;
            Assert.False(control.FormattingEnabled);
            Assert.Equal(2, callCount);

            // Remove handler.
            control.FormattingEnabledChanged -= handler;
            control.FormattingEnabled = true;
            Assert.True(control.FormattingEnabled);
            Assert.Equal(2, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_ValueMember_Set_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                ValueMember = value
            };
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.ValueMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_ValueMember_SetWithDisplayMember_GetReturnsExpected(string value, string expected)
        {
            using var control = new SubListControl
            {
                DisplayMember = "DisplayMember"
            };

            control.ValueMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal("DisplayMember", control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.ValueMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal("DisplayMember", control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetStringNormalizedTheoryData))]
        public void ListControl_ValueMember_SetWithBindingContext_GetReturnsExpected(string value, string expected)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                BindingContext = context
            };

            control.ValueMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.ValueMember = value;
            Assert.Null(control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Null(control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [InlineData(null, "")]
        [InlineData("", "")]
        [InlineData("Value", "Value")]
        [InlineData("value", "value")]
        public void ListControl_ValueMember_SetWithBindingContextWithDataSourceCanCreate_GetReturnsExpected(string value, string expected)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            control.ValueMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.ValueMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal(expected, control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_ValueMember_SetWithBindingContextWithDataSourceCantCreate_ThrowsArgumentException()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource
            };

            Assert.Throws<ArgumentException>("newDisplayMember", (() => control.ValueMember = "NoSuchValue"));
            Assert.Equal("NoSuchValue", control.DisplayMember);
            Assert.Empty(control.ValueMember);
        }

        [WinFormsTheory]
        [InlineData(null, "")]
        [InlineData("", "")]
        [InlineData("Value", "Value")]
        [InlineData("value", "value")]
        public void ListControl_ValueMember_SetWithBindingContextWithDataSourceWithDisplayMemberCanCreate_GetReturnsExpected(string value, string expected)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource,
                DisplayMember = "OtherValue"
            };

            control.ValueMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("OtherValue", control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.ValueMember = value;
            Assert.Same(dataSource, control.DataSource);
            Assert.Equal("OtherValue", control.DisplayMember);
            Assert.Equal(expected, control.ValueMember);
            Assert.Same(context[dataSource], control.DataManager);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_ValueMember_SetWithBindingContextWithDataSourceWithDisplayMemberCantCreate_ThrowsArgumentException()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                BindingContext = context,
                DataSource = dataSource,
                DisplayMember = "Value"
            };

            Assert.Throws<ArgumentException>("value", (() => control.ValueMember = "NoSuchValue"));
            Assert.Equal("Value", control.DisplayMember);
            Assert.Empty(control.ValueMember);
        }

        [WinFormsFact]
        public void ListControl_ValueMember_SetWithHandler_CallsValueMemberChanged()
        {
            using var control = new SubListControl();
            int valueMemberCallCount = 0;
            int selectedValueCallCount = 0;
            EventHandler valueMemberHandler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                valueMemberCallCount++;
            };
            EventHandler selectedValueHanlder = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                Assert.True(valueMemberCallCount > selectedValueCallCount);
                selectedValueCallCount++;
            };
            control.ValueMemberChanged += valueMemberHandler;
            control.SelectedValueChanged += selectedValueHanlder;

            // Set different.
            control.ValueMember = "Value1";
            Assert.Equal("Value1", control.ValueMember);
            Assert.Equal(1, valueMemberCallCount);
            Assert.Equal(1, selectedValueCallCount);

            // Set same.
            control.ValueMember = "Value1";
            Assert.Equal("Value1", control.ValueMember);
            Assert.Equal(1, valueMemberCallCount);
            Assert.Equal(1, selectedValueCallCount);

            // Set different.
            control.ValueMember = "Value2";
            Assert.Equal("Value2", control.ValueMember);
            Assert.Equal(2, valueMemberCallCount);
            Assert.Equal(2, selectedValueCallCount);

            // Set null.
            control.ValueMember = null;
            Assert.Empty(control.ValueMember);
            Assert.Equal(3, valueMemberCallCount);
            Assert.Equal(3, selectedValueCallCount);

            // Set empty.
            control.ValueMember = string.Empty;
            Assert.Empty(control.ValueMember);
            Assert.Equal(3, valueMemberCallCount);
            Assert.Equal(3, selectedValueCallCount);

            // Remove handler.
            control.ValueMemberChanged -= valueMemberHandler;
            control.SelectedValueChanged -= selectedValueHanlder;
            control.ValueMember = "Value1";
            Assert.Equal("Value1", control.ValueMember);
            Assert.Equal(3, valueMemberCallCount);
            Assert.Equal(3, selectedValueCallCount);
        }

        [WinFormsTheory]
        [InlineData("Value")]
        [InlineData("value")]
        public void ListControl_SelectedValue_SetWithMatchingValue_Success(string valueMember)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass { Value = "StringValue" } };
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                ValueMember = valueMember,
                BindingContext = context,
                DataSource = dataSource
            };

            control.SelectedValue = "StringValue";
            Assert.Equal(0, control.SelectedIndex);
            Assert.Equal("StringValue", control.SelectedValue);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.SelectedValue = "StringValue";
            Assert.Equal(0, control.SelectedIndex);
            Assert.Equal("StringValue", control.SelectedValue);
            Assert.False(control.IsHandleCreated);
        }

        public static IEnumerable<object[]> SelectedValue_NoMatchingValue_TestData()
        {
            yield return new object[] { new List<DataClass>(), "selected" };
            yield return new object[] { new List<DataClass> { new DataClass { Value = "NoSuchValue" } }, string.Empty };
            yield return new object[] { new List<DataClass> { new DataClass { Value = "NoSuchValue" } }, "selected" };
            yield return new object[] { new List<DataClass> { new DataClass { Value = "NoSuchValue" } }, "nosuchvalue" };
        }

        [WinFormsTheory]
        [MemberData(nameof(SelectedValue_NoMatchingValue_TestData))]
        public void ListControl_SelectedValue_SetWithNoMatchingValue_Success(object dataSource, string value)
        {
            var context = new BindingContext();
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                ValueMember = "Value",
                BindingContext = context,
                DataSource = dataSource
            };

            control.SelectedValue = value;
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Null(control.SelectedValue);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.SelectedValue = value;
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Null(control.SelectedValue);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsFact]
        public void ListControl_SelectedValue_SetWithChangedDataManager_Success()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                ValueMember = "ValueMember",
                BindingContext = context,
                DataSource = dataSource
            };

            control.SelectedValue = "selected";
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Null(control.SelectedValue);
            Assert.False(control.IsHandleCreated);

            // Set same.
            control.SelectedValue = "selected";
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Null(control.SelectedValue);
            Assert.False(control.IsHandleCreated);
        }

        [WinFormsTheory]
        [InlineData(null)]
        [InlineData(1)]
        public void ListControl_SelectedValue_SetWithoutDataManager_GetReturnsNull(object value)
        {
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                SelectedValue = value
            };
            Assert.Equal(0, control.SelectedIndex);
            Assert.Null(control.SelectedValue);

            // Not set even when given a DataManager.
            control.BindingContext = new BindingContext();
            control.DataSource = new List<int>();
            Assert.Equal(0, control.SelectedIndex);
            Assert.Throws<IndexOutOfRangeException>(() => control.SelectedValue);
        }

        [WinFormsFact]
        public void ListControl_SelectedValue_SetWithHandler_DoesNotCallSelectedValueChanged()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass> { new DataClass { Value = "StringValue" } };
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                ValueMember = "Value",
                BindingContext = context,
                DataSource = dataSource
            };

            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(EventArgs.Empty, e);
                callCount++;
            };
            control.SelectedValueChanged += handler;

            // Set different.
            control.SelectedValue = "StringValue";
            Assert.Equal("StringValue", control.SelectedValue);
            Assert.Equal(0, callCount);

            // Set same.
            control.SelectedValue = "StringValue";
            Assert.Equal("StringValue", control.SelectedValue);
            Assert.Equal(0, callCount);

            // Remove handler.
            control.SelectedValueChanged -= handler;
            control.SelectedValue = "StringValue";
            Assert.Equal("StringValue", control.SelectedValue);
            Assert.Equal(0, callCount);
        }

        [WinFormsFact]
        public void ListControl_SelectedValue_SetNull_ThrowsArgumentNullException()
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                BindingContext = context,
                DataSource = dataSource,
                ValueMember = "Value"
            };
            Assert.Throws<ArgumentNullException>("key", () => control.SelectedValue = null);
            Assert.Equal(-1, control.SelectedIndex);
            Assert.Null(control.SelectedValue);
        }

        [WinFormsTheory]
        [InlineData(null)]
        [InlineData(1)]
        public void ListControl_SelectedValue_SetWithoutValueMember_ThrowsInvalidOperationException(object value)
        {
            var context = new BindingContext();
            var dataSource = new List<DataClass>();
            using var control = new SubListControl
            {
                SelectedIndex = 0,
                BindingContext = context,
                DataSource = dataSource
            };
            Assert.Throws<InvalidOperationException>(() => control.SelectedValue = value);
            Assert.Equal(0, control.SelectedIndex);
            Assert.Throws<IndexOutOfRangeException>(() => control.SelectedValue);
        }

        [WinFormsTheory]
        [InlineData(Keys.Alt, false)]
        [InlineData(Keys.Alt | Keys.PageUp, false)]
        [InlineData(Keys.PageUp, true)]
        [InlineData(Keys.PageDown, true)]
        [InlineData(Keys.Home, true)]
        [InlineData(Keys.End, true)]
        [InlineData(Keys.A, false)]
        public void IsInputKey_Invoke_ReturnsExpected(Keys keyData, bool expected)
        {
            using var control = new SubListControl();
            Assert.Equal(expected, control.IsInputKey(keyData));
        }

        public static IEnumerable<object[]> FilterItemOnProperty_TestData()
        {
            yield return new object[]
            {
                new SubListControl(),
                null,
                null
            };

            var item = new object();
            yield return new object[]
            {
                new SubListControl(),
                item,
                item
            };

            yield return new object[]
            {
                new SubListControl { DisplayMember = "Length" },
                "abc",
                3
            };
            yield return new object[]
            {
                new SubListControl { DisplayMember = "length" },
                "abc",
                3
            };
            yield return new object[]
            {
                new SubListControl { DisplayMember = "Path.Length" },
                "abc",
                3
            };
            yield return new object[]
            {
                new SubListControl { DisplayMember = "NoSuchProperty" },
                "abc",
                "abc"
            };

            var dataClass = new DataClass { Value = 10 };
            var list = new List<DataClass> { dataClass };
            yield return new object[]
            {
                new SubListControl
                {
                    DataSource = list
                },
                list,
                list
            };

            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                list,
                list
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list,
                    DisplayMember = "Value"
                },
                list,
                list
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list,
                    DisplayMember = "Value"
                },
                dataClass,
                10
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list,
                    DisplayMember = "value"
                },
                dataClass,
                10
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list,
                    DisplayMember = "NoSuchProperty"
                },
                dataClass,
                dataClass
            };
        }

        [WinFormsTheory]
        [MemberData(nameof(FilterItemOnProperty_TestData))]
        public void ListControl_FilterItemOnProperty_Invoke_ReturnsExpected(SubListControl control, object item, object expected)
        {
            Assert.Equal(expected, control.FilterItemOnProperty(item));
        }

        public static IEnumerable<object[]> FilterItemOnProperty_String_TestData()
        {
            yield return new object[]
            {
                new SubListControl(),
                null,
                "Field",
                null
            };

            var item = new object();
            yield return new object[]
            {
                new SubListControl(),
                item,
                null,
                item
            };
            yield return new object[]
            {
                new SubListControl(),
                item,
                string.Empty,
                item
            };

            yield return new object[]
            {
                new SubListControl(),
                "abc",
                "Length",
                3
            };
            yield return new object[]
            {
                new SubListControl(),
                "abc",
                "length",
                3
            };
            yield return new object[]
            {
                new SubListControl(),
                "abc",
                "NoSuchProperty",
                "abc"
            };

            var dataClass = new DataClass { Value = 10 };
            var list = new List<DataClass> { dataClass };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                list,
                "NoSuchField",
                list
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                list,
                "Value",
                list
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                dataClass,
                "Value",
                10
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                dataClass,
                "value",
                10
            };
            yield return new object[]
            {
                new SubListControl
                {
                    BindingContext = new BindingContext(),
                    DataSource = list
                },
                dataClass,
                "NoSuchProperty",
                dataClass
            };
        }

        [WinFormsTheory]
        [MemberData(nameof(FilterItemOnProperty_String_TestData))]
        public void ListControl_FilterItemOnProperty_InvokeString_ReturnsExpected(SubListControl control, object item, string field, object expected)
        {
            Assert.Equal(expected, control.FilterItemOnProperty(item, field));
        }

        public static IEnumerable<object[]> GetItemText_TestData()
        {
            yield return new object[]
            {
                new SubListControl(), null, string.Empty
            };
            yield return new object[]
            {
                new SubListControl(),
                "abc",
                "abc"
            };
            yield return new object[]
            {
                new SubListControl
                {
                    DisplayMember = "Length"
                },
                "abc",
                3
            };
            yield return new object[]
            {
                new SubListControl
                {
                    DisplayMember = "Value"
                },
                new DataClass { Value = 1 },
                "1"
            };
            yield return new object[]
            {
                new SubListControl
                {
                    DisplayMember = "Value"
                },
                new DataClass { Value = null },
                string.Empty
            };
        }

        [WinFormsTheory]
        [MemberData(nameof(GetItemText_TestData))]
        public void ListControl_GetItemText_Invoke_ReturnsExpected(ListControl control, object item, string expected)
        {
            Assert.Equal(expected, control.GetItemText(item));

            // Test caching behaviour.
            Assert.Equal(expected, control.GetItemText(item));
        }

        public static IEnumerable<object[]> GetItemText_HasHandler_TestData()
        {
            var item = new DataClass { Value = 3 };
            yield return new object[] { item, null, "3" };
            yield return new object[] { item, new object(), "3" };
            yield return new object[] { item, item, "3" };
            yield return new object[] { item, "custom", "custom" };
        }

        [WinFormsTheory]
        [MemberData(nameof(GetItemText_HasHandler_TestData))]
        public void ListControl_GetItemText_HasHandler_CallsFormat(object item, object value, object expected)
        {
            using var control = new SubListControl
            {
                FormattingEnabled = true,
                DisplayMember = "Value"
            };

            // Handler.
            int callCount = 0;
            ListControlConvertEventHandler handler = (sender, e) =>
            {
                Assert.Equal(control, sender);
                Assert.Equal(3, e.Value);
                Assert.Equal(typeof(string), e.DesiredType);
                Assert.Same(item, e.ListItem);

                e.Value = value;
                callCount++;
            };

            control.Format += handler;
            Assert.Equal(expected, control.GetItemText(item));
            Assert.Equal(1, callCount);

            // Should not call if the handler is removed.
            control.Format -= handler;
            Assert.Equal("3", control.GetItemText(item));
            Assert.Equal(1, callCount);
        }

        public static IEnumerable<object[]> GetItemText_HasHandlerFormattingDisabled_TestData()
        {
            var item = new DataClass { Value = 3 };
            yield return new object[] { item, null };
            yield return new object[] { item, new object() };
            yield return new object[] { item, item };
            yield return new object[] { item, "custom" };
        }

        [WinFormsTheory]
        [MemberData(nameof(GetItemText_HasHandlerFormattingDisabled_TestData))]
        public void ListControl_GetItemText_HasHandlerFormattingDisabled_DoesNotCallFormat(object item, object value)
        {
            using var control = new SubListControl
            {
                FormattingEnabled = false,
                DisplayMember = "Value"
            };

            // Handler.
            int callCount = 0;
            ListControlConvertEventHandler handler = (sender, e) =>
            {
                Assert.Equal(control, sender);
                Assert.Equal(3, e.Value);
                Assert.Equal(typeof(string), e.DesiredType);
                Assert.Same(item, e.ListItem);

                e.Value = value;
                callCount++;
            };

            control.Format += handler;
            Assert.Equal("3", control.GetItemText(item));
            Assert.Equal(0, callCount);

            // Should not call if the handler is removed.
            control.Format -= handler;
            Assert.Equal("3", control.GetItemText(item));
            Assert.Equal(0, callCount);
        }

        [WinFormsFact]
        public void ListControl_GetItemText_CustomConverter_ReturnsExpected()
        {
            var item = new CustomTypeConverterDataClass { Value = 10 };
            using var control = new SubListControl
            {
                FormattingEnabled = true,
                BindingContext = new BindingContext(),
                DataSource = new List<CustomTypeConverterDataClass> { item },
                DisplayMember = "Value"
            };
            Assert.Equal("custom", control.GetItemText(item));

            // Test caching behaviour.
            Assert.Equal("custom", control.GetItemText(item));
        }

        [WinFormsFact]
        public void ListControl_GetItemText_CustomConverterFormattingDisabled_ReturnsExpected()
        {
            var item = new CustomTypeConverterDataClass { Value = 10 };
            using var control = new SubListControl
            {
                FormattingEnabled = false,
                BindingContext = new BindingContext(),
                DataSource = new List<CustomTypeConverterDataClass> { item },
                DisplayMember = "Value"
            };
            Assert.Equal("10", control.GetItemText(item));

            // Test caching behaviour.
            Assert.Equal("10", control.GetItemText(item));
        }

        [WinFormsFact]
        public void ListControl_GetItemText_CustomConverterNoContext_ReturnsExpected()
        {
            var item = new CustomTypeConverterDataClass { Value = 10 };
            using var control = new SubListControl
            {
                FormattingEnabled = true,
                DataSource = new List<CustomTypeConverterDataClass> { item },
                DisplayMember = "Value"
            };
            Assert.Equal("10", control.GetItemText(item));

            // Test caching behaviour.
            Assert.Equal("10", control.GetItemText(item));
        }

        [WinFormsFact]
        public void ListControl_GetItemText_NonCriticalThrowingExceptionType_ReturnsExpected()
        {
            var item = new NonCriticalThrowingTypeConverterDataClass();
            using var control = new SubListControl
            {
                FormattingEnabled = true,
                BindingContext = new BindingContext(),
                DataSource = new List<NonCriticalThrowingTypeConverterDataClass> { item },
                DisplayMember = "Value"
            };
            Assert.Equal("NonCriticalThrowingTypeConverterDataClassToString", control.GetItemText(item));

            // Test caching behaviour.
            Assert.Equal("NonCriticalThrowingTypeConverterDataClassToString", control.GetItemText(item));
        }

        [WinFormsFact]
        public void ListControl_GetItemText_CriticalThrowingExceptionType_RethrowsException()
        {
            var item = new CriticalThrowingTypeConverterDataClass();
            using var control = new SubListControl
            {
                FormattingEnabled = true,
                BindingContext = new BindingContext(),
                DataSource = new List<CriticalThrowingTypeConverterDataClass> { item },
                DisplayMember = "Value"
            };
            Assert.Throws<StackOverflowException>(() => control.GetItemText(item));

            // Test caching behaviour.
            Assert.Throws<StackOverflowException>(() => control.GetItemText(item));
        }

        [WinFormsFact]
        public void ListControl_GetAutoSizeMode_Invoke_ReturnsExpected()
        {
            using var control = new SubListControl();
            Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode());
        }

        [WinFormsTheory]
        [InlineData(ControlStyles.ContainerControl, false)]
        [InlineData(ControlStyles.UserPaint, true)]
        [InlineData(ControlStyles.Opaque, false)]
        [InlineData(ControlStyles.ResizeRedraw, false)]
        [InlineData(ControlStyles.FixedWidth, false)]
        [InlineData(ControlStyles.FixedHeight, false)]
        [InlineData(ControlStyles.StandardClick, true)]
        [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, true)]
        [InlineData((ControlStyles)0, true)]
        [InlineData((ControlStyles)int.MaxValue, false)]
        [InlineData((ControlStyles)(-1), false)]
        public void ListControl_GetStyle_Invoke_ReturnsExpected(ControlStyles flag, bool expected)
        {
            using var control = new SubListControl();
            Assert.Equal(expected, control.GetStyle(flag));

            // Call again to test caching.
            Assert.Equal(expected, control.GetStyle(flag));
        }

        [WinFormsFact]
        public void ListControl_GetTopLevel_Invoke_ReturnsExpected()
        {
            using var control = new SubListControl();
            Assert.False(control.GetTopLevel());
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnBindingContextChanged_Invoke_CallsBindingContextChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.BindingContextChanged += handler;
            control.OnBindingContextChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.BindingContextChanged -= handler;
            control.OnBindingContextChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnDataSourceChanged_Invoke_CallsDataSourceChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.DataSourceChanged += handler;
            control.OnDataSourceChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.DataSourceChanged -= handler;
            control.OnDataSourceChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnDisplayMemberChanged_Invoke_CallsDisplayMemberChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.DisplayMemberChanged += handler;
            control.OnDisplayMemberChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.DisplayMemberChanged -= handler;
            control.OnDisplayMemberChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        public static IEnumerable<object[]> OnFormat_TestData()
        {
            yield return new object[] { null };
            yield return new object[] { new ListControlConvertEventArgs(null, null, null) };
            yield return new object[] { new ListControlConvertEventArgs(new object(), typeof(int), new object()) };
        }

        [WinFormsTheory]
        [MemberData(nameof(OnFormat_TestData))]
        public void ListControl_OnFormat_Invoke_CallsFormat(ListControlConvertEventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            ListControlConvertEventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.Format += handler;
            control.OnFormat(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.Format -= handler;
            control.OnFormat(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnFormatInfoChanged_Invoke_CallsFormatInfoChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.FormatInfoChanged += handler;
            control.OnFormatInfoChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.FormatInfoChanged -= handler;
            control.OnFormatInfoChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnFormatStringChanged_Invoke_CallsFormatStringChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.FormatStringChanged += handler;
            control.OnFormatStringChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.FormatStringChanged -= handler;
            control.OnFormatStringChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnFormattingEnabledChanged_Invoke_CallsFormattingEnabledChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.FormattingEnabledChanged += handler;
            control.OnFormattingEnabledChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.FormattingEnabledChanged -= handler;
            control.OnFormattingEnabledChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnSelectedIndexChanged_Invoke_CallsSelectedValueChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.SelectedValueChanged += handler;
            control.OnSelectedIndexChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.SelectedValueChanged -= handler;
            control.OnSelectedIndexChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnSelectedValueChanged_Invoke_CallsSelectedValueChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // 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);
        }

        [WinFormsTheory]
        [CommonMemberData(nameof(CommonTestHelper.GetEventArgsTheoryData))]
        public void ListControl_OnValueMemberChanged_Invoke_CallsValueMemberChanged(EventArgs eventArgs)
        {
            using var control = new SubListControl();
            int callCount = 0;
            EventHandler handler = (sender, e) =>
            {
                Assert.Same(control, sender);
                Assert.Same(eventArgs, e);
                callCount++;
            };

            // Call with handler.
            control.ValueMemberChanged += handler;
            control.OnValueMemberChanged(eventArgs);
            Assert.Equal(1, callCount);

            // Remove handler.
            control.ValueMemberChanged -= handler;
            control.OnValueMemberChanged(eventArgs);
            Assert.Equal(1, callCount);
        }

        [WinFormsFact]
        public void ListControl_RefreshItems_Invoke_Nop()
        {
            using var control = new SubListControl();
            control.RefreshItemsEntry();
        }

        [WinFormsTheory]
        [InlineData(0, null)]
        [InlineData(-1, 1)]
        public void ListControl_SetItemCore_Invoke_Nop(int index, object value)
        {
            using var control = new SubListControl();
            control.SetItemCoreEntry(index, value);
        }

        private class DataClass
        {
            public object Value { get; set; }
            public object OtherValue { get; set; }
            public IList ListValue { get; set; }

            public override string ToString() => "DataClassToString";
        }

        private class ComponentList : List<int>, IComponent
        {
            public ISite Site { get; set; }

            public event EventHandler Disposed;

            public void Dispose() => OnDisposed(this, EventArgs.Empty);

            public void OnDisposed(object sender, EventArgs e)
            {
                Disposed?.Invoke(sender, e);
            }
        }

        private class SupportInitializeNotificationList : List<int>, ISupportInitializeNotification
        {
            public bool IsInitialized { get; set; }

            public event EventHandler Initialized;

            public void BeginInit()
            {
            }

            public void EndInit()
            {
            }

            public void OnInitialized(object sender, EventArgs e)
            {
                Initialized?.Invoke(sender, e);
            }
        }

        public class SubListControl : ListControl
        {
            public override int SelectedIndex { get; set; }

            public bool AllowSelectionEntry => base.AllowSelection;

            public new bool CanEnableIme => base.CanEnableIme;

            public new bool CanRaiseEvents => base.CanRaiseEvents;

            public new CreateParams CreateParams => base.CreateParams;

            public new CurrencyManager DataManager => base.DataManager;

            public new Cursor DefaultCursor => base.DefaultCursor;

            public new ImeMode DefaultImeMode => base.DefaultImeMode;

            public new Padding DefaultMargin => base.DefaultMargin;

            public new Size DefaultMaximumSize => base.DefaultMaximumSize;

            public new Size DefaultMinimumSize => base.DefaultMinimumSize;

            public new Padding DefaultPadding => base.DefaultPadding;

            public new Size DefaultSize => base.DefaultSize;

            public new bool DesignMode => base.DesignMode;

            public new bool DoubleBuffered
            {
                get => base.DoubleBuffered;
                set => base.DoubleBuffered = value;
            }

            public new EventHandlerList Events => base.Events;

            public new int FontHeight
            {
                get => base.FontHeight;
                set => base.FontHeight = value;
            }

            public new ImeMode ImeModeBase
            {
                get => base.ImeModeBase;
                set => base.ImeModeBase = value;
            }

            public new bool ResizeRedraw
            {
                get => base.ResizeRedraw;
                set => base.ResizeRedraw = value;
            }

            public new bool ShowFocusCues => base.ShowFocusCues;

            public new bool ShowKeyboardCues => base.ShowKeyboardCues;

            public new AutoSizeMode GetAutoSizeMode() => base.GetAutoSizeMode();

            public new bool GetStyle(ControlStyles flag) => base.GetStyle(flag);

            public new bool GetTopLevel() => base.GetTopLevel();

            public new bool IsInputKey(Keys keyData) => base.IsInputKey(keyData);

            public new object FilterItemOnProperty(object item) => base.FilterItemOnProperty(item);

            public new object FilterItemOnProperty(object item, string field) => base.FilterItemOnProperty(item, field);

            public new void OnBindingContextChanged(EventArgs e) => base.OnBindingContextChanged(e);

            public new void OnDataSourceChanged(EventArgs e) => base.OnDataSourceChanged(e);

            public new void OnDisplayMemberChanged(EventArgs e) => base.OnDisplayMemberChanged(e);

            public new void OnFormat(ListControlConvertEventArgs e) => base.OnFormat(e);

            public new void OnFormatInfoChanged(EventArgs e) => base.OnFormatInfoChanged(e);

            public new void OnFormatStringChanged(EventArgs e) => base.OnFormatStringChanged(e);

            public new void OnFormattingEnabledChanged(EventArgs e) => base.OnFormattingEnabledChanged(e);

            public new void OnSelectedIndexChanged(EventArgs e) => base.OnSelectedIndexChanged(e);

            public new void OnSelectedValueChanged(EventArgs e) => base.OnSelectedValueChanged(e);

            public new void OnValueMemberChanged(EventArgs e) => base.OnValueMemberChanged(e);

            public Action RefreshItemsHandler { get; set; }

            public void RefreshItemsEntry() => RefreshItems();

            protected override void RefreshItem(int index)
            {
            }

            protected override void RefreshItems()
            {
                RefreshItemsHandler?.Invoke();
                base.RefreshItems();
            }

            public Action<int, object> SetItemCoreHandler { get; set; }

            public void SetItemCoreEntry(int index, object value) => base.SetItemCore(index, value);

            protected override void SetItemCore(int index, object value)
            {
                SetItemCoreHandler?.Invoke(index, value);
            }

            public Action<IList> SetItemsCoreHandler { get; set; }

            protected override void SetItemsCore(IList items)
            {
                SetItemsCoreHandler?.Invoke(items);
            }
        }

        public class AllowSelectionFalseListControl : SubListControl
        {
            protected override bool AllowSelection => false;
        }

        public class CustomTypeConverterDataClass
        {
            [TypeConverter(typeof(CustomTypeConverter))]
            public int Value { get; set; }

            public override string ToString() => "CustomTypeConverterDataClassToString";
        }

        private class CustomTypeConverter : TypeConverter
        {
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                Assert.Equal(10, value);
                Assert.Equal(typeof(string), destinationType);
                return "custom";
            }
        }

        public class NonCriticalThrowingTypeConverterDataClass
        {
            [TypeConverter(typeof(NonCriticalThrowingTypeConverter))]
            public int Value { get; set; }

            public override string ToString() => "NonCriticalThrowingTypeConverterDataClassToString";
        }

        private class NonCriticalThrowingTypeConverter : TypeConverter
        {
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                throw new InvalidOperationException();
            }
        }

        public class CriticalThrowingTypeConverterDataClass
        {
            [TypeConverter(typeof(CriticalThrowingTypeConverter))]
            public int Value { get; set; }
        }

        private class CriticalThrowingTypeConverter : TypeConverter
        {
            public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
            {
                throw new StackOverflowException();
            }
        }
    }
}
