MainPage.xaml.cs
// theory to Mandelbrot set: http://www.ddewey.net/mandelbrot/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Media.Imaging;     // for WriteableBitmap
using System.Windows.Threading;         // for DispatcherTimer

namespace MandelbrotSet
{
    public partial class MainPage : UserControl
    {
        WriteableBitmap m_RenderTarget;
        DateTime m_LastUpdate;
        int width = 600;
        int height = 400;
        RECT rectClient;
        float xmin = -3;
        float xmax = 3;
        float ymin = -2;
        float ymax = 2;
        float zoom = 1;
        int flagMove;

        public MainPage()
        {
            InitializeComponent();

            this.KeyDown += new KeyEventHandler(MainPage_KeyDown);
            this.KeyUp += new KeyEventHandler(MainPage_KeyUp);

            m_RenderTarget = new WriteableBitmap(width, height);
            image1.Source = m_RenderTarget;

            DispatcherTimer timer = new DispatcherTimer();
            timer.Interval = new System.TimeSpan(0, 0, 0, 0, 1);
            timer.Tick += new EventHandler(timer_Tick);
            timer.Start();

            m_LastUpdate = DateTime.Now;

            rectClient.left = 0;
            rectClient.right = 600;
            rectClient.top = 0;
            rectClient.bottom = 400;
        }

        void timer_Tick(object sender, EventArgs e)
        {
            UpdateScene();
        }

        private void UpdateScene()
        {
            DateTime now = DateTime.Now;
            float deltaTime = (float)now.Subtract(m_LastUpdate).TotalSeconds;
            m_LastUpdate = now;

            Utilities.FillRect(rectClient, Utilities.RGBA(150, 150, 0, 255), m_RenderTarget.Pixels);
 
            text3.Text = string.Format("frame rate: {0}", 1.0f / deltaTime);

            MoveScreenView();
            MandelbrotSet();

            m_RenderTarget.Invalidate();
        }

        void MandelbrotSet()
        {
            int iter;
            ComplexNumber c;
            ComplexNumber z;
            float temp;

            for (int i = 0; i < width; i++)
            {
                for (int j = 0; j < height; j++)
                {
                    c.x = (float)(xmax - xmin) / width * ((float)i) + xmin;
                    c.y = (float) (ymax - ymin) / height * ((float)j) + ymin;

                    z.x = 0; z.y = 0;
                    iter = 0;
                    while (Math.Sqrt(z.x * z.x + z.y * z.y) <= 2 && iter < 30)
                    {
                        temp = z.x;
                        z.x = z.x * z.x - z.y * z.y + c.x;
                        z.y = 2.0f * temp * z.y + c.y;
                        iter++;
                    }
                    m_RenderTarget.Pixels[j * width + i] = Utilities.RGBA((byte)(100 + 3 * iter), (byte)(100 + 3 * iter), (byte)(100 + 3 * iter), 255);
                }
            }
        }

        void MainPage_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    flagMove |= (1 << 0);
                    break;
                case Key.Down:
                    flagMove |= (1 << 1);
                    break;
                case Key.Left:
                    flagMove |= (1 << 2);
                    break;
                case Key.Right:
                    flagMove |= (1 << 3);
                    break;
                case Key.I:
                    flagMove |= (1 << 4);
                    break;
                case Key.O:
                    flagMove |= (1 << 5);
                    break;
            }
        }

        void MainPage_KeyUp(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Up:
                    flagMove ^= (1 << 0);
                    break;
                case Key.Down:
                    flagMove ^= (1 << 1);
                    break;
                case Key.Left:
                    flagMove ^= (1 << 2);
                    break;
                case Key.Right:
                    flagMove ^= (1 << 3);
                    break;
                case Key.I:
                    flagMove ^= (1 << 4);
                    break;
                case Key.O:
                    flagMove ^= (1 << 5);
                    break;
            }
        }

        void MoveScreenView()
        {
            float step = 0.05f * (xmax - xmin);

            if (0 != (flagMove & (1 << 0))) { ymin += step; ymax += step; }	    // UP
            if (0 != (flagMove & (1 << 1))) { ymin -= step; ymax -= step; }	    // DOWN

            if (0 != (flagMove & (1 << 2))) { xmin += step; xmax += step; }	    // LEFT
            if (0 != (flagMove & (1 << 3))) { xmin -= step; xmax -= step; }	    // RIGHT

            if (0 != (flagMove & (1 << 4)))     // I
            {
                xmin = (xmin + xmax) / 2.0f - (xmax - xmin) / 2.1f;
                xmax = (xmin + xmax) / 2.0f + (xmax - xmin) / 2.1f;
                ymin = (ymin + ymax) / 2.0f - (ymax - ymin) / 2.1f;
                ymax = (ymin + ymax) / 2.0f + (ymax - ymin) / 2.1f;
            }	    
            if (0 != (flagMove & (1 << 5)))     // O
            {
                xmin = (xmin + xmax) / 2.0f - (xmax - xmin) / 1.9f;
                xmax = (xmin + xmax) / 2.0f + (xmax - xmin) / 1.9f;
                ymin = (ymin + ymax) / 2.0f - (ymax - ymin) / 1.9f;
                ymax = (ymin + ymax) / 2.0f + (ymax - ymin) / 1.9f;
            }
        }

    }
}