Em mais um artigo da série Reflection na Prática: Uso na Classe de Conexão, desta vez abordo os métodos BindToUI e BindFromUI, mostrando como fazer a atribuição das propriedades de uma classe para os componentes da interface de usuário e vice-versa.

Trabalharemos mais neste método os componentes que recebem um único valor, tais como textboxes, checkboxes, dropdownlists, por aí.

Mas espera ae… o DropDownList recebe vários valores! Sim, mas não estou falando da lista em si, e sim do valor atualmente selecionado :P (e isto vale para os outros __list também!)

Vamos agora atribuir as propriedades da classe para a interface de usuário, ou seja, o método BindToUI da classe Conexão:

 public void BindToUI(Page UI, Type type, ArrayList ExcludeFromBind)
 {
     Type t = this.GetType();
     foreach (FieldInfo c in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
     {
         if (ExcludeFromBind.Contains(c.Name))
         {
             continue;
         }
         if (c == null)
         {
             continue;
         }
         if (c.Name == null)
         {
             continue;
         }
  
         //Retira o prefixo do nome do componente -> ele DEVE ter 3 letras, e o ID do controle deve ter mais que 3 letras
         string PropertyPattern = (c.Name.Length < 3) ? "" : c.Name.Substring(3, c.Name.Length - 3);
         PropertyPattern = PropertyPattern.Replace(t.Name, "");
         if (PropertyPattern.Contains("_"))
         {
             PropertyPattern = PropertyPattern.Substring(0, PropertyPattern.IndexOf("_"));
         }
  
         PropertyInfo pi = t.GetProperty(PropertyPattern);
         if (pi != null)
         {
             if (pi.GetValue(this, null) == null)
             {
                 continue;
             }
  
             int IndexProp = -1;
             HasIndexIdentifier(c.Name, out IndexProp);
  
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
             {
                 int idx = 0;
                 string formatinfo = "";
                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, pi.GetValue(this, null));
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, arrVal[IndexProp]);
                     }
                 }
                 else
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as TextBox).Text = pi.GetValue(this, null).ToString();
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as TextBox).Text = arrVal[IndexProp].ToString();
                     }
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.DropDownList"))
             {
                 if (!pi.PropertyType.IsArray)
                 {
                     (c.GetValue(UI) as DropDownList).SelectedValue = pi.GetValue(this, null).ToString(); ;
                 }
                 else
                 {
                     object[] arrVal = (object[])pi.GetValue(this, null);
                     (c.GetValue(UI) as DropDownList).SelectedValue = arrVal[IndexProp].ToString();
                 }
             }
  
  
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButton"))
             {
                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as RadioButton).Checked = ((int)pi.GetValue(this, null) > 0) ? true : false;
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as RadioButton).Checked = ((int)arrVal[IndexProp] > 0) ? true : false;
                     }
                 }
                 if (pi.PropertyType.Name.Equals("System.Boolean"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as RadioButton).Checked = (bool)pi.GetValue(this, null);
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as RadioButton).Checked = (bool)arrVal[IndexProp];
                     }
                 }
                 if (pi.PropertyType.Name.Equals("System.String"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as RadioButton).Checked = (pi.GetValue(this, null).ToString().ToUpper().Equals("SIM") || pi.GetValue(this, null).ToString().ToUpper().Equals("S"));
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as RadioButton).Checked = ((arrVal[IndexProp].ToString().ToUpper().Equals("SIM") || arrVal[IndexProp].ToString().ToUpper().Equals("S")));
                     }
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.Label"))
             {
                 string formatinfo = "";
                 int idx = 0;
                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as Label).Text = String.Format(formatinfo, pi.GetValue(this, null));
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as Label).Text = String.Format(formatinfo, arrVal[IndexProp]);
                     }
                 }
                 else
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as Label).Text = pi.GetValue(this, null).ToString();
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as Label).Text = arrVal[IndexProp].ToString();
                     }
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBox"))
             {
                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as CheckBox).Checked = ((int)pi.GetValue(this, null) > 0) ? true : false;
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as CheckBox).Checked = ((int)arrVal[IndexProp] > 0) ? true : false;
                     }
                 }
                 if (pi.PropertyType.Name.Equals("Boolean"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as CheckBox).Checked = (bool)pi.GetValue(this, null);
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as CheckBox).Checked = (bool)arrVal[IndexProp];
                     }
                 }
                 if (pi.PropertyType.Name.Equals("System.String"))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as CheckBox).Checked = (pi.GetValue(this, null).ToString().ToUpper().Equals("SIM") || pi.GetValue(this, null).ToString().ToUpper().Equals("S"));
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as CheckBox).Checked = ((arrVal[IndexProp].ToString().ToUpper().Equals("SIM") || arrVal[IndexProp].ToString().ToUpper().Equals("S")));
                     }
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBoxList"))
             {
                 if (!pi.PropertyType.IsArray)
                 {
                     (c.GetValue(UI) as CheckBoxList).SelectedValue = pi.GetValue(this, null).ToString();
                 }
                 else
                 {
                     object[] arrVal = (object[])pi.GetValue(this, null);
                     (c.GetValue(UI) as CheckBoxList).SelectedValue = arrVal[IndexProp].ToString();
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButtonList"))
             {
                 if (!pi.PropertyType.IsArray)
                 {
                     (c.GetValue(UI) as RadioButtonList).SelectedValue = pi.GetValue(this, null).ToString();
                 }
                 else
                 {
                     object[] arrVal = (object[])pi.GetValue(this, null);
                     (c.GetValue(UI) as RadioButtonList).SelectedValue = arrVal[IndexProp].ToString();
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.GridView"))
             {
                 if (!pi.PropertyType.IsArray)
                 {
                     (c.GetValue(UI) as GridView).DataSource = pi.GetValue(this, null);
                     (c.GetValue(UI) as GridView).DataBind();
                 }
                 else
                 {
                     object[] arrVal = (object[])pi.GetValue(this, null);
                     (c.GetValue(UI) as GridView).DataSource = arrVal[IndexProp];
                     (c.GetValue(UI) as GridView).DataBind();
                 }
             }
  
  
             if (c.FieldType.FullName.Equals("System.Web.UI.HtmlControls.HtmlInputHidden"))
             {
                 string formatinfo = "";
                 int idx = 0;
                 if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as HtmlInputHidden).Value = String.Format(formatinfo, pi.GetValue(this, null));
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as HtmlInputHidden).Value = String.Format(formatinfo, arrVal[IndexProp]);
                     }
                 }
                 else
                 {
                     if (!pi.PropertyType.IsArray)
                     {
                         (c.GetValue(UI) as HtmlInputHidden).Value = pi.GetValue(this, null).ToString();
                     }
                     else
                     {
                         object[] arrVal = (object[])pi.GetValue(this, null);
                         (c.GetValue(UI) as HtmlInputHidden).Value = arrVal[IndexProp].ToString();
                     }
                 }
             }
         }
     }
 }

