Pergunta

Eu estou escrevendo um aplicativo WinForms que tem dois modos: console ou GUI. Três projetos dentro da mesma solução, um para o aplicativo console, um para as formas de interface do usuário eo terceiro para manter a lógica de que as duas interfaces serão ambos conectar também. O aplicativo Console corre absolutamente sem problemas.

Um modelo que mantém a facilidade de seleções, tem uma IList<T> onde T é um objeto local, Step, que implementa INotifyPropertyChanged, assim, no UI este é montado em um DataGridView. Tudo está bem em tempo de execução, o estado inicial dos objetos é refletida na tela.

Cada um dos objetos Step é uma tarefa que é executada por sua vez; algumas das propriedades mudará, sendo reflectida de volta para o IList e passada para o DataGridView.

Esta ação nas versões de interface do usuário é feito através da criação de um BackgroundWorker levantando eventos voltar para a interface do usuário. O Step faz coisa e gera um objeto StepResult que é um tipo enumerado indicando um resultado (por exemplo, Correr, NotRun, OK, notok, Caveat) e uma corda para indicar uma mensagem (porque o correu passo, mas não tão esperado, ou seja, com uma advertência). Normalmente as acções envolverá uma interacção da base de dados, mas em modo de depuração eu gerar aleatoriamente um resultado.

Se a mensagem é nulo, nunca há um problema, mas se eu gerar uma resposta como esta:

StepResult returnvalue = new StepResult(stat, "completed with caveat")

Eu recebo um erro dizendo que o DataGridView foi sendo acessado de um thread diferente do thread que foi criado. (Eu estou passando isso por meio de um manipulador personalizado que deve lidar com a invocação quando necessário? - talvez não)

Então, se eu gerar uma resposta única, por exemplo, usando um número r aleatória:

StepResult returnvalue = new StepResult(stat, r.ToString());

as ações ter sucesso sem nenhum problema, os números são escritos de forma clara para o DataGridView.

Estou perplexo. Eu estou assumindo que é de alguma forma um problema literal string, mas alguém pode chegar a uma explicação mais clara?

Foi útil?

Solução

Uma vez que você está fazendo UI ligação via inscrição de evento, você pode encontrar este útil; É um exemplo que eu escrevi há um tempo atrás que mostra como BindingList<T> subclasse para que as notificações estão mobilizados para o segmento de interface do usuário automaticamente.

Se não houver sincronismo de contexto (ou seja, modo de console), em seguida, ele reverte à invocação direta simples, por isso não há nenhuma sobrecarga. Quando executado no segmento interface do usuário, nota que esta utiliza essencialmente Control.Invoke, que se apenas executa o delegado diretamente se ele está no segmento. Então só há qualquer opção se os dados estão sendo editado a partir de um fio não-UI - se projeta o que queremos ;-p

Outras dicas

Você respondeu sua própria quesion: -

Eu recebo um erro dizendo que o DataGridView foi sendo acessado de um thread diferente do thread que foi criado.

WinForms insiste que todas as ações realizadas em formulários e controles são feitos no contexto do segmento do formulário foi criado. A razão para isso é complexo, mas tem muito a ver com a API Win32 subjacente. Para mais detalhes, consulte as várias entradas na The Old New Thing blog.

O que você precisa fazer é usar os métodos InvokeRequired e invocar para assegurar que os controles são sempre acessado a partir do mesmo segmento (pseudocodeish):

object Form.SomeFunction (args)
{
  if (InvokeRequired)
  {
    return Invoke (new delegate (Form.Somefunction), args);
  }
  else
  {
    return result_of_some_action;
  }
}

Eu tive esse mesmo problema antes. Talvez este artigo que eu postei sobre isso pode ajudar.

http: //cyberkruz.vox .com / biblioteca / post / net-problema-assíncronos-e-windows-Forms.html

Eu encontrei este artigo - " Atualizando IBindingList de segmento diferente " - que apontou o dedo da culpa para o BindingList -

Porque o BindingList não está configurado para operações assíncronas, você deve atualizar o BindingList do mesmo segmento que era controlada por diante.

explicitamente passar o formulário pai como um objeto ISynchronizeInvoke e criar um wrapper para o BindingList<T> fez o truque.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top