Click here to Skip to main content
15,881,852 members
Articles / Programming Languages / XML

Silverlight 1.1 Fun and Games

Rate me:
Please Sign up or sign in to vote.
4.91/5 (126 votes)
1 Nov 200727 min read 383.7K   816   238  
Silverlight 1.1 Fun and Games
using System;
using System.IO;
using System.Reflection;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Media.Animation;

namespace SilverlightProject1.Controls
{
    internal enum ActionType { Selecting, Moving, RotatingScaling };

    /// <summary>
    /// Provides a Microsoft Surface like Canvas, where <see cref="Photo">Photos</see>
    /// may be resized and dragged/rotated/and removed
    /// </summary>
    public class ImageCanvas : Canvas
    {

        #region Instance fields
        private Photo _activePhoto;
        private Photo _pendingPhoto;
        private ActionType _actionType;
        private Point _photoCenter;
        private Point _lastPosition;
        private SilverlightProject1.FlickrService.PhotoInfo[] _Photos;
        public static bool RemoveArtWorkOnPhotoAdd=false;
        private ArtyCanvas _ac;
        #endregion
        #region Ctor
        public ImageCanvas()
        {
            this.SetValue(Canvas.BackgroundProperty, Color.FromRgb(210, 223, 232));
            this.SetValue(Canvas.WidthProperty, 1000);
            this.SetValue(Canvas.HeightProperty, 800);

            // Hook up event handlers
            BrowserHost.Resize += new EventHandler(BrowserHost_Resize);
            MouseLeftButtonUp += new MouseEventHandler(OnMouseLeftButtonUpOrLeave);
            MouseLeave += new EventHandler(OnMouseLeftButtonUpOrLeave);
            MouseMove += new MouseEventHandler(OnMouseMove);

            CreateArtyCanvas();
        }
        #endregion
        #region Public properties/methods
        public void AddPhoto(SilverlightProject1.FlickrService.PhotoInfo file)
        {
            if (ImageCanvas.RemoveArtWorkOnPhotoAdd)
                this.Children.Remove(_ac);
            new Photo(this, file);
            _ac.Opacity = 0.3;
        }

        public double Left
        {
            get
            {
                return (double)GetValue(Canvas.LeftProperty);
            }
            set
            {
                SetValue(Canvas.LeftProperty, value);
            }
        }

        public double Top
        {
            get
            {
                return (double)GetValue(Canvas.TopProperty);
            }
            set
            {
                SetValue(Canvas.TopProperty, value);
            }
        }
        #endregion
        #region Private/Internal properties/methods
        private void BrowserHost_Resize(object sender, EventArgs e)
        {
            // Set size to host size
            Width = BrowserHost.ActualWidth;
            Height = (BrowserHost.ActualHeight - Constants.TOP_CANVAS_TOP_POS);
        }

        private void OnMouseLeftButtonUpOrLeave(object sender, EventArgs e)
        {
            if (null != _activePhoto)
            {
                // Tell the previously active photo to hide its controls (in case the mouse already left it)
                Photo previouslyActivePhoto = _activePhoto;
                _activePhoto = null;
                previouslyActivePhoto.HideControls();
            }
            if (null != _pendingPhoto)
            {
                // Tell the pending photo (if any) to show its controls
                _pendingPhoto.ShowControls();
                _pendingPhoto = null;
            }
        }

        private void OnMouseMove(object sender, MouseEventArgs e)
        {
            if (null != _activePhoto)
            {
                // Perform the appropriate transform on the active photo
                var position = e.GetPosition(null);
                switch (_actionType)
                {
                    case ActionType.Moving:
                        // Move it by the amount of the mouse move
                        _activePhoto.Translate(position.X - _lastPosition.X, position.Y - _lastPosition.Y);
                        break;
                    case ActionType.RotatingScaling:
                        // Rotate it according to the angle the mouse moved around the photo's center
                        var radiansToDegrees = 360 / (2 * Math.PI);
                        var lastAngle = Math.Atan2(_lastPosition.Y - _photoCenter.Y, _lastPosition.X - _photoCenter.X) * radiansToDegrees;
                        var currentAngle = Math.Atan2(position.Y - _photoCenter.Y, position.X - _photoCenter.X) * radiansToDegrees;
                        _activePhoto.Rotate(currentAngle - lastAngle);

                        // Scale it according to the distance the mouse moved relative to the photo's center
                        var lastLength = Math.Sqrt(Math.Pow(_lastPosition.Y - _photoCenter.Y, 2) + Math.Pow(_lastPosition.X - _photoCenter.X, 2));
                        var currentLength = Math.Sqrt(Math.Pow(position.Y - _photoCenter.Y, 2) + Math.Pow(position.X - _photoCenter.X, 2));
                        _activePhoto.Scale(currentLength / lastLength);
                        break;
                }
                _lastPosition = position;
            }
        }

