none
Databinding (C#/Win32) RRS feed

  • Pergunta

  • gente é o seguinte ....

    tenho uma classe vinculada a um textbox (simple Databinding).

     

    class teste

    {

      private string _nome  ;

      public string nome

      {

                                  get {return _nome;}

                                 set {_nome=value;}

      }

    e no form:

     

    --> Textbox1.DataBindings.Add("TEXT", ateste, "nome");

     

    Está funcionando perfeitamente, quando altero o valor do Textbox no form, o atributo nome da classe é atualizado corretamente - é isto que quero ....

     

    PORÉM, quando faço um update no textbox, através de um botão:

    button_click(...)

    {

    Textbox1.Text="ola";

    }

    neste caso o atributo da classe não é atualizado .... Sad

    (Obs.:

    Se eu executar o comando: Textbox1.Databindings[0].Writevalue() --> aí funciona, mas acredito que não seja a solução mais correta).

    Certamente preciso implementar mais alguma coisa além do Databindings.Add....

    Alguma dica?

     

    Obrigado.

    sábado, 3 de janeiro de 2009 13:17

Respostas

  • Olá Gustavo,

     

    Você precisa definir que o DataBinding também será atualizado durante o evento PropertyChanged do TextBox:

     

    Code Snippet

     

     textBox1.DataBindings.Add("Text", ateste, "nome", true, DataSourceUpdateMode.OnPropertyChanged);

     

     

    Abraços,
    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 13:37
    Moderador
  • Olá Gustavo,

     

    Se eu entendi bem a sua estrutura, você está em uma classe derivada, e tanto o controle TextBox quanto o objeto que está ligado via DataBinding estão no formulário base, e você, a partir do formulário derivado, está alterando o controle TextBox (que por acaso está invisível).

     

    É isso?

     

    Nesse caso, uma vez que o controle não pertence à sua classe (é uma variável membro da classe base), o correto seria você não ter a possibilidade de alterar o controle do formulário base diretamente.

     

    O formulário base deveria implementar uma propriedade (Ex: Nome) e você, através do seu formulário derivado, utilizaria essa propriedade para alterar os valores do controle.

     

    O formulário base, como conhece os seus próprios controles e objetos, se encarregaria de alterar a propriedade correta do objeto, fazendo com que tudo funcionasse, independente de quem está visível ou invisível.

     

    Acho que esse seria a alternativa correta...

    ---

     

    De qualquer forma, respondendo sua pergunta, via Reflection você pode fazer o seguinte:

     

    Code Snippet

     

     // Obtém uma referência para a propriedade Nome

     PropertyInfo p = ateste.GetType().GetProperty("nome", BindingFlags.Instance | BindingFlags.Public);

     

     // Altera o valor da propriedade, no objeto que você quer

     p.SetValue(ateste, "Maria", null);

     

     

    Abraços,

    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 15:09
    Moderador

Todas as Respostas

  • Olá Gustavo,

     

    Você precisa definir que o DataBinding também será atualizado durante o evento PropertyChanged do TextBox:

     

    Code Snippet

     

     textBox1.DataBindings.Add("Text", ateste, "nome", true, DataSourceUpdateMode.OnPropertyChanged);

     

     

    Abraços,
    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 13:37
    Moderador
  • Caio, muito obrigado. (certamente o vaor default é DataSourceUpdateMode.NEVER  ... não havia visto isto ...)...

     

    Outra coisa, comofazer agora para que o Databinding continue funcionando se o Textbox for alterado para invisible?

    (neste caso, tudo pára de funcionar e tenho uns contrle hidden no form (win32).

     

    Obrigado.

     

    sábado, 3 de janeiro de 2009 13:45
  •  GustavoCastro wrote:

    Outra coisa, comofazer agora para que o Databinding continue funcionando se o Textbox for alterado para invisible?

    (neste caso, tudo pára de funcionar e tenho uns contrle hidden no form (win32).

     

    Olá Gustavo,

     

    Creio que isso não seja possível por ser uma característica de implementação do controle TextBox... Ele simplesmente não dispara o evento PropertyChanged quando está invisível.

     

    Na verdade, uma vez que o controle está invisível, o correto mesmo seria você atualizar o objeto que está ligado ao TextBox, e não o próprio controle:

     

    Code Snippet

     

     ateste.nome = "Maria";

     

     

    ---

     

    De qualquer forma, você sempre pode optar pela "gambiarra" utilizada nos tempos de VB6 para esconder controles:

     

    Mude o TabStop para false, para que o controle não receba foco via tecla Tab, e ao invés de alterar o Visible para false, você deixa ele visível, mas altera a posição horizontal ou vertical do controle para um valor negativo, de forma que ele não possa ser visto no formulário:

     

    Code Snippet

     

     this.textBox1.TabStop = false;

     this.textBox1.Left = -1000;

     

     

    Sinceramente, não recomendo essa alternativa... Mas ela existe, e tem gente que usa.

     

    Abraços,
    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 14:04
    Moderador
  • Caio,

    esta possibilidade não dá, pois estou usando algumas classes herdadas e não sei o nome do atributo na classe, pois as classes de update estão num nível mais baixo (genéricas).

     

    A não ser que eu consiga de alguma forma (Reflection ?) - usando o DataBinding.BindingMemberInfo.BindingField ...

    Neste caso como fazer?

     

    DataBinding.BindingMemberInfo.BindingField = "nome"; (--> este atributo está vindo corretamente, pois o Databings.Add seta esta informação).

     

    Agora preciso fazer um update em ateste.nome, mas só tenho a string "nome" --> como alterar o atributo nome da classe se tenho somente a string "nome"...(não posso escrever ateste.nome, pois estou numa classe genérica - precisaria de um parse no nome do campo ou implementar um setcampo na classe base - outra forma mais elegante?)

     

    ex.: (seria extremamente trabalhoso e improdutivo a abordagem a seguir ...)

    teste.setcampo (string anome, string avalor){

    switch (anome)

    {

    case "nome": nome = avalor;

    }

     

    Obrigado mais uma vez.

    sábado, 3 de janeiro de 2009 14:21
  • Olá Gustavo,

     

    É possível via Reflection, mas antes de irmos por aí (última escolha), eu queria entender uma coisa:

     

    Se você não sabe o nome da propriedade associada em cada controle, então como você cria os DataBindings?

     

    Abraços,
    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 14:29
    Moderador
  • hehe, na verdade tenho o seguinte:

    public abstract class ClasseBaseCadastro

    {

     // aqui defino as rotinas genéricas, para serem reaproveitadas nas classes específicas de cadastro ...

    }

     

    public class ClasseEspecificaCadastro : ClasseBaseCadastro

    {

    //... aqui defino os campos a serem cadastradose demais rotinas específicas

    //esta classe deve requere o mínimo possível de codificação

    }

     

    na verdade tenho ainda:

    FormBaseCadastro : Form

    {

     //outras rotinas genéricas de Interface

    }

     

    FormEspecificoCadastro : FormBaseCadastro

    {

       //DataBindings específicos

      //esta classe(form) deve requerer o mínimo possível de codificação

    }

     

    por isto, defino os campos nas classes específicas, mas toda a lógica de bindings e updates é genérica (ou nas classes de form ou nas classes de cadastro). Preciso evitar ao máximo overrides nas classes específicas para agilizar o desenvolvimento de novas classes para cadastro.

    Esta estrutura que estou criando está ficando muito boa (rápida para desenvolver e rápida no acesso a dados). Estou trabalhando nela há quase um ano, (na verdade tem muitos outros detalhes que não dá pra passar aqui ....)

    Também pensei em criar um Indexer para a classe, mas teria que escrever o acesso campo a campo na classe específica ... seria muito trabalhoso e antiprodutivo).

     

    Obrigado.

    sábado, 3 de janeiro de 2009 14:41
  • Olá Gustavo,

     

    Se eu entendi bem a sua estrutura, você está em uma classe derivada, e tanto o controle TextBox quanto o objeto que está ligado via DataBinding estão no formulário base, e você, a partir do formulário derivado, está alterando o controle TextBox (que por acaso está invisível).

     

    É isso?

     

    Nesse caso, uma vez que o controle não pertence à sua classe (é uma variável membro da classe base), o correto seria você não ter a possibilidade de alterar o controle do formulário base diretamente.

     

    O formulário base deveria implementar uma propriedade (Ex: Nome) e você, através do seu formulário derivado, utilizaria essa propriedade para alterar os valores do controle.

     

    O formulário base, como conhece os seus próprios controles e objetos, se encarregaria de alterar a propriedade correta do objeto, fazendo com que tudo funcionasse, independente de quem está visível ou invisível.

     

    Acho que esse seria a alternativa correta...

    ---

     

    De qualquer forma, respondendo sua pergunta, via Reflection você pode fazer o seguinte:

     

    Code Snippet

     

     // Obtém uma referência para a propriedade Nome

     PropertyInfo p = ateste.GetType().GetProperty("nome", BindingFlags.Instance | BindingFlags.Public);

     

     // Altera o valor da propriedade, no objeto que você quer

     p.SetValue(ateste, "Maria", null);

     

     

    Abraços,

    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 15:09
    Moderador
  • Fechado, acabei optando pelo Reflection. eu havia feito um pouco diferente, mas considero tua implementação mais simples e eficaz (segue minha implementação do reflection ...):

    Na classe base criei este método para ser chamado para atualziar o conteúdo de qualquer controle. Ele se encarrega das checagens para controles invisíveis ...

    ficou mais ou menos assim.

     

    private void AtualizaControle(Control aControl, object avalue)

    {

     aControl.Text = avalue.ToString(); 

     if ( (!aControl.Visible) && (aControl.DataBindings.Count > 0))

     {

      Assembly a = Assembly.GetExecutingAssembly();

      Type aclass = ClasseCadastro.GetType();

      PropertyInfo aproperty = aclass.GetProperty();

      aproperty.SetValue(ClasseCadastro, Int32.Parse(avalue.ToString()), null);

    //falta checagem de tipos, mas para mim, é sempre int ... serão sempre campos chaves que ficarão escondidos

      }

    }

     

    RESOLVIDO. até mais.

     

    Obrigado.

    sábado, 3 de janeiro de 2009 15:38
  • Olá Gustavo,

     

    Fiquei contente que você tenha resolvido o problema, mas confesso que ainda tinha ficado satisfeito em ter que criar um método separado para atualizar o valor dos controles e ter que usar esse monte de Reflection...

     

    Então fui dar uma olhada no código-fonte da classe TextBox, TextBoxBase e Control (a hierarquia), e finalmente descobri que, na verdade, o DataBinding funciona mesmo quando o controle está invisível, desde que ele tenha um handle criado.

     

    Em outras palavras, se você definir que o controle está com Visible=false logo nas propriedades do controle (gerando o código na InitializeComponent), então a caixa de texto nunca chega a ser criada, e logo, não tem seu próprio handle... Sem handle, não há DataBinding.

     

    No entanto, se você voltar a caixa de texto para Visible=true nas propriedades, e deixar para esconder o controle mais tarde, por exemplo, no evento Load do seu formulário, o controle vai ficar invisível e, ao mesmo tempo, o DataBinding estará funcionando sem problemas...

     

    Code Snippet

     

     private void Form1_Load(object sender, EventArgs e)

     {

    this.textBox1.Visible = false;

     

    // ...

     }

     

     

    No evento Load do formulário, o controle já foi criado e já tem seu próprio handle, mas o usuário ainda não viu nada, então você pode escondê-lo, e continuar a trabalhar com o DataBinding Wink

     

    Abraços,
    Caio Proiete




    Caio Proiete
    http://www.caioproiete.com
    sábado, 3 de janeiro de 2009 19:42
    Moderador