Debug em DataBinding do WPF

Como eu escrevi aqui, o WPF fornece várias funcionalidades para databinding. Quando efetuamos a configuração de forma declarativa, a verificação para se certificar de que a propriedade que serve como origem das informações realmente existe, somente acontecerá durante a execução, mas o WPF não irá disparar qualquer exceção se ela não for encontrada. O binding simplesmente não funciona.

Para exemplificar, o código abaixo define a propriedade Content do controle Button com uma propriedade que não existe no TextBox. Esse código compilará sem problemas, mas durante a execução, o texto do botão sempre ficará vazio.

<TextBox Name=”textBox1″ />
<Button Name=”button1″ Content=”{Binding ElementName=textBox1, Path=PropriedadeQueNaoExiste}” />

Assim como já acontece com o WCF, o Microsoft disponibilizou uma série de elementos de tracing que nos permitirá escolher aqueles que nos interessam para começar a monitorar eventuais informações que eles geram. Entre as várias opções, uma delas é a chamada System.Windows.Data, que é utilizada para catalogar mensagens relacionadas ao processo de databinding, incluindo casos como este, onde não é possível resolução do binding.

Para habilitá-lo, basta configurar o TraceSource como é mostrado abaixo, definindo qual nível de severidade das informações está interessado (TraceSwitch) e, finalmente, o local onde deseja salvar essas informações (TraceListener). O exemplo abaixo ilustra a configuração feita através do arquivo App.config da aplicação:

<?xml version=”1.0″ encoding=”utf-8″ ?>
<configuration>
  <system.diagnostics>
    <sources>
      <source name=”System.Windows.Data” switchName=”SourceSwitch”>
        <listeners>
          <add name=”textListener” />
        </listeners>
      </source>
    </sources>
    <switches>
      <add name=”SourceSwitch” value=”All”/>
    </switches>
    <sharedListeners>
      <add name=”console”
           type=”System.Diagnostics.ConsoleTraceListener”
           initializeData=”false”/>
    </sharedListeners>
  </system.diagnostics>
</configuration>

O ConsoleTraceListener faz com que as informações sejam enviadas para a janela de Output do Visual Studio. Ao rodar o código XAML acima, vamos visualizar a seguinte mensagem:

System.Windows.Data Error: 39 : BindingExpression path error: ‘PropriedadeQueNaoExiste’ property not found on ‘object’ ”TextBox’ (Name=’textBox1′)’. BindingExpression:Path=PropriedadeQueNaoExiste; DataItem=’TextBox’ (Name=’textBox1′); target element is ‘Button’ (Name=’button1′); target property is ‘Content’ (type ‘Object’)

Anúncios

Utilizando Resources no WPF

Qualquer tipo de aplicação geralmente precisa de arquivos adicionais, que servem como recursos extras para a mesma. Esses arquivos muitas vezes são do tipo Xml, simples textos, imagens, ícones, etc. Esses arquivos são colocados dentro do mesmo diretório da aplicação, e muitas vezes organizados através de sub-diretórios. Geralmente esse tipo de técnica define esses arquivos como arquivos de conteúdo, e são distribuídos juntamente com o assembly, mas estão fisicamente separados.

Desde as primeiras versões do .NET, para as aplicações construídas em cima da plataforma, podemos embutir um arquivo qualquer em um determinado assembly, fazendo com que este assembly contenha tudo o que ele precise. Um exemplo disso é o assembly System.Web.dll. Dentro dele há toda a infraestrutura do ASP.NET, incluindo os controles. Quando estamos desenvolvendo uma aplicação deste tipo, a ToolBox do Visual Studio exibe os controles disponíveis (novamente, aqueles que estão dentro do System.Web.dll), e ao lado uma imagem que representa o controle. Mas de onde vem essa imagem? Elas estão embutidas neste mesmo assembly, como você pode visualizar na imagem abaixo:

O WPF também possibilita embutir arquivos extras à nossa aplicação, compilando – ou não – juntamente com o assembly (exe). Imagine que você adiciona a referência para uma imagem qualquer no Solution Explorer. Se for até as propriedades da mesma, verá que existe uma propriedade chamada Build Action, que determina justamente o comportamento desta imagem durante a compilação. Entre as várias opções voltadas para o WPF, vamos analisar duas delas: a Resource e Content.

A primeira opção faz com que o arquivo em questão seja embutido no assembly, enquanto a segunda opção faz com que o arquivo seja mantido como um arquivo de conteúdo da aplicação, mas não o compila para dentro do assembly. Independentemente da forma que utiliza para o arquivo, sempre utilizaremos uma URI para acessá-lo, dependendo apenas do local que ela se encontra (embutida ou não). Por exemplo, se temos uma imagem chamada Logo.png e ela está marcada como Resource, você pode simplesmente fazer:

<Image Source=”Logo.png” />

Como disse acima, é comum utilizar sub-diretórios para organizar os arquivos que fazem parte da aplicação. Quando cria uma pasta para armazenar esses arquivos, você deverá também mencionar o caminho ao referenciá-lo. Isso é necessário mesmo quando embutimos o arquivo no assembly, pois o WPF nomeia o recurso utilizando a estrutura de pastas. Abaixo temos o resultado da compilação dos recursos, onde acima temos um sub-diretório chamado Imagens e a imagem está dentro dele, enquanto abaixo temos a imagem colocada na raiz da aplicação.

A utilização das imagens que estão em sub-diretórios, pode ser feita da seguinte forma:

<Image Source=”ImagensLogo.png” />

É importante dizer que a forma de acesso aos recursos que utilizamos acima, é apenas uma espécie de atalho, pois isso é transformado em uma URI muito mais complexa, para que assim possa acessar o respectivo recurso. A URI completa para acessar o recurso deve ser: pack://packageUri/partPath. Transformando os exemplos anteriores nesta sintaxe, teríamos o seguinte:

<Image Source=”pack://application:,,,/Logo.png” />
<Image Source=”pack://application:,,,/Imagens/Logo.png” />

Caso você desejar acessar recursos que estão embutidos em outros assemblies, você deverá referenciá-lo com esta sintaxe, definindo explicitamente o nome do assembly que deseja extrair a informação. O exemplo ilustra como proceder para acessar a mesma imagem, mas que estará em um segundo assembly:

pack://application:,,,/BoletosBancarios;component/Imagens/Logo.png

Quando você não deseja embutir o arquivo no assembly, então o arquivo vinculado à aplicação deverá ser marcado como Content. Para acessar esse tipo de recurso, dependerá também de onde ele estará armazenado. Por exemplo, se ele estiver armazenado em algum diretório do disco, podemos referenciar diretamente:

<Image Source=”C:TempLogo.png” />

Quando Content é definido para o arquivo, você deve definir a propriedade Copy To Output Directory para Copy Always, para que o arquivo seja copiado para o mesmo diretório onde a aplicação está sendo gerada, para assim facilitar as referências relativas à ele.

Você ainda pode referenciar também outros tipos de arquivos que estão externos a sua aplicação, como por exemplo, aqueles que estão em algum ponto da internet, como por exemplo:

<Image Source=”http://www.site.com.br/Imagens/Logo.png&#8221; />

O tipo de distribuição da aplicação influencia no caminho de acesso aos recursos, e ao invés de você deixar em hard-code, o WPF facilita isso com o uso de uma opção chamada de siteOfOrigin. Essa opção retorna valores diferentes, de acordo com a forma com que a aplicação foi originalmente instalada. Por exemplo, se a aplicação foi instalada através do Click Once, essa opção retornará a URL de onde a aplicação foi distribuída; se utilizar Windows Installer (MSI), essa opção refletirá o diretório raiz da aplicação.

Essa opção facilita bastante, já que independentemente da forma que a aplicação é entregue, você sempre conseguirá chegar até o recurso que está sendo solicitado. A sua utilização é simples, basta alterar o packageUri de application para siteOfOrigin, como mostrado no exemplo abaixo:

<Image Source=”pack://siteOfOrigin:,,,/Logo.png” />
<Image Source=”pack://siteOfOrigin:,,,/Imagens/Logo.png” />

E, finalmente, esse tipo de sintaxe também é a mesma para acesso via código:

this.image1.Source = new BitmapImage(new Uri(“pack://application:,,,/Imagens/Logo.png”));
//Ou
this.image1.Source = new BitmapImage(new Uri(“Logo.png”));

Conclusão: Os recursos que são adicionados à aplicação não estão resumidos ao que vimos aqui. Há também a possibilidade de embutir arquivos como MP3, AVI, etc., e tudo isso dependerá do quanto isso é viável. Além disso, os recursos também são largamente utilizados quando estamos construindo uma aplicação localizada, aquela que dá suporte à múltiplos idiomas, mas isso é matéria para um próximo artigo.