Search This Blog

C# Image Zoom Extender control















[ProvideProperty("AfterZoomImage", typeof(PictureBox))]
[ProvideProperty("ZoomFactor", typeof(PictureBox))]
public partial class ImageZoomProvider : Component, IExtenderProvider
{
    public ImageZoomProvider()
    {
        InitializeComponent();
        AnchorStyle = AnchorPoint.TopLeft;
    }

    // Theses will hold references to extended objects.
    private Hashtable pictureBoxes = new Hashtable();
    private Hashtable afterZoomImages = new Hashtable();

    #region "AfterZoomImage"

    [DefaultValue(null)]
    [Description("The image that will be used to display the zoomed image, if set to null the value of the PictureBox.Image property will be used instead")]
    [Category("ImageZoomProvider")]
    public Image GetAfterZoomImage(PictureBox pictureBox)
    {
        if (pictureBox == null)
        {
            throw new ArgumentNullException("pictureBox");
        }
        Image imageAfterZoom = null;
        if (afterZoomImages.Contains(pictureBox))
        {
            imageAfterZoom = afterZoomImages[pictureBox] as Image;
        }
        return imageAfterZoom;
    }

    public void SetAfterZoomImage(PictureBox pictureBox, Image afterZoomImage)
    {
        if (pictureBox == null)
        {
            throw new ArgumentNullException("pictureBox");
        }

        if (afterZoomImage == null)
        {
            if (afterZoomImages.Contains(pictureBox))
                afterZoomImages.Remove(pictureBox);
        }
        else
            afterZoomImages[pictureBox] = afterZoomImage;
    }

    #endregion

    #region IExtenderProvider Members

    public bool CanExtend(object extendee)
    {
        return extendee is PictureBox;
    }

    #endregion

    #region "ZoomFactor"

    [DefaultValue(1)]
    [Description("The factor by which the Image will be zoomed")]
    [Category("ImageZoomProvider")]
    public int GetZoomFactor(PictureBox pictureBox)
    {
        if (pictureBox == null)
        {
            throw new ArgumentNullException("pictureBox");
        }

        object value = pictureBoxes[pictureBox];
        if (value != null)
        {
            return (int)value;
        }
        else
            return ImageZoomProvider.NoZoom;
    }

    public void SetZoomFactor(PictureBox pictureBox, int zoomFactor)
    {

        if (pictureBox == null)
        {
            throw new ArgumentNullException("pictureBox");
        }
        // To Do validate Zoom Factor here.
        if (zoomFactor < 1)
        {
            throw new ArgumentException("ZoomFactor should be greater or equal to 1");
        }
        object oldZoomFactor = pictureBoxes[pictureBox];

        if (oldZoomFactor == null)
        {
            // No zoom factor was associated to this control. Then add zoom factor and set handlers.
            if (zoomFactor != NoZoom)
            {
                pictureBoxes[pictureBox] = zoomFactor;
                if (ZoomOnClick)
                {
                    pictureBox.Click += new EventHandler(OnPictureBoxClick);
                }
                else
                {
                    pictureBox.MouseEnter += new EventHandler(OnPictureBoxMouseEnter);
                    pictureBox.MouseLeave += new EventHandler(OnPictureBoxMouseLeave);
                }
            }
        }
        else
        {
            int oldZoomValue = (int)oldZoomFactor;
            // Zomm Factor has changed ?
            if (oldZoomValue != zoomFactor)
            {
                // update the zoom factor.
                pictureBoxes[pictureBox] = zoomFactor;
                if (zoomFactor == NoZoom)
                {
                    // Remove zoom logic.
                    pictureBoxes.Remove(pictureBox);
                    if (ZoomOnClick)
                    {
                        pictureBox.Click -= new EventHandler(OnPictureBoxClick);
                    }
                    else
                    {
                        pictureBox.MouseEnter -= new EventHandler(OnPictureBoxMouseEnter);
                        pictureBox.MouseLeave -= new EventHandler(OnPictureBoxMouseLeave);
                    }
                }
            }
        }
    }



    #endregion

    #region "Public Properties"

