C#中使用Threads和ListView的问题

发布于 2024-08-22 11:30:04 字数 835 浏览 3 评论 0原文

我有一个文本过滤器,在 TextChanged 事件中我以这种方式启动列表视图填充代码:

ThreadPool.QueueUserWorkItem(new WaitCallback(populate));

然后在填充方法中我有这样的代码,

listView1.BeginUpdate();
listView1.Clear();

// rest of the code

listView1.EndUpdate();

但 listView1.BeginUpdate() 调用给出以下异常:

System.NotSupportedException was unhandled
  Message="An error message cannot be displayed because an optional resource assembly containing it cannot be found"
  StackTrace:
    at Microsoft.AGL.Common.MISC.HandleAr()
    at System.Windows.Forms.ListView.ntvSetStyleEx()
    at System.Windows.Forms.ListView.BeginUpdate()
    at App.frmSelectClient.populate()
    at WorkItem.doWork()
    at System.Threading.Timer.ring()
  InnerException: 

我做错了什么?

我想在后台线程中发出 ListView 的填充。

I have a text filter where in the TextChanged event I launch a listview populate code this way:

ThreadPool.QueueUserWorkItem(new WaitCallback(populate));

Then in the populate method I have code like this

listView1.BeginUpdate();
listView1.Clear();

// rest of the code

listView1.EndUpdate();

but the listView1.BeginUpdate() call gives the following exception:

System.NotSupportedException was unhandled
  Message="An error message cannot be displayed because an optional resource assembly containing it cannot be found"
  StackTrace:
    at Microsoft.AGL.Common.MISC.HandleAr()
    at System.Windows.Forms.ListView.ntvSetStyleEx()
    at System.Windows.Forms.ListView.BeginUpdate()
    at App.frmSelectClient.populate()
    at WorkItem.doWork()
    at System.Threading.Timer.ring()
  InnerException: 

What I am doing wrong?

I would like to issue the populate of the ListView in a background thread.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

℉服软 2024-08-29 11:30:04

您无法从 UI 线程以外的任何线程更新 UI 元素。使用 Control.Invoke/BeginInvoke 来执行此操作。

您可以在后台线程中完成所有数据加载等操作,但您需要编组到 UI 线程以实际填充 UI 控件本身。

大多数 UI 框架都是这种情况 - 当然还有 Windows Forms(桌面和 CF)和 Windows Presentation Foundation(您使用 Dispatcher 而不是 Control.Invoke/BeginInvoke)。

需要注意的一点是:如果我没记错的话,Compact Framework 仅支持 Control.Invoke/BeginInvoke 的 EventHandler 委托。诚然,这在最近的版本中可能已经改变。

You can't update UI elements from any thread other than the UI thread. Use Control.Invoke/BeginInvoke to do this.

You can do all your data loading etc in the background thread, but you'll need to marshal to the UI thread to actually populate the UI controls themselves.

This is the case in most UI frameworks - and certainly Windows Forms (desktop and CF) and Windows Presentation Foundation (where you use a Dispatcher rather than Control.Invoke/BeginInvoke).

One point to note: if I remember rightly, the Compact Framework only supports the EventHandler delegate for Control.Invoke/BeginInvoke. That may have changed in more recent versions, admittedly.

北城孤痞 2024-08-29 11:30:04

就像其他帖子中提到的从另一个线程更新 ListView 一样,您必须使用 BeginInvoke/Invoke 以正确的方式执行此操作。我为自己创建了几个线程安全的辅助函数(对于 ListView 和更多控件)。每当我想用列表视图或控件本身做某事时,我只使用下面提到的其中之一。当然,它错过了很多其他选项,但到目前为止我还不需要其他选项,所以我没有创建更多选项,但它应该向您展示最终将它们添加到列表中的正确方法。

