Как правильно показали другие, это происходит, когда компонент пользовательского интерфейса расположен или завершен (возврат), когда другой поток все еще вызывает код для того же компонента пользовательского интерфейса.
Это обычно происходит, когда пользователь закрывает окно (форму), которое было обновлено другим потоком, и это более распространено, когда частота обновления высока (потому что вероятность неполного вызова при закрытии формы пользователем высокий).
Это может быть изящно обработано:
- Установить флаг, чтобы указать, что выполняется вызов
- Перехватить удаление или возврат пользовательского интерфейса
- Остановить дальнейшие (новые) вызовы
- Дождаться окончания существующих вызовов
- Заполнить запланированную утилизацию или вернуть
Ниже приведен пример того, как изящно обрабатывать наиболее распространенный сценарий (когда форма закрыта во время ее обновления).
Пример взят из простой формы со списком, который обновляется из внешнего потока с помощью открытого метода (AddItem (string)).
Флаги
private bool invokeInProgress = false;
private bool stopInvoking = false
Код вызова
public void AddItem(string newItem)
{
if (listView1.InvokeRequired)
{
if (stopInvoking != true) // don't start new invokes if the flag is set
{
invokeInProgress = true; // let the form know if an invoke has started
listView1.Invoke(new Action(() => addItem(newItem))); // invoke
invokeInProgress = false; // the invoke is complete
}
return;
}
listView1.Items.Add(newItem);
listView1.Items[listView1.Items.Count - 1].EnsureVisible();
}
Перехват и управление событием закрытия формы
private async void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (invokeInProgress)
{
e.Cancel = true; // cancel the original event
stopInvoking = true; // advise to stop taking new work
// now wait until current invoke finishes
await Task.Factory.StartNew(() =>
{
while (invokeInProgress);
});
// now close the form
this.Close();
}
}
Вы можете дополнительно расширить это, выставив метод или свойство, которое позволяет пользователям (другим потокам) знать, что форма закрывается, чтобы вызывающие могли изящно справиться с ситуацией.
Пример ниже показывает, как новое свойство (ShuttingDown) позволяет вызывающей стороне правильно обрабатывать свой поток, если пользователь закрывает форму отображения.
Новый флаг в форме
public bool ShuttingDown { get { return stopInvoking; } }
Звонящий теперь может обнаружить проблему
static void Main()
{
Form1 frm = new Form1();
Task.Factory.StartNew(() => frm.ShowDialog(), TaskCreationOptions.LongRunning);
int i = 0;
while (i < 2000)
{
if (frm.ShuttingDown != true) // the clients can also be notified and allowed to handle the UI disruption
{
frm.addItem(Guid.NewGuid().ToString());
}
else
{
MessageBox.Show("Form is closing. Stopping the process.");
break;
}
i++;
}
MessageBox.Show("Program completed! i=" + i.ToString());
}
Вы можете прочитать больше и загрузить пример проекта отсюда: http://www.ilearnttoday.com/c-sharp-the-destination-thread-no-longer-exists