        private void CreateArtyCanvas()
        {
            _ac = new ArtyCanvas();
            _ac.Left = 0;
            _ac.Top = 0;
            _ac.Opacity = 1.0;
            this.Children.Add(_ac);
        }

        internal void SetActivePhoto(Photo photo, ActionType actionType, Point photoCenter, Point lastPosition)
        {
            if (null == _activePhoto)
            {
                // Set the active photo and note the relevant details
                _activePhoto = photo;
                _actionType = actionType;
                _photoCenter = photoCenter;
                _lastPosition = lastPosition;

                // Bring the active photo to the top
                Children.Remove(_activePhoto);
                Children.Add(photo);
            }
        }

        internal void RemovePhoto(Photo photo)
        {
            this.Children.Remove(photo);
            if (ImageCanvas.RemoveArtWorkOnPhotoAdd)
            {
                if (this.Children.Count == 0 )
                    CreateArtyCanvas();
            }
            else if (this.Children.Contains(_ac) && this.Children.Count == 1)
                    _ac.Opacity = 1.0;

        }


        internal Photo GetActivePhoto()
        {
            return _activePhoto;
        }

        internal void SetPendingPhoto(Photo photo)
        {
            _pendingPhoto = photo;
        }
        #endregion
    }

    /// <summary>
    /// Provides a resizable/draggable/rotatable Photo that may be placed on 
    /// a <see cref="ImageCanvas">ImageCanvas</see>. This classes uses the
    /// <see cref="DisplayImage.ashx">DisplayImage.ashx</see> handler to fetch
    /// the remote (not localost) image. In this case from Flickr
    /// </summary>
    internal class Photo : Control
    {
        #region Instance fields
        private static Random _random = new Random();
        private ImageCanvas _parent;
        private FrameworkElement _root;
        private Image _image;
        private Image _imgClose;
        private Canvas _allControls;
        private RotateTransform _rotateTransform;
        private ScaleTransform _scaleTransform;
        private TranslateTransform _translateTransform;
        private bool _mouseOver;
        private string _imageUrl;
        private Downloader _Downloader;
        private SilverlightProject1.FlickrService.PhotoInfo _file;
        #endregion
        #region Ctor
        public Photo(ImageCanvas parent, SilverlightProject1.FlickrService.PhotoInfo file)
        {
            // Load the control's XAML from the embedded resource
            System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream("SilverlightProject1.Controls.Photo.xaml");
            _root = this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());
            // Initialize
            _parent = parent;
            _file = file;
            _Downloader = new Downloader();
            _Downloader.Completed += new EventHandler(Downloader_Completed);
            // Fetch elements from the loaded XAML
            _image = _root.FindName("image") as Image;
            _imgClose = _root.FindName("imgClose") as Image;
            _imgClose.MouseLeftButtonUp += new MouseEventHandler(ImgClose_MouseLeftButtonUp);
            TextBlock tb = _root.FindName("imgText") as TextBlock;
            tb.Text = _file.Title.Length > 20 ? _file.Title.Substring(0, 20) + "..." : _file.Title;
            _rotateTransform = _root.FindName("rotateTransform") as RotateTransform;
            _scaleTransform = _root.FindName("scaleTransform") as ScaleTransform;
            _translateTransform = _root.FindName("translateTransform") as TranslateTransform;
            _allControls = _root.FindName("allControls") as Canvas;
            Canvas translateControls = _root.FindName("translateControls") as Canvas;
            Canvas rotateScaleControls = _root.FindName("rotateScaleControls") as Canvas;

            _allControls.Opacity = 0;
            _root.Visibility = Visibility.Collapsed;