Sim, ele é um tanto longo, mas cada if trabalha da mesma maneira, por isso, quando chegar na parte de explicar a atribuição em si irei falar apenas sobre o primeiro componente, ou seja, de como atribuir o objeto em um TextBox; os outros serão análogos a este.

Como lembrete, soma-se ao lembrete do post anterior as convenções para nomearmos os componentes da interface de usuário: Prefixo de três (3) letras + Nome da Classe + Nome da Propriedade, todos estes sensíveis ao caso.

Por exemplo, temos uma classe chamada TFuncionario e uma propriedade chamada Nome será atribuída a um textbox. Seu nome deve ficar assim: tbxTFuncionarioNome.

O método pede como parâmetros o objeto Page que terá seus componentes atribuídos, as informações de seu tipo (método GetType() do objeto Page), e um ArrayList com os nomes de cada objeto que não será atribuído caso haja correspondência dele na classe.

Inicialmente, pego as informações de tipo do próprio objeto que vou atribuir e guardo na variável “t”.

Em seguida, faço uma iteração através de um laço foreach em todas as variáveis privadas ou protegidas da página que terá os valores dos componentes modificados. O método GetFields() da classe Type retorna uma coleção de objetos FieldInfo, que por sua vez correspondem às propriedades da classe referenciada pela variável “type” (segundo parâmetro do método BindToUI()). Este médodo pede como parâmetro os BindingFlags, sendo que colocamos o BindingFlags.Instance, já que queremos as variáveis de instância e BindingFlags.NonPublic, já que todos os componentes de uma página Web são declarados como protected.

