Имейте в виду, что независимо от сценария причина всегда одинакова в .NET:
Вы пытаетесь использовать ссылочную переменную, значение которой
Nothing
/null
. Если для ссылочной переменной значениеNothing
/null
, это означает, что на самом деле оно не содержит ссылку на экземпляр любого объекта, который существует в куче.Вы либо никогда не присваивали какую-либо переменную, никогда не создавали экземпляр значения, присвоенного переменной, или вы вручную устанавливали переменную, равную
blockquote>Nothing
/null
, или вы вызывали функцию, которая установите для этой переменной значениеNothing
/null
.
При вызове метода к элементу управления, если вызывающий объект находится в другом потоке, чем тот, на котором был создан элемент управления, вам необходимо вызвать с помощью Control.Invoke . Вот пример кода:
// you can define a delegate with the signature you want
public delegate void UpdateControlsDelegate();
public void SomeMethod()
{
//this method is executed by the background worker
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
if (this.InvokeRequired)
{
this.Invoke(new UpdateControlsDelegate(UpdateControls));
}
else
{
UpdateControls();
}
}
private void UpdateControls()
{
// update your controls here
}
Надеюсь, что это поможет.
Вам нужно проверить, требуется ли Invoke для элемента управления, который вы пытаетесь обновить. Что-то вроде этого:
Action<Control, string> setterCallback = (toSet, text) => toSet.Text = text;
void SetControlText(Control toSet, string text) {
if (this.InvokeRequired) {
this.Invoke(setterCallback, toSet, text);
}
else {
setterCallback(toSet, text);
}
}
Изменения в пользовательском интерфейсе могут выполняться с помощью методов Control.Invoke (), это исключение перекрестного потока может быть разрешено с использованием фрагмента кода.
void UpdateWorker()
{
//Here ddUser is the user control
//Action to be performed should be called within { } as like below code
if (this.ddUser.InvokeRequired)
ddUser.Invoke(new MethodInvoker(() => { ddUser.Size = new Size(100, 100); }));
}
Обновлено из Invoke, чтобы начать Invoke
// you can define a delegate with the signature you want
public delegate void UpdateControlsDelegate();
public void SomeMethod()
{
//this method is executed by the background worker
InvokeUpdateControls();
}
public void InvokeUpdateControls()
{
if (this.InvokeRequired)
{
this.BeginInvoke(new UpdateControlsDelegate(UpdateControls));
}
else
{
UpdateControls();
}
}
private void UpdateControls()
{
// update your controls here
}
Паттерн, который может показаться вам полезным, - это выполнить проверку в верхней части функций, которые взаимодействуют с графическим интерфейсом, чтобы убедиться, что вы работаете в правильном потоке или нет, и при необходимости вызовите функцию. Например:
public delegate void InvocationDelegate();
public void DoGuiStuff(){
if (someControl.InvokeRequired){
someControl.Invoke(InvocationDelegate(DoGuiStuff));
return;
}
//GUI manipulation here
}
Используя этот шаблон - если вы находитесь в правильном потоке при вызове метода, он не вызывает себя, но если вы используете другой поток, он будет вызывать себя, а затем return (поэтому логика манипуляций с графическим интерфейсом называется только когда-либо в любом случае).
Чаще всего, лучший способ сделать это с помощью WinForms - использовать BackgroundWorker , который запустит вашу работу в фоновом потоке, но предоставит вам хороший чистый способ сообщить о статусе Вернуться к пользовательскому интерфейсу.
Во многих повседневных .NET-программах явное создание потоков или вызов .Invoke - это признак того, что вы не используете фреймворк в полной мере (конечно, есть много законных причин делать вещи низкого уровня тоже, это просто, что они менее распространены, что люди иногда понимают).