internal class GlobalFunctions {
    public static void changeControlStatus(Control varControl, bool varState) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new ControlStateChange(changeControlStatus), new object[] {varControl, varState});
        } else {
            varControl.Enabled = varState;
        }
    }
    public static void changeControlText(Control varControl, string varText) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new ControlTextChange(changeControlText), new object[] {varControl, varText});
        } else {
            varControl.Text = varText;
        }
    }
    public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            return (string) varControl.Invoke(new Func<String>(() => readControlText(varControl)));
        } else {
            string varText = varControl.Text;
            return varText;
        }
    }
    public static int listViewCountItems(ListView varControl) {
        if (varControl.InvokeRequired) {
            return (int) varControl.Invoke(new Func<int>(() => listViewCountItems(varControl)));
        } else {
            return varControl.Items.Count;
            //string varText = varControl.Text;
            //return varText;
        }
    }
    public static void comboBoxClearItems(ComboBox varControl) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => comboBoxClearItems(varControl)));
        } else {
            varControl.Items.Clear();
        }
    }
    public static void listViewClearItems(ListView varListView) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new ListViewHandler(listViewClearItems), new object[] {varListView});
        } else {
            varListView.Items.Clear();
        }
    }
    public static void listViewClearColumns(ListView varListView) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new ListViewHandler(listViewClearColumns), new object[] {varListView});
        } else {
            varListView.Clear();
        }
    }
    public static void listViewAddItem(ListView varListView, ListViewItem item) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddItem(varListView, item)));
        } else {
            varListView.Items.Add(item);
        }
    }
    public static void listViewEditItem(ListView varListView, int varRow, int varColumn, string varText) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewEditItem(varListView, varRow,varColumn, varText )));
        } else {
            varListView.Items[varRow].SubItems[varColumn].Text = varText;
        }
    }
    public static void listViewEditItemColor(ListView varListView, int varRow, Color varColor) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewEditItemColor(varListView, varRow, varColor)));
        } else {
            varListView.Items[varRow].BackColor = varColor;
        }
    }
    public static void listViewChangeBackColor(ListView varListView, ListViewItem item, Color varColor) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewChangeBackColor(varListView, item, varColor)));
        } else {
            for (int i = 0; i < varListView.Columns.Count; i++) {
                item.UseItemStyleForSubItems = false;
                item.SubItems[i].BackColor = varColor;
            }
        }
    }
    public static void listViewChangeHeaderStyle(ListView varListView, ColumnHeaderStyle varColumnHeaderStyle) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewChangeHeaderStyle(varListView, varColumnHeaderStyle)));
        } else {
            varListView.HeaderStyle = varColumnHeaderStyle;
        }
    }
    public static void listViewAddItemRange(ListView varListView, ListViewItem item) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddItemRange(varListView, item)));
        } else {
            //varListView.Items.Add(item);
            varListView.Items.AddRange(new[] {item});
        }
    }
    public static void listViewAddColumn(ListView varListView, string varColumnName, int varColumnSize) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddColumn(varListView, varColumnName, varColumnSize)));
        } else {
            varListView.Columns.Add(varColumnName, varColumnSize, HorizontalAlignment.Left);
        }
    }
    #region Nested type: ControlStateChange
    private delegate void ControlStateChange(Control varControl, bool varState);
    #endregion
    #region Nested type: ControlTextChange
    private delegate void ControlTextChange(Control varControl, string varText);
    #endregion
    private delegate string ControlTextRead(Control varControl);
    #region Nested type: ListViewHandler
    private delegate void ListViewHandler(ListView varListView);
    #endregion
    #region Nested type: ListViewHandlerItem
    private delegate void ListViewHandlerItem(ListView varListView, ListViewItem item);
    #endregion
}

用法很简单:GlobalFunctions.listViewClearItems(yourListView);

编辑:我错过了紧凑框架标签,所以不确定这是否适用于它。你应该有人能够证实这一点。

Like it was mentioned in other posts to update ListView from another thread you have to do it the proper way using BeginInvoke/Invoke. I've created for myself couple of helper functions that are thread safe (for both ListView and more Controls). Whenever i wanna do something with listview or control itself i just use one of those mentioned below. Of course it misses a lot of other options but so far I haven't had a need for something else so i didn't created more, but it should show you the right way to eventually add them up to the list.

