Jump to content
  • Revista PROGRAMAR: Já está disponível a edição #60 da revista programar. Faz já o download aqui!

Sign in to follow this  
msr

Thread + ListBox

Recommended Posts

msr

Olá,

Estou aqui com um problema.

Criei uma nova WinForm e agora tenho uma thread cujo código queria que utilizasse uma LisbBox, no entanto tal não é possível. Obtenho o seguinte erro "control acessed from a thread other than the thread it was created on".

Porque é que tal não é possivel e como posso resolver a situação?

Obrigado

Share this post


Link to post
Share on other sites
mjamado

Boas, msr.

Esse erro acontece porque - já deves ter adivinhado - não podes alterar as propriedades de um componente numa thread que não a criadora do mesmo. Há várias razões para isso, mas explicá-las está fora do âmbito desta posta.

A solução é usar um delegate para que o componente seja alterado assim que o processador tiver um tempinho disponível. Tipo isto:

delegate void SetPropriedadeComponenteCallback(Control componente, string propriedade, object valor);

private void SetPropriedadeComponente(Control componente, string propriedade, object valor)
{
    if(componente.InvokeRequired)
    {
        SetPropriedadeComponenteCallback dlgt = new SetPropriedadeComponenteCallback(SetPropriedadeComponente);
        componente.Invoke(dlgt, new object[] {componente, propriedade, valor});
    }
    else
    {
        Type tipo = componente.GetType();
        PropertyInfo[] propriedades = t.GetProperties();

        foreach (PropertyInfo p in propriedades)
            if (p.Name == propriedade)
                p.SetValue(componente, valor, null);
    }
}

/* O teu código normal, por aqui abaixo */

public void TeuThreadStarter()
{
    /* o teu código por aqui
        Quando quiseres mudar a propridade da tal listbox: */
    this.SetPropriedadeComponente(tuaListBox, "propriedadeAMudar", valorAMudar);

    // o resto do código normalmente
}

Se googlares pelo erro, o mais provável é que a primeira solução que encontres seja colocar o Control.CheckForIllegalCrossThreadCalls a falso. Não o faças. Há boas razões para essa verificação existir e deixa-a ficar, que está bem. A maneira correcta é mesmo com delegates.

Abraços!


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites
bruno1234

A solução do delegate é boa, no entanto é preciso ter em atenção uma coisa...

Quantas threads vais querer q actualizem a caixa? Essas threads n podem antes fazer o trabalho delas e devolver  o valor á thread principal?

Cuidado com a utilização de várias threads a afectarem o UI, pq se alguma coisa correr mal, o debug é complicado.


Matraquilhos para Android.

Gratuito na Play Store.

https://play.google.com/store/apps/details?id=pt.bca.matraquilhos

Share this post


Link to post
Share on other sites
msr

Obrigado pelas respostas e pelo código exemplo. Bastante explícito!

Já tenho isto a funcionar com o delegate.

Este caso é muito simples, tenho apenas 1 thread a correr. Mas já agora bruno1234, se fossem várias a afectarem o UI o que deveria fazer? Colocar um lock na chamada da função que altera o componente? Esse caso nao poderia criar situações de impasse?

Obrigado

Share this post


Link to post
Share on other sites
bruno1234

Se fossem várias threads depende de como quisesses fazer.

O lock é uma solução, se for bem feito, n causa deadlocks, mas preferia optar por outra solução.

O que fazia era criar as threads para fazerem o seu trabalho, e devolviam o resultado para a thread principal q as lançou, e essa thread ficava então responsável por todas as alterações ao UI.


Matraquilhos para Android.

Gratuito na Play Store.

https://play.google.com/store/apps/details?id=pt.bca.matraquilhos

Share this post


Link to post
Share on other sites
mjamado

bruno1234, como é que devolves o resultado de um thread à thread principal? Isso é novidade para mim, e olha que já ando no C# há muitos anos...

msr, o ónus da integridade dos dados está sempre do lado do programador. Quando estás a mexer em dados que precisem de ser lidos e escritos por várias threads ao mesmo tempo, o melhor mesmo é usar semáforos nas partes sensíveis, ou então montar um esquema em que cada thread mexa em pedaços separados.

Abraços!


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites
mjamado
Com um BackgroundWorker, por exemplo.

Fiquei pacientemente à espera que elaborasses; não o fizeste. Mas eu explico: o BackgroundWorker não "devolve" nada à thread principal, porque isso é impossível - aliás, o próprio conceito de assincronacidade não o permite. O que acontece é que é chamado um evento no final, cujo callback na thread principal vai buscar os dados finais, se forem passados. E isso podes fazer, também, na Thread, definindo o teu próprio evento.

O problema da integridade e consistência dos dados mantêm-se, visto que cada BW chamado irá disparar o evento e nada te garante que as threads acabem pela ordem com que foram chamadas. Na realidade, terás que garantir tu próprio a integridade e consistência dos dados no callback do RunWorkerCompleted...

O BackgroundWorker não é mais que uma Thread com eventos e com alguns settings já definidos (por exemplo, a Thread pode ser definida como foreground e o BackgroundWorker, como o próprio nome indica, não). E é mais pesada ao nível da instanciação (herda de Component, se não estou em erro).


"Para desenhar um website, não tenho que saber distinguir server-side de client-side" - um membro do fórum que se auto-intitula webdesigner. Temo pelo futuro da web.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.