Usuário com melhor resposta
Databinding (C#/Win32)

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 ....
(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.
Respostas
-
Olá Gustavo,
Você precisa definir que o DataBinding também será atualizado durante o evento PropertyChanged do TextBox:
Code SnippettextBox1.DataBindings.Add("Text", ateste, "nome", true, DataSourceUpdateMode.OnPropertyChanged);
Abraços,
Caio Proiete
Caio Proiete
http://www.caioproiete.com -
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
Todas as Respostas
-
Olá Gustavo,
Você precisa definir que o DataBinding também será atualizado durante o evento PropertyChanged do TextBox:
Code SnippettextBox1.DataBindings.Add("Text", ateste, "nome", true, DataSourceUpdateMode.OnPropertyChanged);
Abraços,
Caio Proiete
Caio Proiete
http://www.caioproiete.com -
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.
-
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 Snippetateste.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 Snippetthis.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 -
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.
-
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 -
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.
-
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 -
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.
-
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 Snippetprivate 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
Abraços,
Caio Proiete
Caio Proiete
http://www.caioproiete.com