    [DefaultValue(100)]
    [Description("When ZoomOnClick property is false, this value is used as an initial delay debore showing the zoomed picture")]
    [Category("ImageZoomProvider")]
    public int ZoomDelay
    {
        get
        {
            return timer.Interval;
        }
        set
        {
            timer.Interval = value;
        }
    }

    [DefaultValue(100)]
    [Description("When UseAnimation is set to true, this value controls how fast the animation is")]
    [Category("ImageZoomProvider")]
    public int AnimationInterval
    {
        get
        {
            return timerAnimation.Interval;
        }
        set
        {
            timerAnimation.Interval = value;
        }
    }

    private AnchorPoint anchorStyle = AnchorPoint.TopLeft;
    [Category("ImageZoomProvider")]
    [DefaultValue(AnchorPoint.TopLeft)]
    public AnchorPoint AnchorStyle
    {
        get { return anchorStyle; }
        set { anchorStyle = value; }
    }

    private int border = 0;
    [Category("ImageZoomProvider")]
    [DefaultValue(0)]
    [Description("if value is different than 0, a border rectangle will be drawn around the zoomed image")]
    public int Border
    {
        get { return border; }
        set { border = value; }
    }

    [Category("ImageZoomProvider")]
    [DefaultValue(false)]
    [Description("if set to true, the image will grow in steps")]
    public bool UseAnimation { get; set; }

    private ImageZoomForm zoomForm = null;
    private static int noZoom = 1;

    public static int NoZoom
    {
        get { return ImageZoomProvider.noZoom; }
    }

    private bool zoomOnClick = false;
    [DefaultValue(false)]
    [Description("If set to true then zoom will be triggered by mouse click, otherwise mouse hover will trigger the zoom")]
    [Category("ImageZoomProvider")]
    public bool ZoomOnClick
    {
        get { return zoomOnClick; }
        set
        {
            if (zoomOnClick != value)
            {
                zoomOnClick = value;
                UpdatePictureBoxesHandlers();
            }
        }
    }

    #endregion


    private void UpdatePictureBoxesHandlers()
    {
        if (pictureBoxes != null)
        {
            foreach (PictureBox pictureBox in pictureBoxes.Keys)
            {
                if (ZoomOnClick)
                {
                    pictureBox.MouseEnter -= new EventHandler(OnPictureBoxMouseEnter);
                    pictureBox.MouseLeave -= new EventHandler(OnPictureBoxMouseLeave);
                    pictureBox.Click += new EventHandler(OnPictureBoxClick);
                }
                else
                {
                    pictureBox.Click -= new EventHandler(OnPictureBoxClick);
                    pictureBox.MouseEnter += new EventHandler(OnPictureBoxMouseEnter);
                    pictureBox.MouseLeave += new EventHandler(OnPictureBoxMouseLeave);
                }
            }
        }
    }

    public ImageZoomProvider(IContainer container)
    {
        container.Add(this);
        InitializeComponent();
    }

    void OnPictureBoxClick(object sender, EventArgs e)
    {
        timer.Tag = sender;
        // No delay required. call timer.Tick event Handler.
        ShowZoomedPicture(timer, EventArgs.Empty);
    }

    void OnPictureBoxMouseLeave(object sender, EventArgs e)
    {
        timer.Tag = null;
        timer.Stop();
    }

    void OnPictureBoxMouseEnter(object sender, EventArgs e)
    {
        timer.Tag = sender;
        timer.Start();
    }

