【问题标题】:The Refresh method for ListBox won't trigger the event handler for the DrawItem propertyListBox 的 Refresh 方法不会触发 DrawItem 属性的事件处理程序
【发布时间】: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


【解决方案1】:

查看 Designer 并尝试将 DrawMode 属性更改为 OwnerDrawFixed

ListBox DrawMode Example

【讨论】:

  • 我已经尝试过了,它在我的环境中运行良好。如果您将 Global 类添加到您的问题中可能会更好,以便我们可以重现该问题。@BLM
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多