我在Winforms应用中遇到Listbox
的问题,它会以意外的顺序将条目添加两次。
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();
}
}
到目前为止疑难解答步骤
listStepHistory
未在代码中的任何其他位置引用(当然,除了Designer.cs文件外)。它没有绑定到DataSource。Job.Progress.StepHistory
属性进行了双重检查,但它不包含两次相同的消息。每个代码都应该提到一次,因为它应该是。Task.Delay(TimeSpan.FromMilliseconds(500))
的值减少并增加到极值(1,10,100,1000,10000)并且从未见过超过两个条目,也从不少于两个。这似乎排除了并发UI更新作为问题的原因。有趣的是
如果你回头看截图,你会看到Winforms选择了具有最高代码的行(数字),这在导入作业的整个过程中是一致的,最高的数字始终是所选择的数字。这是有道理的,因为我在处理代码之前对代码进行了排序,因此应按数字顺序处理它们 如果您在所选项目之后查看该项目,您将看到这是一个较小的代码。该行(11004)实际上与列表框顶部的第一行相同。同样,所选行(73109)与列表框的底部行相同。
换句话说,重复发生如下(粗体 选择):
A B C D E A B C D E
这很奇怪,因为我已经指示列表框选择最后一项。请注意我的UpdateJobInformation()
方法的最后一步:
if (listStepHistory.Items.Count > 0)
{
//Select the last item (so that it scrolls to the bottom)
listStepHistory.SelectedIndex = listStepHistory.Items.Count - 1;
}
即使我错误地将项目添加了两次,我仍然希望列表框仍然选择最后项目(无论它是否重复),但这不是情况下。
在我看来,重复的条目是"幻像条目"。它们被渲染到屏幕上,但它们不存在于listStepHistory.Items
属性中。
我从中得出结论,列表框呈现的内容与其Items
属性中包含的内容不同。
任何人都可以解释这种行为吗?
附录
根据要求,Job
和Job.Progress
接口/类定义:
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>();
}
答案 0 :(得分:2)
而不是使用新的ListBox.ObjectCollection,只需添加数组
listStepHistory.Items.AddRange(Job.Progress.StepHistory.ToArray());