            // Hook up event handlers
            _root.MouseLeftButtonDown += new MouseEventHandler(Root_MouseLeftButtonDown);
            _allControls.MouseEnter += new MouseEventHandler(AllControls_MouseEnter);
            _allControls.MouseLeave += new EventHandler(AllControls_MouseLeave);
            translateControls.MouseLeftButtonDown += new MouseEventHandler(TranslateControls_MouseLeftButtonDown);
            rotateScaleControls.MouseLeftButtonDown += new MouseEventHandler(RotateScaleControls_MouseLeftButtonDown);
            // Position and rotate the photo randomly
            Translate(_random.Next((int)(BrowserHost.ActualWidth - _root.Width)), _random.Next((int)((BrowserHost.ActualHeight - Constants.TOP_CANVAS_TOP_POS) - _root.Height)));
            Rotate(_random.Next(-30, 30));
            // Add the photo to the parent and play the display animation
            _parent.Children.Add(this);
            (_root.FindName("display") as Storyboard).Begin();
            this.ImageUrl = GetPhotoUrl(_file);
        }
        #endregion
        #region Public properties/methods
        public string ImageUrl
        {
            get { return _imageUrl; }
            set
            {
                _imageUrl = value;
                if (!String.IsNullOrEmpty(_imageUrl) && _imageUrl.IndexOf("http") >= 0)
                {
                    try
                    {
                        string url = value;
                        string fullImageUrl = "http://localhost:49505/WebSite1/DisplayImage.ashx?URL=" + url + "&Width=250";
                        Uri uri = new Uri(fullImageUrl, UriKind.Absolute);
                        _Downloader.Open("GET", uri);
                        _Downloader.Send();
                    }
                    catch (Exception ee)
                    {

                        string str = ee.ToString();
                    }
                }
            }
        }

        public void Translate(double deltaX, double deltaY)
        {
            _translateTransform.X += deltaX;
            _translateTransform.Y += deltaY;
        }

        public void Rotate(double deltaAngle)
        {
            _rotateTransform.Angle += deltaAngle;
        }

        public void Scale(double deltaScale)
        {
            _scaleTransform.ScaleX *= deltaScale;
            _scaleTransform.ScaleY *= deltaScale;
        }

        public void ShowControls()
        {
            if (_mouseOver)
            {
                // If the mouse is (still) over the photo
                if (null == _parent.GetActivePhoto())
                {
                    // No active photo, so this photo can show its controls
                    _allControls.Opacity = 0.4;
                }
                else
                {
                    // Let the parent know this photo is ready to show its controls
                    _parent.SetPendingPhoto(this);
                }
            }
        }

        public void HideControls()
        {
            if (!_mouseOver && (this != _parent.GetActivePhoto()))
            {
                // If the mouse is not over the photo and it's not the active photo, hide its controls
                _allControls.Opacity = 0;
            }
        }
        #endregion
        #region Private properties/methods
        private string GetPhotoUrl(SilverlightProject1.FlickrService.PhotoInfo file)
        {
            return "http://farm" + file.Farm + ".static.flickr.com/" +
                           file.Server + "/" + file.Id + "_" +
                            file.Secret + "_m.jpg";
        }

        private void ImgClose_MouseLeftButtonUp(object sender, MouseEventArgs e)
        {
            _parent.RemovePhoto(this);
        }

        private void Downloader_Completed(object sender, EventArgs e)
        {

            _image.SetSource(_Downloader, null);
            _root.Visibility = Visibility.Visible;
        }

        private void AllControls_MouseEnter(object sender, MouseEventArgs e)
        {
            _mouseOver = true;
            ShowControls();
        }

        private void AllControls_MouseLeave(object sender, EventArgs e)
        {
            _mouseOver = false;
            HideControls();
        }

        private void Root_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            HandleMouseLeftButtonDown(ActionType.Selecting, e);
        }

        private void TranslateControls_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            HandleMouseLeftButtonDown(ActionType.Moving, e);
        }

        private void RotateScaleControls_MouseLeftButtonDown(object sender, MouseEventArgs e)
        {
            HandleMouseLeftButtonDown(ActionType.RotatingScaling, e);
        }

        private void HandleMouseLeftButtonDown(ActionType actionType, MouseEventArgs e)
        {
            // Give the parent information about the new active photo
            _parent.SetActivePhoto(this, actionType, new Point(_translateTransform.X + _rotateTransform.CenterX, _translateTransform.Y + _rotateTransform.CenterY), e.GetPosition(null));
        }
        #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 has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)

- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence

Both of these at Sussex University UK.

Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2016
  • Codeproject MVP 2016
  • Microsoft C# MVP 2015
  • Codeproject MVP 2015
  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions