Вызывающий поток не может получить доступ к этому объекту, потому что другой поток владеет им. исключение
private void Thread1_Exe()
{
try
{
int sleepValT1 = Convert.ToInt32(listBoxT2.SelectedValue);
int StartLoop = 0;
int EndLoop = 10000;
for (int i = StartLoop; i <= EndLoop; i++)
{
Dispatcher.BeginInvoke(
new Action(() => listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
Thread.Sleep(sleepValT1);
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
Я пытался вызвать вышеуказанную функцию в другом потоке
private void thread1_Click(object sender, RoutedEventArgs e)
{
threadBtn1.IsEnabled = false;
Thread t1 = new Thread(new ThreadStart(Thread1_Exe));
t1.Start();
}
Но исключение возникает, когда я выбираю значение из списка и пытаюсь сохранить его в переменной, а затем пытаюсь передать это значение в
Thread.Sleep()
Я всегда получаю это исключение, что другой поток владеет этим объектом. Перепробовал много вещей. Пожалуйста, помогите мне, где я делаю ошибку.
Спасибо
2 ответа
Ваша проблема в том, что вы получаете доступ к элементу управления пользовательского интерфейса из фонового потока. Пользовательские интерфейсы, как правило, являются однопоточными, поэтому вам необходимо координировать доступ к элементам управления, чтобы это всегда происходило через поток пользовательского интерфейса.
Самое простое, что вы можете сделать, это прочитать значение из списка, прежде чем запускать новый поток:
private void Thread1_Exe(int sleepVal)
{
try
{
int StartLoop = 0;
int EndLoop = 10000;
for (int i = StartLoop; i <= EndLoop; i++)
{
Dispatcher.BeginInvoke(
new Action(() =>
listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
Thread.Sleep(sleepVal);
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
private void thread1_Click(object sender, RoutedEventArgs e)
{
threadBtn1.IsEnabled = false;
int sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue);
Thread t1 = new Thread(() => Thread1_Exe(sleepValT1));
t1.Start();
}
Другие альтернативы включают доступ к элементу управления через поток диспетчера:
private void Thread1_Exe()
{
try
{
int sleepValT1;
listBoxT1.Dispatcher.Invoke(() => sleepValT1 = Convert.ToInt32(listBoxT1.SelectedValue));
int StartLoop = 0;
int EndLoop = 10000;
for (int i = StartLoop; i <= EndLoop; i++)
{
Dispatcher.BeginInvoke(
new Action(() =>
listboxE1.Items.Add("T1: Execution Count> " + i.ToString())));
Thread.Sleep(sleepValT1);
}
}
catch (Exception Ex)
{
MessageBox.Show(Ex.Message);
}
}
private void thread1_Click(object sender, RoutedEventArgs e)
{
threadBtn1.IsEnabled = false;
Thread t1 = new Thread(() => Thread1_Exe());
t1.Start();
}
Как правило, вы действительно хотите по возможности избегать совместного использования изменяемого состояния между потоками, чтобы было легче рассуждать.
Любой доступ к GUI
элемент, независимо от того, читается он или пишется, должен называться через main-UI-thread
, Эта тема доступна через Dispatcher
,
В вашем коде я вижу строку, где это не так - когда вы звоните listBoxT2.SelectedValue
Чтобы исправить ошибку, назовите этот код на Dispatcher Thread
и сохраните его в локальной переменной:
int selectedValue;
listBoxT2.Dispatcher.Invoke(() => selectedValue = Convert.ToInt32(listBoxT2.SelectedValue));
Остальная часть кода должна работать нормально.