internal class GlobalFunctions {
    public static void changeControlStatus(Control varControl, bool varState) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new ControlStateChange(changeControlStatus), new object[] {varControl, varState});
        } else {
            varControl.Enabled = varState;
        }
    }
    public static void changeControlText(Control varControl, string varText) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new ControlTextChange(changeControlText), new object[] {varControl, varText});
        } else {
            varControl.Text = varText;
        }
    }
    public static string readControlText(Control varControl) {
        if (varControl.InvokeRequired) {
            return (string) varControl.Invoke(new Func<String>(() => readControlText(varControl)));
        } else {
            string varText = varControl.Text;
            return varText;
        }
    }
    public static int listViewCountItems(ListView varControl) {
        if (varControl.InvokeRequired) {
            return (int) varControl.Invoke(new Func<int>(() => listViewCountItems(varControl)));
        } else {
            return varControl.Items.Count;
            //string varText = varControl.Text;
            //return varText;
        }
    }
    public static void comboBoxClearItems(ComboBox varControl) {
        if (varControl.InvokeRequired) {
            varControl.BeginInvoke(new MethodInvoker(() => comboBoxClearItems(varControl)));
        } else {
            varControl.Items.Clear();
        }
    }
    public static void listViewClearItems(ListView varListView) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new ListViewHandler(listViewClearItems), new object[] {varListView});
        } else {
            varListView.Items.Clear();
        }
    }
    public static void listViewClearColumns(ListView varListView) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new ListViewHandler(listViewClearColumns), new object[] {varListView});
        } else {
            varListView.Clear();
        }
    }
    public static void listViewAddItem(ListView varListView, ListViewItem item) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddItem(varListView, item)));
        } else {
            varListView.Items.Add(item);
        }
    }
    public static void listViewEditItem(ListView varListView, int varRow, int varColumn, string varText) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewEditItem(varListView, varRow,varColumn, varText )));
        } else {
            varListView.Items[varRow].SubItems[varColumn].Text = varText;
        }
    }
    public static void listViewEditItemColor(ListView varListView, int varRow, Color varColor) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewEditItemColor(varListView, varRow, varColor)));
        } else {
            varListView.Items[varRow].BackColor = varColor;
        }
    }
    public static void listViewChangeBackColor(ListView varListView, ListViewItem item, Color varColor) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewChangeBackColor(varListView, item, varColor)));
        } else {
            for (int i = 0; i < varListView.Columns.Count; i++) {
                item.UseItemStyleForSubItems = false;
                item.SubItems[i].BackColor = varColor;
            }
        }
    }
    public static void listViewChangeHeaderStyle(ListView varListView, ColumnHeaderStyle varColumnHeaderStyle) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewChangeHeaderStyle(varListView, varColumnHeaderStyle)));
        } else {
            varListView.HeaderStyle = varColumnHeaderStyle;
        }
    }
    public static void listViewAddItemRange(ListView varListView, ListViewItem item) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddItemRange(varListView, item)));
        } else {
            //varListView.Items.Add(item);
            varListView.Items.AddRange(new[] {item});
        }
    }
    public static void listViewAddColumn(ListView varListView, string varColumnName, int varColumnSize) {
        if (varListView.InvokeRequired) {
            varListView.BeginInvoke(new MethodInvoker(() => listViewAddColumn(varListView, varColumnName, varColumnSize)));
        } else {
            varListView.Columns.Add(varColumnName, varColumnSize, HorizontalAlignment.Left);
        }
    }
    #region Nested type: ControlStateChange
    private delegate void ControlStateChange(Control varControl, bool varState);
    #endregion
    #region Nested type: ControlTextChange
    private delegate void ControlTextChange(Control varControl, string varText);
    #endregion
    private delegate string ControlTextRead(Control varControl);
    #region Nested type: ListViewHandler
    private delegate void ListViewHandler(ListView varListView);
    #endregion
    #region Nested type: ListViewHandlerItem
    private delegate void ListViewHandlerItem(ListView varListView, ListViewItem item);
    #endregion
}

Usage is simple: GlobalFunctions.listViewClearItems(yourListView);

Edit: i have missed compact framework tag so not sure this is applicable to it. Someone should be able to confirm it thou.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文