Pergunta

Eu tenho um PropertyGrid no meu aplicativo que é usado para editar objetos arbitrários. Eu preciso ser capaz de executar uma sub-rotina arbitrária em outro segmento que também olha para esses objetos (funcionalidade de pesquisa, se você está curioso). A questão óbvia é que um usuário pode estar editando um desses objetos ao mesmo tempo a minha linha de pesquisa é lê-lo, o que seria preferível evitar (embora ele provavelmente não vai resultar em nada crítico desde a minha linha de pesquisa é apenas leitura, não escrever).

Chamando lock(obj) é bastante fácil de minha linha de pesquisa, mas depois de olhar através da documentação e uma breve skim através do código PropertyDescriptorGridEntry no refletor, eu posso não parecem encontrar um local análogo ao usar uma chamada System.Threading.Monitor.Enter()/Exit() sobre o objeto em questão no PropertyGrid. Eu estava esperando que seria BeginEdit e EndEdit eventos que tornam este bastante simples, mas eu não consigo encontrar qualquer coisa semelhante. Eu prefiro não bloquear todo o objeto enquanto ele está em exibição no PropertyGrid como que obviamente bloquear o meu fio de pesquisa até que outro objeto foi selecionado.

Eu sou um pouco novo para o modelo de segmentação de Windows Forms, por isso estou esperando há alguma resposta óbvia Acabei esquecido. Qualquer ajuda?

Editar: Synchronously clonagem meus objetos antes de executar a busca de forma assíncrona provavelmente será o suficiente ineficiente que eu poderia muito bem executar a busca em si de forma síncrona - o ponto de executar de forma assíncrona é, naturalmente, para permitir que meus usuários continuar a trabalhar enquanto a procura está em execução. As necessidades de pesquisa para dimensionar bem, como o conjunto de dados que estou passando, eventualmente, acabar por ser arbitrariamente grande, o que torna olhar clonagem síncrona como ele fará com que o problema de usabilidade que eu estou tentando evitar.

Foi útil?

Solução

Eu acho que você vai ter que fazer um pouco de trabalho para isso.

Primeiro, você teria que criar uma implementação ICustomTypeDescriptor que iria basear sua implementação em qualquer TypeDescriptor você normalmente obter para esse tipo.

Em seguida, nas implementações dos métodos que expõem os descritores dos membros que você deseja bloquear, você iria fornecer subclasses que derivam desses descritores e substituir os métodos apropriados para embrulhar um bloqueio ao redor.

Assim, para uma propriedade, você poderia implementar GetProperties para retornar suas subclasses específicas de PropertyDescriptor. Estas subclasses iria substituir o GetValue e métodos SetValue (e outros) e usar um bloqueio ao acessar essas variáveis.

Deve ser mencionado que o bloqueio como esta no segmento interface do usuário é provavelmente uma má idéia, desde que você não quer operações arbitrariamente bloquear nesse segmento. Talvez seja melhor apenas para criar um clone do objeto e, em seguida, ter um método que atualiza o armazenamento de objetos quando você está feito.

Outras dicas

Isso vai realmente não ser thread-safe. Você poderia organizar bits do código de busca para o segmento de interface do usuário, mas isso vai retardar as coisas, e talvez derrotar o ponto da rosca ...

Como rapidamente a necessidade de busca de ser? você pode trabalhar contra um clone? etc

Você pode clonar os dados antes de exibi-lo, e obter o seu fio de pesquisa para o trabalho no clone? Se você deseja que o segmento de pesquisa para "ver" mudanças, você poderia responder a eventos no PropertyGrid e talvez fazer controlados mudanças no clone de alguma forma. (Provavelmente é mais fácil simplesmente usar os dados "obsoletos" embora.)

Eu sei clonagem sons de dados terrivelmente ineficiente, mas enfiar certamente mais simples quando cada thread funciona em dados completamente independentes (ou todos os fios somente leitura).

Eu posso estar errado, mas parece-me que você está vindo do lado errado.

Há duas questões distintas que você precisa para endereço.

Em primeiro lugar, certificando-se de que o PropertyGrid só é sempre acessado no segmento. Se qualquer um dos seus métodos (incluindo a propriedade getter / setters) são acessados ??a partir de outros tópicos, você vai sofrer a dor de maneiras misteriosas. As exceções são InvokeRequired() e Invoke, é claro.

Em segundo lugar, certificando-se de seu segmento de busca pode ser executado corretamente.

Para resolver o primeiro problema, qualquer Verifique se o seu objetos nunca são modificados , exceto pelo segmento interface do usuário, ou fazer tudo do seu evento gatilhos fio de modo consciente de que seus objetos de eventos (como PropertyChanged) são sempre apenas desencadeada no segmento.

O segundo problema é mais fácil - desde que seu segmento de pesquisa só lê a partir de seu núcleo objetos, tudo deve funcionar bem. Sim, seu segmento de busca pode inadvertidamente ver alguns dados parcialmente atualizado, mas é que realmente um problema?

Um casal de pensamentos finais ...

  • não implementar a sua pesquisa para percorrer o próprio PropertyGrid; obter uma lista dos objetos na frente (eles não precisam ser clones) e trabalhar através dessa vez.

  • Você considerou usando processamento ocioso para fazer a pesquisa? O objeto Application dispara um evento cada vez que o aplicativo é executado fora de mensagens para processo - você pode ligar para isso e realizar uma etapa da sua pesquisa cada vez que o evento é acionado. Tipo de uma má-mans rosqueamento, mas com nenhuma das dores de cabeça mutex / bloqueio / semaphone. Eu usei isso com muito bons resultados no passado.

Atualizar : rel Se bem me lembro, PropertyGrid respeita a IEditableObject interface, chamando BeginEdit assim que você começar a modificar uma linha, e EndEdit quando você mover para uma linha diferente. Você pode aproveitar isso para evitar que seu segmento de pesquisa de ver mudanças incompletos.

Update 2 : No seguimento, eu descobri o que você já sabia - que PropertyGrid não respeitar a interface IEditableObject.

Eu tenho uma outra sugestão - embora possa ser mais trabalho do que você quer investir.

Em torno do momento em que o namespace System.Transactions foi introduzido no .NET 2.0, eu vi um artigo sobre o uso da transação de ambiente para fornecer fios de isolamento para objetos. A ideia é que as propriedades do objeto tem de armazenamento dual. Primeiro você tem o valor comprometido, visível para todos os tópicos, e você tem uma variável de segmento local usado para armazenar valores não consolidados em uma base por thread. Quando uma propriedade é modificada, as pede objeto em qualquer transação de ambiente por armazenar o novo valor no segmento local. Quando os commits transação ou rolos trás, o valor para o segmento está armazenado ou descartado.

Infelizmente, eu não posso encontrar o artigo original, embora pareça que CSLA oferece esse suporte. Espero que isso ajude.

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