Com cada item a ser iterado guardado na variável “c” declarada no foreach, verificamos se o mesmo está dentro do ArrayList ExcludeFromBind através de seu nome. Se estiver, passamos para a próxima iteração. Passamos para a próxima iteração caso o objeto seja nulo ou a propriedade Name for nula também.

Em seguida, isolamos o nome da propriedade da classe do nome do componente. Retiramos o prefixo, o nome da classe, e se ele for sucedido de underline (_) mais um número, isolamos isso também. Guardamos o resultado na variável “PropertyPattern”.

Em seguida, instanciamos um objeto do tipo PropertyInfo, que é análogo ao FieldInfo, só que neste caso iremos trabalhar sobre Propriedades e não sobre campos, ou seja, as variáveis de uma classe que possuem métodos get() e/ou set(). Para isso, inicializamos a variável “pi” utilizando o método GetProperty() da classe Type (a variável “t”) passando como parâmetro o nome da propriedade que iremos atribuir em seu correspondente na UI.

Se a propriedade for nula e seu valor, que pegamos através do método GetValue() de PropertyInfo, que pede como parâmetros o objeto a ser verificado (ponteiro this) e o índice (caso a propriedade seja indexada), também for nulo, passamos para a próxima iteração do foreach.

Criamos uma variável inteira chamada IndexProp, que denota se a nossa propriedade em questão é indexada: Se seu valor for –1, significa que não é indexada, caso contrário, denota o próprio índice.

Este índice é buscado através do método privado de Conexão HasIndexIndentifier, que recebe como parâmetros o nome do componente e devolve como saída o índice.

Agora a brincadeira da atribuição começa. Vou destacar aqui como atribuímos para um TextBox, que é o componente mais recorrente em uma interface de usuário:

 if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
 {
     int idx = 0;
     string formatinfo = "";
     if (ContainFormatInfo(pi.Name, out idx, out formatinfo))
     {
         if (!pi.PropertyType.IsArray)
         {
             (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, pi.GetValue(this, null));
         }
         else
         {
             object[] arrVal = (object[])pi.GetValue(this, null);
             (c.GetValue(UI) as TextBox).Text = String.Format(formatinfo, arrVal[IndexProp]);
         }
     }
     else
     {
         if (!pi.PropertyType.IsArray)
         {
             (c.GetValue(UI) as TextBox).Text = pi.GetValue(this, null).ToString();
         }
         else
         {
             object[] arrVal = (object[])pi.GetValue(this, null);
             (c.GetValue(UI) as TextBox).Text = arrVal[IndexProp].ToString();
         }
     }
 }

Se o tipo do componente da iteração do foreach for do tipo System.Web.UI.WebControls.TextBox (um TextBox), verificamos primeiro se ele possui informações para a formatação de seu conteúdo, através do método ContainFormatInfo() da classe Conexao. Ele verifica a coleção _FormatProperties, e pede como parâmetros o nome da propriedade; e devolve como parâmetros de saída o índice do item a ser formatado e a string de formatação.

Se a propriedade em questão não é do tipo array (indexada), é feito um cast do componente da iteração atual do foreach para TextBox, que estará no método GetValue() nossa variável “c”) e atribuímos na propriedade Text o valor da propriedade correspondente no objeto, utilizando o método GetValue do objeto “pi”.

Caso a propriedade seja indexada, primeiro pegamos os valores para um array de object, para em seguida atribuir deste array somente o valor do índice que armazenamos anteriormente em IndexProp.

E se fomos formatar a propriedade para exibí-la, no passo anterior fazemos a atribuição através de um comando String.Format.

Para os outros componentes, o método é análogo.

