Mitsu Furuta (from Microsoft France) updated his Page Turner to Silverlight 2 RTM. Let's explain how to use it.
Let's first demonstrate the page turner, with paintings from Pablo Picasso (the Spanish-born painter is currently honored in Paris with several outstanding exhibitions). Please note that some pages are more than just images.
Project / source code
You can find Mitsu's component at the following address :
www.codeplex.com/wpfbookcontrol. Codeplex is really becoming a major player ! Download the zip-file and unzip it. You will find
SLMitsuControls.dll (a 35 KB file!) in the
SLMitsuControls/ClientBin folder. The component is under Ms-Pl licence, meaning you can use it in your own products, even commercial, for free (no royaltie to Microsoft, even if your product is not free) but, of course, you can't claim rights on ownership.
Let's now create a Silverlight application. Add a reference to SLMitsuControls.dll (in the Silverlight part of the project, right-click on the project, Add Reference and Browse to the folder containing the SLMitsuControls.dll file).
Let's first assume that our book-like control just contains images. These images need to be copied in the ClientBin folder (the one containing the XAP file). We first need to populate our book with these images. We keep file names (without extension) in an array of string (in Page.xaml.cs) :
string[] ts = {"Picasso", "Head", "Blind man", "At the Lapin Agile", "Chicks from Avignon",
"Woman crying", "Guitar player", "Auto portrait"};
In the UserControl tag (in Page.xaml), we add a xmlns tag for the control (any other name than local is OK), handle the Loaded event and insert our book in the first row of the main grid (the second row will contain a status bar implemented as a TextBlock) :
<UserControl x:Class="TurnThePage2.Page"
.....
xmlns:local="clr-namespace:SLMitsuControls;assembly=SLMitsuControls"
.....
Loaded="UserControl_Loaded" >
<Grid x:Name="LayoutRoot" Background="LightBlue" >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="25" />
</Grid.RowDefinitions>
<local:UCBook x:Name="book" Grid.Row="0" OnPageTurned="book_OnPageTurned" Margin="20" />
.....
</Grid>
</UserControl>
In the Page.xaml.cs file, we need to add a using, declare that the Page class implements the IDataProvider interface and implement two functions (just two small lines, always the same) :
.....
using SLMitsuControls;
.....
namespace TurnThePage2
{
public partial class Page : UserControl, IDataProvider
{
.....
public int GetCount()
{
return pages.Count;
}
public object GetItem(int index)
{
return pages[index];
}
}
}
In case our pages are just images, it's possible to keep them in a List<Image>. But some of our pages will be more elaborate (a page could for instance be a complex grid). So, we prefer List<UIElement> since UIElement is the base class for UI elements. But here, our book is (to begin) just a collection of images (only two images here, no need to show more) :
List<UIElement> pages;
.....
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
pages = new List<UIElement> {
new Image {Source=new BitmapImage(new Uri(ts[1]+".jpg",
UriKind.Relative)), Stretch=Stretch.UniformToFill },
new Image {Source=new BitmapImage(new Uri(ts[2]+".jpg", UriKind.Relative)),
Stretch=Stretch.UniformToFill }
};
book.SetData(this);
}
It's enough to get a page turner for images ! It's possible to handle the OnPageTurned event :
private void book_OnPageTurned(int leftPageIndex, int rightPageIndex)
{
.....
}
After a page turn, the arguments give you the left and right pages that are visible : starting at 1 (be careful !) and with -1 for absence of page.
Let's now complicate a bit : our first page will present an animated text on top of a photo and the last page will present a button on top of an image (remember : the images must be copied in the ClientBin folder). Our downloadable project is still a bit more complex (with a list box). We dynamically specify attributes for the grid in first page and dynamically add a TextBlock :
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
pages = new List {
new Grid (), // first page
new Image ..... // second page (image)
.....
new Image ....
new Grid() // last page
};
// specify first page
Grid g = pages[0] as Grid;
g.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri("Picasso.jpg",
UriKind.Relative)),
Stretch = Stretch.UniformToFill };
TextBlock tb = new TextBlock { Text = "Pablo\nPicasso", FontSize = 70,
Foreground = new SolidColorBrush(Color.FromArgb(255, 173, 216, 230)),
TextWrapping = TextWrapping.Wrap,
VerticalAlignment = VerticalAlignment.Center,
HorizontalAlignment = HorizontalAlignment.Center,
TextAlignment = TextAlignment.Center };
..... // here the animation on FontSize
g.Children.Add(tb);
......
The code to animate the FontSize property is :
Storyboard stbPage0 = new Storyboard();
Storyboard.SetTarget(stbPage0, tb);
DoubleAnimation daSize = new DoubleAnimation {From = 70, To = 0,
RepeatBehavior = RepeatBehavior.Forever,
AutoReverse = true };
daSize.Duration = new Duration(new TimeSpan(0, 0, 5));
Storyboard.SetTargetProperty(daSize, new PropertyPath("FontSize"));
stbPage0.Children.Add(daSize);
stbPage0.Begin();
The last page (with a button on top of an image) is similar :
g = pages[pages.Count - 1] as Grid;
g.Background = new ImageBrush { ImageSource = new BitmapImage(new Uri("Picasso2.jpg",
UriKind.Relative)), Stretch = Stretch.UniformToFill };
Button b = new Button { Content = "Back to the first page", Width = 130, Height = 50 };
b.Click += new RoutedEventHandler(b_Click);
g.Children.Add(b);
The function that handles the click being, as usual :
void b_Click(object sender, RoutedEventArgs e)
{
.....
}
To go back to the first page, we just need to write :
book.CurrentSheetIndex = 0;
It's possible to launch an animation to switch to a next or previous page :
book.AnimateToNextPage(1000);
.....
book.AnimateToPreviousPage(1000);
where the argument is the duration of the animation, expressed in milliseconds.