Usuário com melhor resposta
Thread erro: System.InvalidOperationException: 'Operação entre threads inválida: controle 'progressBar1' acessado de um thread que não é aquele no qual foi criado.'

Pergunta
-
Boa Tarde Gente,
Desculpem a minha ignorância mas estou começando a estudar um pouco de c# e estou com esta dificuldade na parte de threads, ocorre este erro até procurei alguns tutorias mas a internet não tem me ajudado muito, ou não estou sabendo procurar, mas enfim precisa de uma ajuda como corrigir o erro citado acima, algum favor poderia me ajudar, existe algum erro no meu codigo.
att,
Fabio
using System.Threading;
namespace Threads
{
public partial class frmLista01 : Form
{
Thread tarefa;
public frmLista01()
{
InitializeComponent();
}
private void cmdListar_Click(object sender, EventArgs e)
{
//Listar();
tarefa.IsBackground = true;
tarefa.Priority = ThreadPriority.Lowest;
tarefa.Start();
}
public void Listar()
{
for (int i = 0; i <= 100; i++)
{
progressBar1.Value = i;
Thread.Sleep(100);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lblHorario.Text = "Horário: " + DateTime.Now.ToString("hh:mm:ss");
}
private void frmLista01_Load(object sender, EventArgs e)
{
tarefa = new Thread (new ThreadStart(Listar));
timer1.Start();
}
}
}
Respostas
-
Olá,
Isso acontece porque o componente de progressbar foi criado na Thread principal, a do formulário, e você tenta obter o valor de uma logica dentro de outra, elas não se conhecem. Já passei por isso, uma das alternativas que aprendi e adotei usar, é por delegação, veja:
/// <summary> /// Evento botão coletar informação /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnBuscarInfo_Click(object sender, EventArgs e) { btnBuscarInfo.Enabled = false; marcaColetaThread = ColetaAsync(); marcaColetaThread.Priority = ThreadPriority.Highest; marcaColetaThread.Start(); txtResult.Clear(); txtResult.Text = "Coletando informação .........."; }
Aqui eu nomeio uma variave "marcaColetaThread ", do tipo "Thread", que recebe uma "Thead" criada dentro do método "ColetaAsync":
/// <summary> /// Thread chama a execução da rotina de coleta e transfere o retorno para fora /// </summary> /// <returns></returns> public Thread ColetaAsync() { AsyncOperation operation = AsyncOperationManager.CreateOperation(null); return new Thread(new ThreadStart(delegate () { try { string result = Coletar(); operation.PostOperationCompleted(delegate (object source) { // Retorno pra a Thread Principal RetornoColetaCompleted(result); }, null); } catch (Exception ex) { operation.PostOperationCompleted(delegate (object source) { ErrorRetornoColeta((Exception)source); }, ex); } })); }
Nesta função, crio uma operação assíncrona que vai chamar o método que realmente vai fazer o trabalho que quero, e o retorno dela irei passar para outro método "RetornoColetaCompleted" se ocorrer tudo certo, ou "ErrorRetornoColeta" se ocorrer um erro, e dentro destes métodos eu coloco nos objetos do formulário:
/// <summary> /// Expoe o retorno da coleta /// </summary> /// <param name="result"></param> private void RetornoColetaCompleted(string result) { txtResult.Text = result; txtResult.Select(0, 0); btnBuscarInfo.Enabled = true; } /// <summary> /// Expoe e trata o retorno de erro da rotina de coleta /// </summary> /// <param name="error"></param> private void ErrorRetornoColeta(Exception error) { btnBuscarInfo.Enabled = true; txtResult.Text = error.Message; } /// <summary> /// Método coletar informações /// </summary> private string Coletar() { StringBuilder strbl = new StringBuilder(); Identify identificar = new Identify(); strbl.Append(identificar.GetSystemInfo()); strbl.Append(identificar.Framework()); return strbl.ToString(); }
Atenciosamente, Ezequiel S. Daniel
- Marcado como Resposta welington jrModerator terça-feira, 9 de maio de 2017 21:57
Todas as Respostas
-
Olá,
Isso acontece porque o componente de progressbar foi criado na Thread principal, a do formulário, e você tenta obter o valor de uma logica dentro de outra, elas não se conhecem. Já passei por isso, uma das alternativas que aprendi e adotei usar, é por delegação, veja:
/// <summary> /// Evento botão coletar informação /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnBuscarInfo_Click(object sender, EventArgs e) { btnBuscarInfo.Enabled = false; marcaColetaThread = ColetaAsync(); marcaColetaThread.Priority = ThreadPriority.Highest; marcaColetaThread.Start(); txtResult.Clear(); txtResult.Text = "Coletando informação .........."; }
Aqui eu nomeio uma variave "marcaColetaThread ", do tipo "Thread", que recebe uma "Thead" criada dentro do método "ColetaAsync":
/// <summary> /// Thread chama a execução da rotina de coleta e transfere o retorno para fora /// </summary> /// <returns></returns> public Thread ColetaAsync() { AsyncOperation operation = AsyncOperationManager.CreateOperation(null); return new Thread(new ThreadStart(delegate () { try { string result = Coletar(); operation.PostOperationCompleted(delegate (object source) { // Retorno pra a Thread Principal RetornoColetaCompleted(result); }, null); } catch (Exception ex) { operation.PostOperationCompleted(delegate (object source) { ErrorRetornoColeta((Exception)source); }, ex); } })); }
Nesta função, crio uma operação assíncrona que vai chamar o método que realmente vai fazer o trabalho que quero, e o retorno dela irei passar para outro método "RetornoColetaCompleted" se ocorrer tudo certo, ou "ErrorRetornoColeta" se ocorrer um erro, e dentro destes métodos eu coloco nos objetos do formulário:
/// <summary> /// Expoe o retorno da coleta /// </summary> /// <param name="result"></param> private void RetornoColetaCompleted(string result) { txtResult.Text = result; txtResult.Select(0, 0); btnBuscarInfo.Enabled = true; } /// <summary> /// Expoe e trata o retorno de erro da rotina de coleta /// </summary> /// <param name="error"></param> private void ErrorRetornoColeta(Exception error) { btnBuscarInfo.Enabled = true; txtResult.Text = error.Message; } /// <summary> /// Método coletar informações /// </summary> private string Coletar() { StringBuilder strbl = new StringBuilder(); Identify identificar = new Identify(); strbl.Append(identificar.GetSystemInfo()); strbl.Append(identificar.Framework()); return strbl.ToString(); }
Atenciosamente, Ezequiel S. Daniel
- Marcado como Resposta welington jrModerator terça-feira, 9 de maio de 2017 21:57
-
Amigo Ezequiel,
Em primeiro lugar gostaria de agradece-lo pela reposta rapida e objetiva eu testei e funcionou perfeitamente, porém pesquisei e verificquei que também tem como fazer por delegate, funcionou também, e o código ficou desta forma.
using System.Threading;
using System.Reflection;
namespace Threads
{
public partial class frmLista01 : Form
{
Thread tarefa;
public frmLista01()
{
InitializeComponent();
}
private void cmdListar_Click(object sender, EventArgs e)
{
//Listar();
tarefa.IsBackground = true;
tarefa.Priority = ThreadPriority.Lowest;
tarefa.Start();
}
public void Listar()
{
for (int i = 0; i <= 100; i++)
{
//progressBar1.Value = i;
SetControlPropertyValue(progressBar1, "value", i);
Thread.Sleep(100);
}
}
private void timer1_Tick(object sender, EventArgs e)
{
lblHorario.Text = "Horário: " + DateTime.Now.ToString("hh:mm:ss");
}
private void frmLista01_Load(object sender, EventArgs e)
{
tarefa = new Thread (new ThreadStart(Listar));
timer1.Start();
}
delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
private void SetControlPropertyValue(Control oControl, string propName, object propValue)
{
if (oControl.InvokeRequired)
{
SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
oControl.Invoke(d, new object[] { oControl, propName, propValue });
}
else
{
Type t = oControl.GetType();
PropertyInfo[] props = t.GetProperties();
foreach (PropertyInfo p in props)
{
if (p.Name.ToUpper() == propName.ToUpper())
{
p.SetValue(oControl, propValue, null);
}
}
}
}
}att,
Fabio
-
Isso,
Existe varias formas de fazer, eu adotei a primeiro por ter conseguido entender mais rápido, mas você pode utilizar outras maneiras para chegar no mesmo resultado, utilize o que você sinta mais confiança..
Obrigado pelo retorno!!
Atenciosamente, Ezequiel S. Daniel