none
Display Thumbnail Images

    Question

  • Hello. 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.  
    Wednesday, March 04, 2009 12:35 AM

Answers

  • 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:52 AM

All replies

  • ...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!

    Friday, March 06, 2009 5:42 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:52 AM
  • Below is an example that show this approach.
    This program is created by Bea Stollnitz.

    Wednesday, March 11, 2009 7:54 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; 
            } 
        } 

    Wednesday, March 11, 2009 7:55 AM