    private void ShowZoomedPicture(object sender, EventArgs e)
    {
        // Show zoomed window here.
        timer.Stop();
        if (pictureBoxes.Contains(timer.Tag))
        {
            int zoomFactor = (int)pictureBoxes[timer.Tag];
            PictureBox pictureBox = (PictureBox)timer.Tag;

            if (zoomForm == null)
                zoomForm = new ImageZoomForm();

            // Set zoom properties.
            zoomForm.InitialSize = pictureBox.Size;
            zoomForm.Border = Border;
            zoomForm.ZoomFactor = zoomFactor;

            Image afterZoomImage = GetAfterZoomImage(pictureBox);
            if (afterZoomImage == null)
                afterZoomImage = pictureBox.Image;


            if (zoomForm.Image != afterZoomImage)
                zoomForm.Image = afterZoomImage;


            if (!UseAnimation)
            {
                zoomForm.Size = new Size(zoomFactor * pictureBox.Size.Width,
                    zoomFactor * pictureBox.Size.Height);
                ControlAnchorer.AnchorControl(zoomForm, pictureBox,AnchorStyle);
                zoomForm.Show();
            }
            else
            {
                if (AnchorStyle == AnchorPoint.OverlapCenters || AnchorStyle == AnchorPoint.TopCenter)
                {
                    zoomForm.Size = new Size(zoomFactor * pictureBox.Size.Width,
                    zoomFactor * pictureBox.Size.Height);
                    ControlAnchorer.AnchorControl(zoomForm, pictureBox, AnchorStyle);
                }
                zoomForm.Size = new Size(pictureBox.Size.Width,
                        pictureBox.Size.Height);
                if(AnchorStyle != AnchorPoint.OverlapCenters && AnchorStyle != AnchorPoint.TopCenter)
                    ControlAnchorer.AnchorControl(zoomForm, pictureBox, AnchorStyle);

                originalSize = zoomForm.Size;
                growSize = new Size((zoomFactor -1) * originalSize.Width /3,( zoomFactor-1)  * originalSize.Height/3 );
                counter = 0;

                timerAnimation.Tag = pictureBox;
                timerAnimation.Start();
                zoomForm.Show();
                }
        }
    }

    private Size originalSize = Size.Empty;
    private Size growSize = Size.Empty;
    private int counter = 0;
    private void timerAnimation_Tick(object sender, EventArgs e)
    {
        if (counter < 3)
        {
            zoomForm.Size += growSize;
            //ControlAnchorer.AnchorControl(zoomForm, timerAnimation.Tag as Control, AnchorStyle);
            counter++;
        }
        else
        {
            timerAnimation.Stop();
        }
    }



    internal class ImageZoomForm : Form
    {
        private int border = 0;
        private Size initialSize;
        private int zoomFactor = 1;

        private PictureBox zoomedPicture = null;

        public int Border
        {
            get { return border; }
            set
            {
                border = value;
                UpdateZoomedPictureSize();
            }
        }

        public Size InitialSize
        {
            get { return initialSize; }
            set
            {
                initialSize = value;
                Size = value;
                UpdateZoomedPictureSize();
            }
        }


        public int ZoomFactor
        {
            get { return zoomFactor; }
            set
            {
                zoomFactor = value;
            }
        }

        private void UpdateZoomedPictureSize()
        {
            if (zoomedPicture != null)
            {
                zoomedPicture.Size = new Size(initialSize.Width  - (border * 2),
                    initialSize.Height  - (border * 2));
                zoomedPicture.Location = new Point(border, border);
            }
        }

        public ImageZoomForm()
        {
            TopMost = true;
            BackColor = Color.Black;
            ShowInTaskbar = false;
            StartPosition = FormStartPosition.Manual;
            FormBorderStyle = FormBorderStyle.None;
            zoomedPicture = new PictureBox();
            zoomedPicture.SizeMode = PictureBoxSizeMode.Zoom;
            zoomedPicture.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Bottom;
            zoomedPicture.Click += new EventHandler(OnClick);
            Click += new EventHandler(OnClick);
            LostFocus += new EventHandler(OnLostFocus);
            Controls.Add(zoomedPicture);
        }

        void OnLostFocus(object sender, EventArgs e)
        {
            Hide();
        }

        void OnClick(object sender, EventArgs e)
        {
            PictureBox pictureBox = sender as PictureBox;
            if (pictureBox != null)
            {
                ((Form)pictureBox.Parent).Hide();
            }
            else
                ((Form)sender).Hide();
        }

        public Image Image
        {
            get
            {
                return zoomedPicture.Image;
            }
            set
            {
                zoomedPicture.Image = value;
            }
        }

        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (keyData == Keys.Escape)
            {
                DialogResult = System.Windows.Forms.DialogResult.OK;
                Hide();
                return true;
            }
            else
            {
                return base.ProcessCmdKey(ref msg, keyData);
            }
        }


    }



}


References:
Developing .NET Custom Controls and Designers Using Visual Basic .NET (Second Edition)
Pro .NET 2.0 Windows Forms and Custom Controls in C#