'Why does a function that loads a ListView take significantly longer to run when called from the app compared to at start-up?

I am using a ListView in a Forms App which takes significantly longer to load the ListView with content if the load function is called from a button click (Reload ListView) compared to being called at start-up in the Form() function – see code.

The Forms app has a ListView (listView1) with three columns, a ‘Clear ListView’ button (button2) to clear the contents of the ListView, and a ‘Reload ListView’ button (button1) to call the same LoadListViewItems() function that is called at start-up. The Form also includes a TextBox (textBox1) to displaying the results (number of items loaded, time taken to load).

When I talk about it being slower, based upon the tests performed it is about 200x slower.

On my laptop it takes between 3 to 6 ms to load the ListView at start-up compared 953 to 1044 ms when clicking the Reload button following the ListView being cleared ‘Clear ListViw’ button.

I’ve tried disabling the redraw until the ListView has loaded by uncommenting out:

SendMessage(this.Handle, WM_SETREDRAW, false, 0);
SendMessage(this.Handle, WM_SETREDRAW, true, 0);
this.Refresh();

This has no effect on the time taken to load at start-up but results in a slightly faster time using the Load button: 727 to 769 ms.

If I comment out:

lvwColumnSorter = new ListViewColumnSorter();
this.listView1.ListViewItemSorter = lvwColumnSorter;

in the InitializeListView1() function which disables the column sort, it has no effect on the start-up load time but does improve the Reload button time: 180 to 203 ms. It is therefore clear that this is having an effect.

My question is, why does the ListView load significantly quicker at start-up compared to loading the ListView with the same using a button on the Forms app, and how can I make it load faster from the Forms apps whilst retaining the column sort functionality?

Form1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace FormsAppListView
{
    public partial class Form1 : Form
    {
        public bool MultiSelect { get; set; }
        private ListViewColumnSorter lvwColumnSorter;

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam);
        private const int WM_SETREDRAW = 11;

        public Form1()
        {
            InitializeComponent();

            InitializeListView1();

            LoadListViewItems();
        }

        // This method adds two columns to the ListView, setting the Text 
        // and TextAlign, and Width properties of each ColumnHeader.  The 
        // HeaderStyle property is set to NonClickable since the ColumnClick 
        // event is not handled.  Finally the method adds ListViewItems and 
        // SubItems to each column.
        private void InitializeListView1()
        {
            // Create an instance of a ListView column sorter and assign it
            // to the ListView control.
            lvwColumnSorter = new ListViewColumnSorter();
            this.listView1.ListViewItemSorter = lvwColumnSorter;
            this.listView1.Name = "ListView1";
            this.listView1.TabIndex = 0;
            this.listView1.View = System.Windows.Forms.View.Details;
            this.listView1.MultiSelect = true;
            this.listView1.HideSelection = false;
            this.listView1.HeaderStyle = ColumnHeaderStyle.Clickable;
            this.listView1.GridLines = true;
            this.Controls.Add(listView1);
        }

        private void ListView1_ColumnClick(object sender, ColumnClickEventArgs e)
        {
            // Determine if clicked column is already the column that is being sorted.
            if (e.Column == lvwColumnSorter.SortColumn)
            {
                // Reverse the current sort direction for this column.
                if (lvwColumnSorter.Order == SortOrder.Ascending)
                {
                    lvwColumnSorter.Order = SortOrder.Descending;
                }
                else
                {
                    lvwColumnSorter.Order = SortOrder.Ascending;
                }
            }
            else
            {
                // Set the column number that is to be sorted; default to ascending.
                lvwColumnSorter.SortColumn = e.Column;
                lvwColumnSorter.Order = SortOrder.Ascending;
            }

            // Perform the sort with these new sort options.
            this.listView1.Sort();
        }

        private void LoadListViewItems()
        {
            try
            {
                int i = 0;

                //SendMessage(this.Handle, WM_SETREDRAW, false, 0);

                long start_ms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;

                for (i = 0; i < 1001; i++)
                {
                    string col1 = "item-" + i;
                    string col2 = "sub-item-" + i + "a";
                    string col3 = "sub-item-" + i + "b";

                    ListViewItem listItem = new ListViewItem(col1);
                    listItem.SubItems.Add(col2);
                    listItem.SubItems.Add(col3);
                    listView1.Items.Add(listItem);

                }
                textBox1.Text = "items added = " + i + Environment.NewLine;

                long end_ms = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
                textBox1.Text += "Time taken to add = " + (end_ms - start_ms) + " ms" + Environment.NewLine;

                //SendMessage(this.Handle, WM_SETREDRAW, true, 0);
                //this.Refresh();
            }
            catch (Exception error)
            {
                //Console.WriteLine(error.Message);
                string errorMessage = "Error: " + error.Message + Environment.NewLine;
                MessageBox.Show(errorMessage);
                return;
            }
        }

        private void button2_Click(object sender, EventArgs e)
        {
            listView1.Items.Clear();                // Clear current ListView
        }

        private void button1_Click(object sender, EventArgs e)
        {
            LoadListViewItems();
        }
    }
}


Class1.cs
using System.Collections;
using System.Windows.Forms;

/// <summary>
/// This class is an implementation of the 'IComparer' interface.
/// </summary>
public class ListViewColumnSorter : IComparer
{
    /// <summary>
    /// Specifies the column to be sorted
    /// </summary>
    private int ColumnToSort;

    /// <summary>
    /// Specifies the order in which to sort (i.e. 'Ascending').
    /// </summary>
    private SortOrder OrderOfSort;

    /// <summary>
    /// Case insensitive comparer object
    /// </summary>
    private CaseInsensitiveComparer ObjectCompare;

    /// <summary>
    /// Class constructor. Initializes various elements
    /// </summary>
    public ListViewColumnSorter()
    {
        // Initialize the column to '0'
        ColumnToSort = 0;

        // Initialize the sort order to 'none'
        OrderOfSort = SortOrder.None;

        // Initialize the CaseInsensitiveComparer object
        ObjectCompare = new CaseInsensitiveComparer();
    }

    /// <summary>
    /// This method is inherited from the IComparer interface. It compares the two objects passed using a case insensitive comparison.
    /// </summary>
    /// <param name="x">First object to be compared</param>
    /// <param name="y">Second object to be compared</param>
    /// <returns>The result of the comparison. "0" if equal, negative if 'x' is less than 'y' and positive if 'x' is greater than 'y'</returns>
    public int Compare(object x, object y)
    {
        int compareResult;
        ListViewItem listviewX, listviewY;

        // Cast the objects to be compared to ListViewItem objects
        listviewX = (ListViewItem)x;
        listviewY = (ListViewItem)y;

        string temp = listviewX.ListView.Columns[ColumnToSort].Tag.ToString();

        // Compare the two items
        if (temp == "numeric")
        {
            compareResult = ObjectCompare.Compare(int.Parse(listviewX.SubItems[ColumnToSort].Text), int.Parse(listviewY.SubItems[ColumnToSort].Text));
        }
        else
        {
            compareResult = ObjectCompare.Compare(listviewX.SubItems[ColumnToSort].Text, listviewY.SubItems[ColumnToSort].Text);
        }

        // Calculate correct return value based on object comparison
        if (OrderOfSort == SortOrder.Ascending)
        {
            // Ascending sort is selected, return normal result of compare operation
            return compareResult;
        }
        else if (OrderOfSort == SortOrder.Descending)
        {
            // Descending sort is selected, return negative result of compare operation
            return (-compareResult);
        }
        else
        {
            // Return '0' to indicate they are equal
            return 0;
        }
    }

    /// <summary>
    /// Gets or sets the number of the column to which to apply the sorting operation (Defaults to '0').
    /// </summary>
    public int SortColumn
    {
        set
        {
            ColumnToSort = value;
        }
        get
        {
            return ColumnToSort;
        }
    }

    /// <summary>
    /// Gets or sets the order of sorting to apply (for example, 'Ascending' or 'Descending').
    /// </summary>
    public SortOrder Order
    {
        set
        {
            OrderOfSort = value;
        }
        get
        {
            return OrderOfSort;
        }
    }
}


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source