Click here to Skip to main content
15,884,176 members
Articles / Desktop Programming / WPF

Deep Zoom for WPF

Rate me:
Please Sign up or sign in to vote.
4.97/5 (54 votes)
24 Nov 2010Ms-PL13 min read 383.1K   9.1K   100  
An implementation of MultiScaleImage (Deep Zoom) for WPF, compatible with Deep Zoom Composer and Zoom.it.
using System;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace DeepZoom.Controls
{
    /// <summary>
    /// Simple FrameworkElement that draws and animates an image in the screen with the lowest possible overhead.
    /// </summary>
    public class TileHost : FrameworkElement
    {
        // Create a collection of child visual objects.
        private DrawingVisual _visual;
        private static readonly AnimationTimeline _opacityAnimation = 
            new DoubleAnimation(1, TimeSpan.FromMilliseconds(500)) { EasingFunction = new ExponentialEase() };

        public TileHost()
        {
            IsHitTestVisible = false;
        }

        public TileHost(ImageSource source, double scale)
            : this()
        {
            Source = source;
            Scale = scale;
        }

        #region Dependency Properties

        #region Source

        /// <summary>
        /// Source Dependency Property
        /// </summary>
        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(ImageSource), typeof(TileHost),
                new FrameworkPropertyMetadata(null,
                    new PropertyChangedCallback(RefreshTile)));

        /// <summary>
        /// Gets or sets the Source property. This dependency property 
        /// indicates the source of the image to be displayed.
        /// </summary>
        public ImageSource Source
        {
            get { return (ImageSource)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        #endregion

        #region Scale

        /// <summary>
        /// Scale Dependency Property
        /// </summary>
        public static readonly DependencyProperty ScaleProperty =
            DependencyProperty.Register("Scale", typeof(double), typeof(TileHost),
                new FrameworkPropertyMetadata(1.0,
                    new PropertyChangedCallback(RefreshTile)));

        /// <summary>
        /// Gets or sets the Scale property. This dependency property 
        /// indicates the scaling to be applied to this tile.
        /// </summary>
        public double Scale
        {
            get { return (double)GetValue(ScaleProperty); }
            set { SetValue(ScaleProperty, value); }
        }

        #endregion

        #endregion

        #region Private methods

        /// <summary>
        /// Called when the tile should be refreshed (Scale or Source changed)
        /// </summary>
        private static void RefreshTile(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var tileHost = d as TileHost;
            if (tileHost != null && tileHost.Source != null && tileHost.Scale > 0)
                tileHost.RenderTile();
        }

        private void RenderTile()
        {
            _visual = new DrawingVisual();
            Width = Source.Width * Scale;
            Height = Source.Height * Scale;
            var dc = _visual.RenderOpen();
            dc.DrawImage(Source, new Rect(0, 0, Width, Height));
            dc.Close();

            CacheMode = new BitmapCache(1 / Scale);

            // Animate opacity
            Opacity = 0;
            BeginAnimation(OpacityProperty, _opacityAnimation);
        }

        #endregion

        #region FrameworkElement overrides

        // Provide a required override for the VisualChildrenCount property.
        protected override int VisualChildrenCount
        {
            get { return _visual == null ? 0 : 1; }
        }

        // Provide a required override for the GetVisualChild method.
        protected override Visual GetVisualChild(int index)
        {
            return _visual;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Virtual Dreams
Brazil Brazil
Hi! I'm Roberto. I'm a Brazilian Engineering student at the University of São Paulo and the Ecole Centrale de Lille (France).

I've participated in the Imagine Cup competition and went to the world finals every year from 2005 to 2009. I also won the 1st place award in 2006, in India, for the Interface Design invitational, in 2007 in Korea, for the Embedded Development invitational, and in 2009 in Egypt for the Windows Mobile Award.

Currently I keep a blog (in English and Portuguese) at http://virtualdreams.com.br/blog/ and a weekly webcast about WPF and Silverlight (in Portuguese) at http://www.xamlcast.net.

Comments and Discussions