Flater
Flater

Reputation: 13823

Winforms listbox showing items twice

I'm encountering an issue with a Listbox in a Winforms app, where it adds the entries twice, in an unexpected order.

enter image description here

private async void btnStart_Click(object sender, EventArgs e)
{
    Job.Start();

    await StartProgressTracking();
}

public async Task StartProgressTracking()
{    
    while (!Job.Progress.EndTime.HasValue)
    {
        await Task.Run(() => UpdateJobInformation());
        await Task.Delay(TimeSpan.FromMilliseconds(500));
    }
}

private void UpdateJobInformation()
{
    this.UIThread(() => 
    {
        listStepHistory.SelectedIndex = -1;
        listStepHistory.Items.Clear();

        listStepHistory.Items.AddRange(new ListBox.ObjectCollection(listStepHistory, Job.Progress.StepHistory.ToArray()));
        if (listStepHistory.Items.Count > 0)
        {
            //Select the last item (so that it scrolls to the bottom)
            listStepHistory.SelectedIndex = listStepHistory.Items.Count - 1;
        }
    });            
}

// The extension method that I'm using

public static void UIThread(this Control @this, Action code)
{
    if (@this.InvokeRequired)
    {
        @this.BeginInvoke(code);
    }
    else
    {
        code.Invoke();
    }
}

Troubleshooting steps, so far

Interesting to note

If you look back at the screenshot, you will see that Winforms has selected the line with the highest code (numerically), this is consistent throughout the progress of the import job, the highest number is always the one that is selected. This makes sense, as I've ordered the codes before processing them, so they should be processed in numerical order.
If you look at the item after the one that is selected, you will see that this is a smaller code. This line (11004) is in fact the same as the first line at the top of the listbox. Similarly, the selected line (73109) is the same as the bottom line of the listbox.

In other words, the duplication happens as follows (and bold is selected):

A B C D E A B C D E

This is weird, because I've instructed the listbox to select the last item. Notice the last step in my UpdateJobInformation() method:

if (listStepHistory.Items.Count > 0)
{
    //Select the last item (so that it scrolls to the bottom)
    listStepHistory.SelectedIndex = listStepHistory.Items.Count - 1;
}

Even if I had mistakenly added the items twice, I would expect the listbox to still select its last item (regardless of whether it's a duplicate or not), but that is not the case.

It seems to me that the duplicate entries are a "phantom entries". They get rendered to the screen, but they do not exist inside the listStepHistory.Items property.

I conclude from this that the listbox is rendering something differently than what is contained in its Items property.

Can anyone explain this behavior?


Appendix

As requested, the Job and Job.Progress interface/class definitions:

public interface IProgressTrackable
{
    ImportProgress Progress { get; }

    void Start();
    bool Cancel();
}

public class ImportProgress
{
    //redacted for brevity

    public List<string> StepHistory { get; set; } = new List<string>();
}

Upvotes: 0

Views: 699

Answers (1)

Kailash Chandra Polai
Kailash Chandra Polai

Reputation: 241

instead of using new ListBox.ObjectCollection, simply add the array

listStepHistory.Items.AddRange(Job.Progress.StepHistory.ToArray());

Upvotes: 2

Related Questions