Reputation: 13823
I'm encountering an issue with a Listbox
in a Winforms app, where it adds the entries twice, in an unexpected order.
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
listStepHistory
is not being referenced anywhere else in the code (other than the Designer.cs file, of course). It is not bound to a DataSource.Job.Progress.StepHistory
property, it does not contain the same message twice. Every code is mentioned exactly once, as it should be.Task.Delay(TimeSpan.FromMilliseconds(500))
to extreme values (1,10,100,1000,10000) and have never seen more than two entries, also never less than two. This seems to exclude concurrent UI updates as the cause of the problem.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
Reputation: 241
instead of using new ListBox.ObjectCollection, simply add the array
listStepHistory.Items.AddRange(Job.Progress.StepHistory.ToArray());
Upvotes: 2