Проблема в C # с использованием потоков и ListView - PullRequest
2 голосов
/ 20 февраля 2010

У меня есть текстовый фильтр, в котором в событии TextChanged я запускаю заполненный код представления списка следующим образом:

ThreadPool.QueueUserWorkItem(new WaitCallback(populate));

Тогда в методе 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 в фоновом потоке.

Ответы [ 2 ]

5 голосов
/ 20 февраля 2010

Вы не можете обновить элементы пользовательского интерфейса из любого потока, кроме потока пользовательского интерфейса. Для этого используйте Control.Invoke / BeginInvoke.

Вы можете выполнять всю загрузку данных и т. Д. В фоновом потоке, но вам необходимо выполнить маршалинг в поток пользовательского интерфейса, чтобы фактически заполнить сами элементы управления пользовательского интерфейса.

Это имеет место в большинстве сред пользовательского интерфейса - и, конечно, в Windows Forms (для настольных ПК и CF) и Windows Presentation Foundation (где вы используете Dispatcher, а не Control.Invoke / BeginInvoke).

Замечание: если я правильно помню, Compact Framework поддерживает только делегат EventHandler для Control.Invoke / BeginInvoke. Это, возможно, изменилось в более поздних версиях.

1 голос
/ 20 февраля 2010

Как уже упоминалось в других сообщениях, чтобы обновить ListView из другого потока, вы должны сделать это правильно, используя BeginInvoke / Invoke. Я создал для себя пару вспомогательных функций, которые являются потокобезопасными (как для ListView, так и для других элементов управления). Всякий раз, когда я хочу сделать что-то с помощью 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);
Надеюсь, это поможет:)

Редактировать: я пропустил компактный тег рамки, поэтому не уверен, что это применимо к нему. Кто-то должен быть в состоянии подтвердить это ты.

...