Desperately Seeking Love of Sophie

Updated Stack 3D Image Viewer

with 2 comments

I blogged about the little control (Stack 3D) that I wrote that shows pictures in virtual 3D. Here is the improved code for that. There are two improvements here…

  1. I added error handling code on PictureFrame so that when image fails to load it shows the text message
  2. I also changed the rotation logic so that I don’t add all pictures at the same time in the tree. Instead I only keep things that are needed in visual tree for given view.

Error handling for Picture Frame

This is pretty straight forward.

 public PictureFrame() 
        { 
            Stream s = this.GetType().Assembly.GetManifestResourceStream("Visualization.PictureFrame.xaml"); 
            _rootCanvas = (Canvas)this.InitializeFromXaml(new StreamReader(s).ReadToEnd()); 
            _image = (Image)_rootCanvas.FindName("image"); 
            _txterror = (TextBlock)_rootCanvas.FindName("txtError"); 
            _image.ImageFailed += new ErrorEventHandler(_image_ImageFailed); 
            _rectborder = (Rectangle)_rootCanvas.FindName("rectborder"); 
            _rootCanvas.Loaded += new EventHandler(_rootCanvas_Loaded); 
        }  

        void _image_ImageFailed(object sender, ErrorEventArgs e) 
        { 
            _txterror.Visibility = Visibility.Visible; 
        }

rotation logic

This was more interesting

using System; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Documents; 
using System.Windows.Ink; 
using System.Windows.Input; 
using System.Windows.Media; 
using System.Windows.Media.Animation; 
using System.Windows.Shapes; 
using System.Collections.ObjectModel; 
using System.IO;  

namespace Visualization 
{ 
    public class StackThreeD : Control 
    { 
        private Canvas _rootCanvas; 
        private int _numberOfFrames = 2; 
        private Collection<FrameworkElement> _frames; 
        private Collection<Point> _points; 
        private Collection<Size> _sizes; 
        private Collection<int> _currentview; 
        private FrameworkElement _hideframe; 
        private bool _enablemovenext = true;  

        public StackThreeD() 
        { 
            Stream s = this.GetType().Assembly.GetManifestResourceStream("Visualization.StackThreeD.xaml"); 
            _rootCanvas = (Canvas)this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd()); 
            _rootCanvas.Loaded += new EventHandler(_rootCanvas_Loaded); 
            _currentview = new Collection<int>();  

        }  

        public int NumberOfFrames 
        { 
            get { return _numberOfFrames; } 
            set 
            { 
                _numberOfFrames = value; 
                _currentview.Clear(); 
                for (int i = 0; i < _numberOfFrames; i++) 
                { 
                    _currentview.Add(i); 
                } 
            } 
        }  

        public Collection<FrameworkElement> Frames 
        { 
            get { return _frames; } 
            set 
            { 
                _frames = value; 
                PopulateTree(); 
            } 
        }  

        private void PopulateTree() 
        { 
            _rootCanvas.Children.Clear(); 
            if (_currentview.Count > 0) 
            { 
                foreach (int i in _currentview) 
                { 
                    FrameworkElement pf = _frames[i]; 
                    _rootCanvas.Children.Add(pf); 
                    pf.SetValue(DependencyObject.NameProperty, i.ToString()); 
                    string _transformstring; 
                    Stream s = this.GetType().Assembly.GetManifestResourceStream("Visualization.FrameTransform.xaml"); 
                    _transformstring = new StreamReader(s).ReadToEnd(); 
                    TransformGroup tg = (TransformGroup)XamlReader.Load(_transformstring); 
                    pf.RenderTransform = tg; 
                    AttachAnimation(pf); 
                    pf.Width = Width / 2; 
                    pf.Height = Height / 2;  

                } 
            } 
        }  

        public void MoveNext() 
        { 
            if (_enablemovenext == true) 
            { 
                _enablemovenext = false; 
                HideFrame(); 
                UpdateCurrentViewCollection(); 
                AddFrame(); 
                for (int i = 0; i < _numberOfFrames; i++) 
                { 
                    MoveFrame(i); 
                } 
            }  

        }  

