Display Thumbnail Images
-
Wednesday, March 04, 2009 12:35 AMHello. I am trying to create an image viewer in WPF that will allow me to display all images from a specified folder, in thumbnail size. I then want to be able to drag and drop those images anywhere on the canvas.
I have found some good resources for drag and drop
http://www.codeproject.com/KB/WPF/DraggingElementsInCanvas.aspx?fid=335963&fr=1#xx0xx
and a also some good resources for creating thumbnail images
http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/6fa5f3bf-f274-4d8e-8ba7-7788fdc1e2fd/.
In addition to those, I found a good post on modifying a list control to behave more like a canvas
http://cromwellhaus.com/blogs/ryanc/archive/2008/11/03/the-wpf-mindset.aspx. (This one seemed like what I was looking for, but I could not figure out how to implement drag/drop on the individual list items.)
I have already been able to create an observable collection and populate a databound list view with those images. Now I am trying to connect the dots.
My question is what is the best way to approach the image display? Do I programmatically create new thumbnail image instances on a canvas for each image or is it better (or even possible) to databind a control, like a listview, to a collection and somehow modify the control to allow me to drag and drop each list item anywhere on the screen. The whole idea is to have a user experience as though you were sitting at a table with several photos spread out in front of you. You could rearrange the individual photos however you want on the table. This is why I am not just using a default list box. Thanks for any help on this.
All Replies
-
Friday, March 06, 2009 5:42 AM
...or to be less wordy...
How can I take an observable collection of images and display them as individual thumbnail image objects on a canvas?
Eventually want to be able to drag and drop each of the images around on the canvas, but I will deal with that functionality later. This is the reason why I am not just binding to a list box. Thanks! -
Wednesday, March 11, 2009 7:52 AM
Based on my understanding, the approach can be divided into 5 steps:
The first step, define a class (named “PositionImage”) which contains the information of thumbnail image, X position and Y position.
The second step, converts all the images into the PositionImage
The third step, push these instances into an ObservableCollection;
The fourth step, bind the ObservableCollection to a ListBox in Canvas.
The fifth step, modify the template of ListBoxItem to make it suitable to display and layout image.
- Marked As Answer by Tao Liang Wednesday, March 11, 2009 7:52 AM
-
Wednesday, March 11, 2009 7:54 AM
Below is an example that show this approach.
This program is created by Bea Stollnitz.
-
Wednesday, March 11, 2009 7:55 AM
XAML:<Window x:Class="PlanetsListBox.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:PlanetsListBox" Title="PlanetsListBox" Height="700" Width="700" > <Window.Resources> <local:SolarSystem x:Key="solarSystem" /> <local:ConvertOrbit x:Key="convertOrbit" /> <DataTemplate DataType="{x:Type local:SolarSystemObject}"> <Canvas Width="20" Height="20" > <Ellipse Canvas.Left="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=-1.707}" Canvas.Top="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=-0.293}" Width="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=2}" Height="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=2}" Stroke="White" StrokeThickness="1"/> <Image Source="{Binding Path=Image}" Width="20" Height="20"> <Image.ToolTip> <StackPanel Width="250" TextBlock.FontSize="12"> <TextBlock FontWeight="Bold" Text="{Binding Path=Name}" /> <StackPanel Orientation="Horizontal"> <TextBlock Text="Orbit: " /> <TextBlock Text="{Binding Path=Orbit}" /> <TextBlock Text=" AU" /> </StackPanel> <TextBlock Text="{Binding Path=Details}" TextWrapping="Wrap"/> </StackPanel> </Image.ToolTip> </Image> </Canvas> </DataTemplate> <Style TargetType="ListBoxItem"> <Setter Property="Canvas.Left" Value="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=0.707}"/> <Setter Property="Canvas.Bottom" Value="{Binding Path=Orbit, Converter={StaticResource convertOrbit}, ConverterParameter=0.707}"/> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBoxItem}"> <Grid> <Ellipse x:Name="selectedPlanet" Margin="-10" StrokeThickness="2"/> <ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/> </Grid> <ControlTemplate.Triggers> <Trigger Property="IsSelected" Value="true"> <Setter Property="Stroke" TargetName="selectedPlanet" Value="Yellow"/> </Trigger> </ControlTemplate.Triggers> </ControlTemplate> </Setter.Value> </Setter> </Style> <Style TargetType="ListBox"> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <Canvas Width="590" Height="590" Background="Black" /> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style> </Window.Resources> <Grid HorizontalAlignment="Center" VerticalAlignment="Center" ClipToBounds="True"> <ListBox ItemsSource="{Binding Source={StaticResource solarSystem}, Path=SolarSystemObjects}" Focusable="False" /> </Grid> </Window>
C#:using System; using System.Windows.Data; using System.Collections.ObjectModel; using System.Globalization; namespace PlanetsListBox { /// <summary> /// Interaction logic for Window1.xaml /// </summary> public partial class Window1 : System.Windows.Window { public Window1() { InitializeComponent(); } } public class SolarSystem { private ObservableCollection<SolarSystemObject> solarSystemObjects; public ObservableCollection<SolarSystemObject> SolarSystemObjects { get { return solarSystemObjects; } } public SolarSystem() { this.solarSystemObjects = new ObservableCollection<SolarSystemObject>(); this.solarSystemObjects.Add(new SolarSystemObject("Sun", 0, 1380000, new Uri(@"Images\sun.jpg", UriKind.Relative), "The yellow dwarf star in the center of our solar system.")); this.solarSystemObjects.Add(new SolarSystemObject("Mercury", 0.38, 4880, new Uri(@"Images\merglobe.gif", UriKind.Relative), "The small and rocky planet Mercury is the closest planet to the Sun.")); this.solarSystemObjects.Add(new SolarSystemObject("Venus", 0.72, 12103.6, new Uri(@"Images\venglobe.gif", UriKind.Relative), "At first glance, if Earth had a twin, it would be Venus.")); this.solarSystemObjects.Add(new SolarSystemObject("Earth", 1, 12756.3, new Uri(@"Images\earglobe.gif", UriKind.Relative), "Earth, our home planet, is the only planet in our solar system known to harbor life.")); this.solarSystemObjects.Add(new SolarSystemObject("Mars", 1.52, 6794, new Uri(@"Images\marglobe.gif", UriKind.Relative), "The red planet Mars has inspired wild flights of imagination over the centuries.")); this.solarSystemObjects.Add(new SolarSystemObject("Jupiter", 5.20, 142984, new Uri(@"Images\jupglobe.gif", UriKind.Relative), "With its numerous moons and several rings, the Jupiter system is a \"mini-solar system.\"")); this.solarSystemObjects.Add(new SolarSystemObject("Saturn", 9.54, 120536, new Uri(@"Images\2moons_2.gif", UriKind.Relative), "Saturn is the most distant of the five planets known to ancient stargazers.")); this.solarSystemObjects.Add(new SolarSystemObject("Uranus", 19.218, 51118, new Uri(@"Images\uraglobe.gif", UriKind.Relative), "Uranus gets its blue-green color from methane gas above the deeper cloud layers.")); this.solarSystemObjects.Add(new SolarSystemObject("Neptune", 30.06, 49532, new Uri(@"Images\nepglobe.gif", UriKind.Relative), "Neptune was the first planet located through mathematical predictions.")); this.solarSystemObjects.Add(new SolarSystemObject("Pluto", 39.5, 2274, new Uri(@"Images\plutoch_2.gif", UriKind.Relative), "Long considered to be the smallest, coldest, and most distant planet from the Sun.")); } } public class ConvertOrbit : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double orbit = (double)value; double factor = System.Convert.ToDouble(parameter, culture.NumberFormat); return Math.Pow(orbit / 40, 0.4) * 770 * factor; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotSupportedException("This method should never be called"); } } public class SolarSystemObject { private string name; public string Name { get { return name; } set { name = value; } } // In Astronomic Units (AU) private double orbit; public double Orbit { get { return orbit; } set { orbit = value; } } // In Km private double diameter; public double Diameter { get { return diameter; } set { diameter = value; } } private Uri image; public Uri Image { get { return image; } set { image = value; } } private string details; public string Details { get { return details; } set { details = value; } } public SolarSystemObject(string name, double orbit, double diameter, Uri image, string details) { this.name = name; this.orbit = orbit; this.diameter = diameter; this.image = image; this.details = details; } public override string ToString() { return this.name; } } }

