【发布时间】:2019-04-24 00:15:51
【问题描述】:
我正在尝试创建一个绑定到列表的列表框,当它检查或对列表中的每个元素执行特定处理时,它会更改列表框控件上该项的颜色。 第一次加载列表框时,它会显示列表中的所有元素,并通过我的 listbox_Drawitem 事件处理程序接收 DrawItemEventArgs 事件。 但是当我想刷新列表框以使用更新的状态或颜色重绘项目时,它永远不会通过 listbox_DrawItem 事件处理程序。
我尝试单独使用刷新方法,但没有成功。 我尝试将 list.Datasource 设置为 null,然后是 list.refresh,这会擦除列表框中的所有内容,然后再次将数据源设置为我的列表并刷新,但没有任何反应。
我正在使用两个线程,当我从 UI 表单以外的另一个线程编辑控件时,我通过委托来避免跨线程错误。到目前为止,它一直在工作,除了 DrawItem 处理程序,它应该通过我的控件被我的委托中的 safeRefreshAllMethod 内的刷新重绘而触发。
这是我的 UI 表单中的代码:
public partial class Form1 : Form
{
public delegate void SafeRefresh();
public SafeRefresh myDelegate;
private Form1 currentForm;
Thread scriptThread;
public Form1()
{
InitializeComponent();
currentForm = this;
myDelegate = new SafeRefresh(SafeRefreshAllMethod);
}
private async void button_script_Click(object sender, EventArgs e)
{
scriptThread = new Thread( () => SomeClass.RunScript(currentForm));
scriptThread.Start();
}
public void SafeRefreshAllMethod()
{
listBox.DataSource = null;
listBox.Refresh();
listBox.DataSource = Global.ListAllItems;
listBox.Refresh();
}
public void listBox_DrawItem(object sender, DrawItemEventArgs e)
{
Brush myBrush;
if (Global.ListItemsDisconnected.Contains(Global.ListAllItems[e.Index] ))
{
myBrush = Brushes.Gray;
}
else if (Global.ListItemsConnected.Contains(Global.ListAllItems[e.Index]))
{
myBrush = Brushes.Green;
}
else
{
myBrush = Brushes.Black;
}
e.DrawBackground();
e.Graphics.DrawString(listBox.Items[e.Index].ToString(), listBox.Font, myBrush, e.Bounds);
}
}
这是表单中新线程执行的代码,它调用委托来刷新列表框控件:
class SomeClass {
public static void RunScript(Form1 theForm)
{
theForm.Invoke(theForm.myDelegate);
foreach (string item in Global.ListAllItems)
{
//some code that works with the items on list
//if disconnected : adds to Global.ListItemsDisconnected
//if connected: adds it to Global.ListItemsConnected
theForm.Invoke(theForm.myDelegate);
}
}
}
我想知道是否有人知道为什么 listBox_DrawItem 会在线程第一次调用控件时触发,绘制列表中的所有项目。但是当我尝试用不同的颜色刷新和重绘列表时,处理程序永远不会被调用。
【问题讨论】:
-
我无法复制这个。每次我单击按钮时,脚本都会运行良好并且会调用 DrawItem。你能解释一下你是如何尝试刷新和重绘的吗
-
调试时,我可以看到“RunScript”中的第一条语句中的“theForm.Invoke(theForm.myDelegate”) 进程如何调用“SafeRefreshAllMethod”,然后是事件处理程序“listBox_DrawItem”被触发。这是第一次在 listBox 中绘制项目,但是一旦 foreach 循环运行并且再次调用相同的方法,'listBox_DrawItem' 处理程序不会被触发,因此在将数据源设置为 null 后项目就会消失,但刷新后它们永远不会重绘。
-
我看到当委托在 foreach 循环中调用时调用它,当我们在行 listBox1.DataSource = Global.ListAllItems; 上设置数据源时调用 drawItem 事件;
标签: c# forms delegates thread-safety eventhandler