O método BindFromUI() faz a operação inversa, tendo a mesma lógica do BindToUI(), porém ele faz uma troca de tipos, como veremos na transcrição do código a seguir:

 public void BindFromUI(Page UI, Type type, ArrayList ExcludeFromBind)
 {
     Type t = this.GetType();
     foreach (FieldInfo c in type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic))
     {
         if (ExcludeFromBind.Contains(c.Name))
         {
             continue;
         }
         if (c == null)
         {
             continue;
         }
         if (c.Name == null)
         {
             continue;
         }
  
         //Retira o prefixo do nome do componente -> ele DEVE ter 3 letras, e o ID do controle deve ter mais que 3 letras
         string PropertyPattern = (c.Name.Length < 3) ? "" : c.Name.Substring(3, c.Name.Length - 3);
         PropertyPattern = PropertyPattern.Replace(t.Name, "");
         if (PropertyPattern.Contains("_"))
         {
             PropertyPattern = PropertyPattern.Substring(0, PropertyPattern.IndexOf("_"));
         }
  
  
         PropertyInfo pi = t.GetProperty(PropertyPattern);
         if (pi != null)
         {
             if (pi.GetSetMethod() == null)
             {
                 continue;
             }
             int IndexProp = -1;
             HasIndexIdentifier(c.Name, out IndexProp);
  
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.TextBox"))
             {
                 if ((c.GetValue(UI) as TextBox).Text.Trim().Equals(""))
                 {
                     pi.SetValue(this, null, null);
                 }
                 else
                 {
                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as TextBox).Text, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
                 }
             }
  
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.DropDownList"))
             {
                 if ((c.GetValue(UI) as DropDownList).SelectedValue.Trim().Equals(""))
                 {
                     pi.SetValue(this, null, null);
                 }
                 else
                 {
                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as DropDownList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButton"))
             {
                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
                 {
                     pi.SetValue(this, ((c.GetValue(UI) as RadioButton).Checked ? 1 : 0), null);
                 }
                 if (pi.PropertyType.Name.Equals("Boolean"))
                 {
                     pi.SetValue(this, (c.GetValue(UI) as RadioButton).Checked, null);
                 }
                 if (pi.PropertyType.Name.Equals("System.String"))
                 {
                     pi.SetValue(this, ((c.GetValue(UI) as RadioButton).Checked ? "S" : "N"), null);
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.Label"))
             {
                 pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as Label).Text, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
             }
  
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBox"))
             {
                 if (pi.PropertyType.Name.Equals("System.Int16") || pi.PropertyType.Name.Equals("System.Int32") || pi.PropertyType.Name.Equals("System.Int64"))
                 {
                     pi.SetValue(this, ((c.GetValue(UI) as CheckBox).Checked ? 1 : 0), null);
                 }
                 if (pi.PropertyType.Name.Equals("Boolean"))
                 {
                     pi.SetValue(this, (c.GetValue(UI) as CheckBox).Checked, null);
                 }
                 if (pi.PropertyType.Name.Equals("System.String"))
                 {
                     pi.SetValue(this, ((c.GetValue(UI) as CheckBox).Checked ? "S" : "N"), null);
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.CheckBoxList"))
             {
                 if ((c.GetValue(UI) as CheckBoxList).SelectedValue.Trim().Equals(""))
                 {
                     pi.SetValue(this, null, null);
                 }
                 else
                 {
                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as CheckBoxList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.WebControls.RadioButtonList"))
             {
                 if ((c.GetValue(UI) as RadioButtonList).SelectedValue.Trim().Equals(""))
                 {
                     pi.SetValue(this, null, null);
                 }
                 else
                 {
                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as RadioButtonList).SelectedValue, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
                 }
             }
             if (c.FieldType.FullName.Equals("System.Web.UI.HtmlControls.HtmlInputHidden"))
             {
                 if ((c.GetValue(UI) as HtmlInputHidden).Value.Trim().Equals(""))
                 {
                     pi.SetValue(this, null, null);
                 }
                 else
                 {
                     pi.SetValue(this, Convert.ChangeType((c.GetValue(UI) as HtmlInputHidden).Value, pi.PropertyType.Name.Equals("Nullable`1") ? System.Nullable.GetUnderlyingType(pi.PropertyType) : pi.PropertyType), null);
                 }
             }
         }
     }
 }

Se fomos atribuir a propriedade Text de um TextBox em uma propriedade inteira, teremos um erro na execução do programa. Para isso, no momento da atribuição utilizo o método Convert.ChangeType, que pede como parâmetros o valor e o tipo de destino, que no nosso caso é o tipo da propriedade a ser atribuída.

Para pegar o tipo, primeiro verificamos se a propriedade é do tipo nulável, pois caso afirmativo deveremos pegar o tipo encapsulado ao invés do tipo real. Utilizando o método System.Nullable.GetUnderlyingType() conseguimos fazer isso.

A lógica deste método é análoga ao BindToUI(), o que dispensa maiores comentários a respeito deste código.

Foi trabalhoso no início, mas depois poupou um trabalho…

Um abraço!