Introduction
This application shows how easy it is to create Google's Picasa Web album viewer using WPF and XMLDataProvider
.
Background
As there are a number of applications that do the same using code behind, I have tried to use XAML wherever possible (moreover, there are no WPF sample applications I know that use Picasa Web APIs, so Picasa Web was my default choice). I could have extended the application but I think this should be enough to give you a head start. I am not following best practices as my main aim is to show the easiness and the concept.
Using the Code
The application is a window based application and uses a dock panel. The dock panel has two panels i.e. left
and right
. The left
panel contains a listbox
that enumerates the various albums from my picasaweb folder. The right
panel displays all the pictures from the selected album.
<Window x:Class="PictureViewer.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PictureViewer"
Title="PictureViewer" SizeToContent="WidthAndHeight"
>
<DockPanel>
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBox DockPanel.Dock="Left" SelectionChanged="OnSelctionChanged"
DataContext="{StaticResource Picasa}"
ItemsSource="{Binding XPath=default:feed/default:entry/default:title}">
</ListBox>
</ScrollViewer>
<ListBox x:Name="MyListBox" ...>
...
</ListBox>
</DockPanel>
</Window>
To read the albums from Picasa Web album, the xmldataprovider
should understand and use the same XML namespace
as Picasa Web. To do this, add the following XML namespace
tags as a dockpanel resource:
<XmlNamespaceMappingCollection x:Key="mapping">
<XmlNamespaceMapping Uri="http://www.w3.org/2005/Atom" Prefix="default"/>
<XmlNamespaceMapping Uri="http://schemas.google.com/photos/2007" Prefix="gphoto"/>
</XmlNamespaceMappingCollection>
Next, we need to add an xmldataprovider
as a resource so we could fetch albums from my picasaweb folder. Here we set the source to my picasaweb album folder. (You may bind and replace my user-id with yours but well, I am a narcissist so I am not going to show you how:
<XmlDataProvider x:Key="Picasa" XmlNamespaceManager="{StaticResource mapping}"
Source="http://picasaweb.google.com/data/feed/api/user/rohits79?kind=album">
</XmlDataProvider>
I have added the above two as a resource as we shall reuse and bind as a StaticResource
later in the project.
Now, when the application loads, it would get the list of all the albums from my picasaweb folder (as xmldataprovider
is part of the resource). Next we need that the listbox
in the left
panel should list all the albums. For this, parse the XML node list from the xmldataprovider
and read only the album's title; the populated album's title list should be set as ItemsSource
property of listbox
. The efficient way to do the above is by using XPath
as below.
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBox DockPanel.Dock="Left" DataContext="{StaticResource Picasa}"
ItemsSource="{Binding XPath=default:feed/default:entry/default:title}">
</ListBox>
</ScrollViewer>
Our next goal is that when the user clicks on the left listbox
we should show all the pictures from the selected album folder in the right listbox
/panel. To do this, add an event handler in the left listbox
.
<ListBox DockPanel.Dock="Left" SelectionChanged="OnSelctionChanged"
DataContext="{StaticResource Picasa}"
ItemsSource="{Binding XPath=default:feed/default:entry/default:title}">
The event handler shall get all pictures from the selected album folder using XMLDataprovider
which is also set as the datacontext
of the right listbox
as shown below:
public void OnSelctionChanged(Object source, RoutedEventArgs args)
{
ListBox lb = args.Source as ListBox;
string simplestr;
XmlDataProvider provider = MyListBox.DataContext as XmlDataProvider;
if (provider != null)
{
simplestr = lb.SelectedValue.ToString().Replace(" ", "");
simplestr = simplestr.Replace(",", "");
provider.Source = new Uri
(@http:
+ simplestr + "?kind=photo");
}
}
Once again, parse the binary picture content using XPath
as we did for the left listbox
.
<ListBox x:Name="MyListBox"
ItemsSource="{Binding XPath=/default:feed/default:entry/default:content}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderBrush="White">
Update the datatemplate
of the listbox
so that the listbox
items are rendered as images instead of as the default listbox
items.
<ListBox x:Name="MyListBox"
ItemsSource="{Binding XPath=/default:feed/default:entry/default:content}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderBrush="White">
<ListBox.DataContext>
<XmlDataProvider XmlNamespaceManager="{StaticResource mapping}">
</XmlDataProvider>
</ListBox.DataContext>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding XPath=@src}" Width="300"></Image>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
The following is the full XAML code where the right listbox
items are wrapped using WrapPanel
.
<Window x:Class="PictureViewer.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml
xmlns:local="clr-namespace:PictureViewer" Title="PictureViewer"
SizeToContent="WidthAndHeight"><DockPanel><DockPanel.Resources >
<XmlNamespaceMappingCollection x:Key="mapping">
<XmlNamespaceMapping Uri="http://www.w3.org/2005/Atom" Prefix="default"/>
<XmlNamespaceMapping Uri=http://schemas.google.com/photos/2007
Prefix="gphoto"/>
</XmlNamespaceMappingCollection><XmlDataProvider x:Key="Picasa"
XmlNamespaceManager="{StaticResource mapping}"
Source="http://picasaweb.google.com/data/feed/api/user/rohits79?kind=album">
</XmlDataProvider>
</DockPanel.Resources>
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto"
ScrollViewer.HorizontalScrollBarVisibility="Auto">
<ListBox DockPanel.Dock="Left" SelectionChanged="OnSelctionChanged"
DataContext="{StaticResource Picasa}"
ItemsSource="{Binding XPath=default:feed/default:entry/default:title}">
</ListBox>
</ScrollViewer>
<ListBox x:Name="MyListBox"
ItemsSource="{Binding XPath=/default:feed/default:entry/default:content}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderBrush="White">
<ListBox.DataContext>
<XmlDataProvider XmlNamespaceManager="{StaticResource mapping}">
</XmlDataProvider>
</ListBox.DataContext>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding XPath=@src}" Width="300"></Image>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</DockPanel>
</Window>
At the end, here is how the final application will look: