A problem in c# using Threads and 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
li开发者_JS百科stView1.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.
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.
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.
精彩评论