        private void UpdateCurrentViewCollection() 
        { 
            for (int i = 0; i < _currentview.Count; i++) 
            { 
                _currentview[i] = _currentview[i] - 1; 
                if (_currentview[i] < 0) 
                    _currentview[i] = _frames.Count + _currentview[i]; 
            } 
        }  

        private void MoveFrame(int index) 
        { 
            FrameworkElement currentframe = _frames[_currentview[index]]; 
            currentframe.SetValue(UIElement.ZIndexProperty, index); 
            double startscale;  

            if (index == 0) 
            { 
                currentframe.SetValue(Canvas.TopProperty, 0); 
                currentframe.SetValue(Canvas.LeftProperty, 0); 
                startscale = 0.0001;  

            } 
            else 
                startscale = ((ScaleTransform)((TransformGroup)currentframe.RenderTransform).Children[0]).ScaleY;  

            Point startpoint = new Point((double)currentframe.GetValue(Canvas.LeftProperty), (double)currentframe.GetValue(Canvas.TopProperty)); 
            double endscale = (_sizes[index].Width / (Width / 2)); 
            AnimateFrame(_currentview[index], startpoint, _points[index], startscale, endscale).Begin();  

        }  

        private Storyboard AnimateFrame(int framenumber, Point startpoint, Point endpoint, double startscale, double endscale) 
        { 
            DoubleAnimation topanimation = (DoubleAnimation)_rootCanvas.FindName("topanimation" + framenumber.ToString()); 
            DoubleAnimation leftanimation = (DoubleAnimation)_rootCanvas.FindName("leftanimation" + framenumber.ToString()); 
            DoubleAnimation scalexanimation = (DoubleAnimation)_rootCanvas.FindName("scalexanimation" + framenumber.ToString()); 
            DoubleAnimation scaleyanimation = (DoubleAnimation)_rootCanvas.FindName("scaleyanimation" + framenumber.ToString());  

            scaleyanimation.From = startscale; 
            scalexanimation.From = startscale; 
            scalexanimation.To = endscale; 
            scaleyanimation.To = endscale;  

            topanimation.From = startpoint.Y; 
            leftanimation.From = startpoint.X; 
            topanimation.To = endpoint.Y; 
            leftanimation.To = endpoint.X;  

            return (Storyboard)_rootCanvas.FindName("storyboard" + framenumber.ToString());  

        }  

        private void HideFrame() 
        { 
            int framenumber = _currentview[_currentview.Count - 1]; 
            _hideframe = _frames[framenumber];  

            Point startpoint = new Point((double)_hideframe.GetValue(Canvas.LeftProperty), (double)_hideframe.GetValue(Canvas.TopProperty)); 
            Point endpoint = new Point(Width, Height); 
            Storyboard sb = AnimateFrame(framenumber, startpoint, endpoint, 1, 2); 
            sb.Completed += new EventHandler(sb_Completed); 
            sb.Begin(); 
        }  

        void sb_Completed(object sender, EventArgs e) 
        { 
            _rootCanvas.Children.Remove(_hideframe); 
            _enablemovenext = true; 
        }  

        private void AddFrame() 
        { 
            int framenumber = _currentview[0]; 
            FrameworkElement pf = _frames[framenumber]; 
            _rootCanvas.Children.Add(pf); 
            if (pf.Name == string.Empty) 
            { 
                pf.SetValue(DependencyObject.NameProperty, framenumber.ToString()); 
                string _transformstring; 
                Stream s = this.GetType().Assembly.GetManifestResourceStream("Visualization.FrameTransform.xaml"); 
                _transformstring = new StreamReader(s).ReadToEnd(); 
                TransformGroup tg = (TransformGroup)XamlReader.Load(_transformstring); 
                pf.RenderTransform = tg; 
                AttachAnimation(pf); 
                pf.Width = Width / 2; 
                pf.Height = Height / 2; 
            }  

            pf.SetValue(UIElement.ZIndexProperty, -1);  

        }  

        private void AttachAnimation(FrameworkElement pf) 
        { 
            string _frameanimation; 
            Stream s = this.GetType().Assembly.GetManifestResourceStream("Visualization.FrameAnimation.xaml"); 
            _frameanimation = new StreamReader(s).ReadToEnd(); 
            _frameanimation = _frameanimation.Replace("frame", pf.Name); 
            _frameanimation = _frameanimation.Replace("scalexanimation", "scalexanimation" + pf.Name); 
            _frameanimation = _frameanimation.Replace("scaleyanimation", "scaleyanimation" + pf.Name); 
            _frameanimation = _frameanimation.Replace("topanimation", "topanimation" + pf.Name); 
            _frameanimation = _frameanimation.Replace("leftanimation", "leftanimation" + pf.Name); 
            Storyboard sb = (Storyboard)XamlReader.Load(_frameanimation); 
            sb.SetValue(DependencyObject.NameProperty, "storyboard" + pf.Name); 
            _rootCanvas.Resources.Add(sb); 
        }  

        private void UpdateLayout() 
        {  

            if (Height > 0 && Width > 0) 
            { 
                _rootCanvas.Height = Height; 
                _rootCanvas.Width = Width; 
                //update clipping area 
                RectangleGeometry clip = new RectangleGeometry(); 
                clip.Rect = new Rect(0, 0, Width, Height); 
                _rootCanvas.Clip = clip; 
                CalculateSteps(); 
                if (_currentview.Count > 0) 
                { 
                    foreach (int i in _currentview) 
                    { 
                        FrameworkElement pf = _frames[i]; 
                        ((PictureFrame)pf).Height = Height / 2; 
                        ((PictureFrame)pf).Width = Width / 2; 
                        ((ScaleTransform)((TransformGroup)pf.RenderTransform).Children[0]).ScaleX = (_sizes[i].Width / (Width / 2)); 
                        ((ScaleTransform)((TransformGroup)pf.RenderTransform).Children[0]).ScaleY = (_sizes[i].Height / (Height / 2)); 
                        pf.SetValue(Canvas.TopProperty, _points[i].Y); 
                        pf.SetValue(Canvas.LeftProperty, _points[i].X); 
                    } 
                }  

            }  

        }  

        private void CalculateSteps() 
        { 
            _points = new Collection<Point>(); 
            _sizes = new Collection<Size>();  

            double xstep = Width / (2 * _numberOfFrames); 
            double ystep = Height / (2 * _numberOfFrames);  

            Point startpoint = new Point(xstep, ystep); 
            Size startsize = new Size(2 * xstep, 2 * ystep);  

            Point endpoint = new Point(Width / 2, Height / 2); 
            Size endsize = new Size(Width / 2, Height / 2);  

            _points.Add(startpoint); 
            _sizes.Add(startsize);  

            double widthstep = (Width / 2) / (_numberOfFrames + 1); 
            double heightstep = (Height / 2) / (_numberOfFrames + 1);  

            for (int i = 1; i < (_numberOfFrames - 1); i++) 
            { 
                Point p = new Point(startpoint.X + (i * xstep), startpoint.Y + (i * ystep)); 
                Size s = new Size(startsize.Width + (i * widthstep), startsize.Height + (i * heightstep)); 
                _points.Add(p); 
                _sizes.Add(s); 
            }  

            _points.Add(endpoint); 
            _sizes.Add(endsize); 
        }  

        private void _rootCanvas_Loaded(object sender, EventArgs e) 
        { 
            UpdateLayout(); 
        }  

        public new double Height 
        { 
            get { return ((FrameworkElement)this).Height; } 
            set 
            { 
                ((FrameworkElement)this).Height = value; 
                UpdateLayout(); 
            } 
        }  

        public new double Width 
        { 
            get { return ((FrameworkElement)this).Width; } 
            set 
            { 
                ((FrameworkElement)this).Width = value; 
                UpdateLayout(); 
            } 
        } 
    } 
} 

I think control behaves much better now and I was able to integrate with my search application. I will add the full source to search application with this control integrated.  Here is the source code for updated control.

About these ads

Written by Vivek

July 3, 2007 at 10:49 pm

Posted in Professional, Software

Tagged with

2 Responses

Subscribe to comments with RSS.

  1. [...] Menu for Thought ← Updated Stack 3D Image Viewer [...]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: