WPF - Vinculando imagens de um banco de dados em um ListBox
O controle ListBox da WPF é diferente do controle ListBox Windows Forms e possui muitas habilidades que podem ser estendidas. Usando apenas o controle ListBox podemos desenhar a maioria dos controles disponíveis na seção de controles Data da ASP .NET.
Neste artigo eu vou realizar a vinculação de dados entre o banco de dados Northwind.mdf e o controle ListBox da WPF mostrando como vincular imagens armazenadas no banco de dados no ListBox.
Vou usar LINQ to SQL para obter os dados e realizar a vinculação no ListBox, sendo que, através do mapeamento do tipo de dados Image do SQL Server para o tipo System.Data.Linq.Binary e posteriormente, quando da vinculação para o tipo Image, vamos converter de System.Data.Linq.Binary para o formato BitmapSource.
Desde que precisamos converter o System.Data.Linq.Binary para BitmapSource, temos definir um conversor enquanto estamos atribuindo a origem da imagem na tag. Isso pode ser feito usando um StaticResource. Sem a criação de um recurso estático a marcação não sabe como criar uma instância da classe de conversor.
Geralmente
precisamos formatar ou converter os dados exibidos quando
usamos o databinding pois na vinculação de dados
comum a informação vem da fonte para a origem sem
qualquer mudança. Se você estiver usando a vinculação
two-way vai ter que fazer um conversor de forma a
converter os dados informados pelo usuário em um formato
apropriado ao objeto de origem. A WPF permite que você realize estas duas tarefas através da criação de uma classe conversora de forma que ela formate a exibição no destino e , em caso de two-way binding, converta o novo valor informado no destino antes do mesmo ser aplicado a fonte. Os conversores de valores (Value Converter) podem então ser considerados como uma peça muito importante na vinculação de dados no WPF podendo ser usados de diversas formas:
Para criar um conversor de valores, você precisa seguir 4 etapas:
|
Então, precisamos criar um recurso estático e mapear o arquivo de classe respectivo na seção de recursos. Na seção de recursos no âmbito de Window.Resources, podemos criar o recurso estático com uma referência ao objeto de classe. Esta classe de objeto pode ser especificada na tag window como um atributo xmlns. Podemos especificar o nosso próprio namespace. Neste caso, chamei-o como local e voltado para a classe ImageConverter.
O nosso conversor de imagem deve implementar a interface IValueConverter. A interface IValueConverter tem que definir dois métodos:
Criando o projeto WPF
Abra o Visual Basic 2010 Express Edition e crie um novo projeto do tipo WPF Application com o nome ListBox_Imagem;
No menu Project clique em Add New Item e a seguir selecione o template LINQ to SQL Classes, informe o nome Northwind.dbml e clique no botão Add;
A seguir abra a janela DataBase Explorer e selecionando o banco de dados Northwind.mdf arraste e solte as tabelas Categories e Products para o descritor LINQ to SQL conforme a figura abaixo:
Obs: Se a conexão com o banco de dados ainda não existir você deverá criá-la ou adicioná-la;
Com isso temos a nossa fonte de dados definida através do LINQ to SQL.
Definindo a interface WPF
Selecione o arquivo MainWindow.xaml e defina o seguinte leiaute usando o código XAML:
<Window x:Class="MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:ListBox_Imagem" Title="Exibindo imagens do banco de dados" Height="500" Width="550"> <Window.Resources> <local:ImageConverter x:Key="ImageConverter"/> <DataTemplate x:Key="ProductTemplate" > <TextBlock Text="{Binding ProductName}" FontFamily="Calibri" FontSize="14" /> </DataTemplate> <DataTemplate x:Key="CategoryTemplate"> <StackPanel Orientation="Horizontal" VerticalAlignment="Top" > <Border BorderThickness="1" BorderBrush="silver" CornerRadius="10" Padding="5" Margin="15px" Background="#E6E6E6" > <StackPanel> <Image Source="{Binding Picture, Converter={StaticResource ImageConverter}}" /> <ItemsControl ItemsSource="{Binding Products}" ItemTemplate="{StaticResource ProductTemplate}" > </ItemsControl> </StackPanel> </Border> </StackPanel> </DataTemplate> </Window.Resources> <Grid> <ListBox Margin="10,10,10,0" Name="lstCategories" ItemTemplate="{StaticResource CategoryTemplate}" VerticalAlignment="Top" Height="439"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> </Window> |
No código acima temos:
1- A declaração do namespace local: xmlns:local="clr-namespace:ListBox_Imagem"
2- A definição do recurso estático - Window.Resources - que usa o conversor de Imagens - ImageConverter - e o recurso DataTemplate para exibir a imagem da categoria e os nomes dos produtos relacionados:
<Window.Resources> <local:ImageConverter x:Key="ImageConverter"/> <DataTemplate x:Key="ProductTemplate" > <TextBlock Text="{Binding ProductName}" FontFamily="Calibri" FontSize="14" /> </DataTemplate> <DataTemplate x:Key="CategoryTemplate"> <StackPanel Orientation="Horizontal" VerticalAlignment="Top" > <Border BorderThickness="1" BorderBrush="silver" CornerRadius="10" Padding="5" Margin="15px" Background="#E6E6E6" > <StackPanel> <Image Source="{Binding Picture, Converter={StaticResource ImageConverter}}" /> <ItemsControl ItemsSource="{Binding Products}" ItemTemplate="{StaticResource ProductTemplate}" > </ItemsControl> </StackPanel> </Border> </StackPanel> </DataTemplate> </Window.Resources> |
3- O controle ListBox usando o recurso estático para exibir a imagem:
<Grid> <ListBox Margin="10,10,10,0" Name="lstCategories" ItemTemplate="{StaticResource CategoryTemplate}" VerticalAlignment="Top" Height="439"> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True" /> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </Grid> |
Vamos definir agora a classe conversora chamada ImageConverter. No menu Project clique em Add Class, selecione o template Class e informe o nome ImageConverter.vb;
Após isso inclua o código a seguir nesta classe:
Imports System.IO Imports System.Globalization Public Class ImageConverter Implements IValueConverter Public Function Convert(ByVal value As Object, _ ByVal targetType As Type, _ ByVal parameter As Object, _ ByVal culture As CultureInfo) _ As Object Implements IValueConverter.Convert Dim BmpImage As BitmapSource Dim BmpBytes = DirectCast(value, System.Data.Linq.Binary).ToArray Using BmpStream = New MemoryStream() Dim NwOffset = 78 'para tratar imagens do tipo ole armazenadas no Northwind BmpStream.Write(BmpBytes, NwOffset, BmpBytes.Length - NwOffset) BmpImage = BitmapFrame.Create(BmpStream, _ BitmapCreateOptions.IgnoreImageCache, _ BitmapCacheOption.OnLoad) End Using Return BmpImage End Function Public Function ConvertBack(ByVal value As Object, _ ByVal targetType As Type, _ ByVal parameter As Object, _ ByVal culture As CultureInfo) _ As Object Implements IValueConverter.ConvertBack Return Nothing End Function End Class |
Esta classe implementa a interface IValueConverter e os métodos: Convert e ConvertBack;
Para concluímos basta definir no arquivo code-behind MainWindow.xaml.vb o código abaixo onde estamos usando o contexto definido pelo LINQ to SQL onde foi realizado o mapeamento das tabelas Products e Categories para as classes Product e Category:
Class MainWindow Public NorthwindDados As New NorthwindDataContext Private Sub Window1_Loaded(ByVal sender As System.Object, _ ByVal e As RoutedEventArgs) Handles MyBase.Loaded lstCategories.ItemsSource = NorthwindDados.Categories End Sub End Class |
Executando o projeto teremos o seguinte resultado:
Você pode fazer o mesmo em aplicações Windows Forms mas vai dar um pouco mais de trabalho.
Pegue o projeto completo aqui: ListBox_Imagem.zip
"Deus é Espírito,e importa que os que o adoram o adorem em espírito e em verdade." (João 4:24)
Referências: