Проект draw1 с пустым окном

Введение в Visual C# 2010 Express:

0) Main Menu в VC# 2010 Express: Tools → Options → Show all Settings → Projects and Solutions → Visual Studio projects location: → C:\temp

1) Main Menu в VC# 2010 Express: File → New Project... →
Installed Templates: Windows Forms Application
Name: draw1 → OK

Появится Form1.cs[Design].

2) Стереть два лишних файла: Form1.Designer.cs и Program.cs.
Вы найдете эти файлы в окне Solution Explorer - элемент в дереве проекта draw1: нажать на стрелку или плюс для открытия ветки draw1 и после открыть ветку Form1.cs.
Кликнуть правой кнопкой на Program.cs. Откроется контекстное меню - кликнуть на Delete. Появится Message Box : 'Program.cs' will be deleted permanently. Кликнуть OK.
Также удалить и Form1.Designer.cs (не стирайте элемент Form1 полностью - он нужен).

3)Кликните правой кнопкой мыши на Form1. Откроется контекстное меню. Кликните на View Code.
Вы увидите код, созданный автоматически при создании проекта для окна Form1.cs. Сотрите этот код полностью.

4)Напишите в полностью очищенном окне следующие четыре строчки кода:

public class Form1 : System.Windows.Forms.Form

static void Main() { System.Windows.Forms.Application.Run( newForm1() ); }
}

5) Кликните Debug в MainMenu. Откроется подменю. Кликните на Start Without Debugging CtrlF5. Мини-программа автоматически скомпилируется и запустится. Обратите внимание на окно Error List в нижней части основного окна Visual Studio. Список ошибок должен быть пуст. Исправляйте ошибки, начиная сверху. После исправления первой, попробуйте снова скомпилировать код, так как часто одна ошибка синтаксиса создает несколько ошибок компиляции кода.

Наша программа стартует как самостоятельное окно, состоящее из трех частей:
1. MainFrame с голубым титульным полем (Caption);
2. три системные кнопки Minimize, Maximize, Close;
3. тонкая рамка с четырьмя подвижными сторонами и углами, изменяющими размеры окна при их передвижении мышью. Этот функционал полностью прописан в классе System.Windows.Forms.Form и доступен для использования в вашей первой C# программе.
Необходимо внести изменения в установки VisualStudio
1. В главном меню VisualC# 2010: Tools-> Options....
3. Появится окно Options. Переключитесь на опцию Projects and Solutions.
4. Кликните на General
5. Все три пути должны указывать на C:\temp .
6. Закройте окно кнопкой OK.
Запишите данные проекта: Main Menu в VS 2010: File → Save all и минимизируйте окно Visual Studio.
Запустите программу File Explorer. Перейдите в папку C:\temp\draw1\bin\Release или, если там ничего нет, в папку C:\temp\draw1\bin\Debug.
Для понимания того, что draw1.exe является отдельной программой запустите draw1.exe. Вы можете запустить параллельно множество инстанций draw1.exe. Минимизируйте FileExplorer.
Важно: Всегда закрывайте все запущенные инстанции приложения draw1 перед тем, как внести изменения в код и скомпилировать новую программу! Если есть сомнения все ли инстанции закрыты, запустите системную программу TaskManager, нажав комбинацию клавиш Ctrl+Alt+Del, и если в списке запущенных процессов найдется draw1.exe– удалите его.

Минимальная программа 

Если вы не видите код, - двойной клик по Form1.cs, передаст фокус окну с кодом.
Стирайте весь код и в пустом окне Form1.cs напишите следующий код:

using System;
using System.Drawing;
using System.Windows.Forms;

public class Form1 : Form
{
   [STAThread] static void Main() { Application.Run( new Form1() ); }
   Graphics g;

   Point p0, p1;
   Brush redbrush = new SolidBrush( Color.Red );
   Brush graybrush = SystemBrushes.Control;
   Brush blackbrush = SystemBrushes.ControlText;
   Pen blackpen = SystemPens.ControlText;
   Pen redpen = new Pen( Color.Red );
   Pen greenpen = new Pen( Color.Green );

   public Form1()
   { 
      Text = "Draw1: A Scribble Program";

      Width = 800;
      Height = 600;
      g = this.CreateGraphics();
   }

   protected override void OnMouseDown( MouseEventArgs e )
   {
      p0 = e.Location;
      Invalidate();
   }

   protected override void OnMouseMove( MouseEventArgs e )
   {
      if ( e.Button == MouseButtons.None ) return;
      p1 = e.Location;
      g.DrawLine( blackpen, p0, p1 );
      p0 = p1;
   }

   protected override void OnMouseUp( MouseEventArgs e )
   {
   }

   protected override void OnPaint( PaintEventArgs e )
   {
      g.DrawString( "Press the left mouse button and move!", Font, redbrush, 0, 0 );
   }
}

Кликните Debug в MainMenu. Откроется подменю. Кликните на Start Without Debugging CtrlF5. Мини-программа автоматически скомпилируется и запустится. Обратите внимание на окно Error List в нижней части основного окна Visual Studio.
Нарисуйте несколько произвольных фигур. Попробуйте поменять в коде параметр цвета в объекте Pen в функции события ...OnMouseMove(...) и с объекте Brush в функции ...OnPaint(...).

Совет: Если при наборе текста кода вы ошиблись, то при компиляции система выдаст сообщение в виде Message Box: There were build errors. Continue ?. Выбирайте No, иначе студия запустит предыдущую запускаемую версию, не соответствующую последним изменениям в коде.
В нижней части экрана вы увидите окно со списком ошибок и предупреждений (Варнингов). Проскролируйте этот список наверх чтобы увидеть самую первую ошибку , игнорируя Варнинги. Двойной клик на первую ошибку автоматически переведет текстовой курсор на строку, где была сделана ошибка. Найдите там ошибку ( иногда ошибка может быть не в указанной строке, а выше, если вы забыли там написать точку с запятой или скобку. Исправьте ошибку и игнорируя другие (так как часто последующие ошибки являются производными первой), снова запустите компиляцию кода. Повторяйте процесс пока приложение не запустится автоматически, без ошибок компиляции.

Отображение координат 

Версия 2: Закройте программу draw1.
Напишите в заголовке класса  public class Form1 : Form под строкой Pen greenpen = new Pen(Color.Green); следующее определение переменной:

  String myline;

в трех следующих строках в функции protected override void OnMouseMove(MouseEventArgs e) прямо под строкой p0 = p1;, но перед фигурной скобкой, закрывающей метод OnMouseMove:

    g.DrawString( myline, Font, graybrush , 0, Font.Height );
    myline = String.Format( "{0}, {1}", p1.X, p1.Y );
    g.DrawString( myline, Font, blackbrush, 0, Font.Height );

Кликните на Start Without Debugging CtrlF5.

Отображение Вертексов 

Вертексы (англ. Vertices) множественное число от слова Vertex = Вершина угла - в Компьютерной Графике этот термин означает вершину Полигона.

 Версия3: Закройте программу draw1.
Допишите строку кода в функцию protected override void OnMouseMove(MouseEventArgs e) :

    g.DrawRectangle( blackpen, p1.X-3, p1.Y-3, 7, 7 );

Кликните на Start Without Debugging CtrlF5.

Порисуйте быстро и медленно - обратите внимание, как плотность Вертексов зависит от скорости движения мыши.
Более медленные компьютеры производят меньшее количество Вертексов, чем более быстрые, так как Операционная Система обрабатывает меньшее количество событий WM_MouseMove, которые она передает в class Form1, который соответственно реже вызывает функцию protected override void OnMouseMove(MouseEventArgs e)Программа не может производить константное количество Вертексов, так как это количество зависит от скорости мыши и компьютера пользователя.

Минимальное растояние между Вертексами

Версия 4: Закройте программу draw1.
Допишите следующие строчки кода в функции protected override void OnMouseMove(MouseEventArgs e) прямо под строкой: p1 = e.Location;

    Int32 dx = p1.X - p0.X;
    Int32 dy = p1.Y - p0.Y;
    if ( dx*dx + dy*dy < 100 ) return;

Кликните на Start Without Debugging CtrlF5.

Мы используем теорему Пифагора для прямоугольных треугольников: Сумма квадратов катетов равна квадрату гипотенузы. В данном случае мы игнорируем новые вершины (Вертексы), если Гипотенуза меньше допустимого минимума в 10 пикселей. Порисуйте с разной скоростью и понаблюдайте за плотностью Вертексов. Попробуйте поменять значение 100 на  0, 4, 16, 64, 400, 900, 1600 и так далее.

Vertex-Array

Версия 5: нарисованный Полигон теряется при перерисовке или при наложении других окон, кроме того Полигон остается открытым. Этот недостаток будет исправлен следующим образом: 1) Вертексы будут сохраняться в массиве фиксированной длины, и при каждом обновлении окна автоматически перерисованы; 2) последний Вертекс будет совмещен с первым.
Закройте программу draw1.
Допишите в заголовок класса  public class Form1 : Form под строчкой Graphics g;:

  Int16 i, n;
  const Int16 nMax = 100;
  Point[] polygon = new Point[nMax];

Поменяйте функцию protected override void OnMouseDown(MouseEventArgs e), чтобы она выглядела так:

  protected override void OnMouseDown( MouseEventArgs e )
  { 
    polygon[0] = p0 = e.Location;
    n = 1;
    Invalidate();
  }

Измените функцию protected override void OnMouseMove(MouseEventArgs e), чтобы она была такой:

  protected override void OnMouseMove( MouseEventArgs e )
  { 
    if ( e.Button == MouseButtons.None ) return;
    p1 = e.Location;
    Int32 dx = p1.X - p0.X;
    Int32 dy = p1.Y - p0.Y;
    if ( dx*dx + dy*dy < 100 ) return;
    if ( n >= nMax-1 ) return;
    g.DrawLine( blackpen, p0, p1 );
    polygon[n++] = p0 = p1;
    g.DrawString( myline, Font, graybrush , 0, Font.Height );
    myline = String.Format( "{0}, {1}", p1.X, p1.Y );
    g.DrawString( myline, Font, blackbrush, 0, Font.Height );
    g.DrawRectangle( blackpen, p1.X-3, p1.Y-3, 7, 7 );
  }

Измените функцию protected override void OnMouseUp(MouseEventArgs e) так :

  protected override void OnMouseUp( MouseEventArgs e )
  { 
    if ( n < 2 ) return;
    polygon[n++] = polygon[0];
    Invalidate();
  }

Измените функцию protected override void OnPaint( PaintEventArgs e ), чтобы получилось так:

  protected override void OnPaint( PaintEventArgs e )
  { g.DrawString( "Press the left mouse button and move!", Font, redbrush, 0, 0 );
    for ( int i=0; i < n-1; i++ ) g.DrawLine( blackpen, polygon[i], polygon[i+1] );
  }

Кликните на Start Without Debugging CtrlF5.

Испытайте программу следующим образом: 1.) подвигайте границу окна: Form1 максимально уменьшить и снова увеличить; 2.) перекройте Form1 каким -нибудь другим окном (приложением).
Укоротите или увеличьте массив, изменяя nMax на 10 и на 200 - посмотрите на что это влияет. 

Замечание: Использование массива фиксированной длины (Point[] polygon = new Point[nMax];)не оптимально, так как длинна определяется заранее и как правило либо слишком коротка, либо слишком длина. Лучше и правильнее, но медленнее с точки зрения системы - это динамический массив ArrayList polygon = new ArrayList(); - см  3. Miniprogramm for Training в конце страницы. С помощью методов Add, Insert и Clear можно произвольно увеличивать или уменьшать массивы данных.

Периметр, Площадь, Центр Тяжести, Описанный Прямоугольник

Версия 6: Закройте программу draw1.
Допишите декларацию следующих переменных в заголовке класса public class Form1 : Form
под строкой Point p1 = new Point();:

  Point mid_of_p, mid_of_r;
  Rectangle minmax;
  Double perimeter, area;

Измените функцию protected override void OnMouseUp(MouseEventArgs e), чтобы было так:

  protected override void OnMouseUp( MouseEventArgs e )
  { 
    if ( n < 2 ) return;
    p0 = polygon[n++] = polygon[0];
    perimeter = area = 0;
    mid_of_p.X = mid_of_p.Y = 0;
    Int32 xmin, xmax, ymin, ymax;
    xmin = xmax = p0.X;
    ymin = ymax = p0.Y;
    for ( i=1; i < n; i++ )
    { p1 = polygon[i];
      Double dx = p1.X - p0.X;
      Double dy = p1.Y - p0.Y;
      Double my = (p0.Y + p1.Y) / 2.0;
      perimeter  += Math.Sqrt( dx*dx + dy*dy );
      area       += dx * my;
      mid_of_p.X += p1.X;
      mid_of_p.Y += p1.Y;
      if ( p1.X < xmin ) xmin = p1.X;
      if ( p1.X > xmax ) xmax = p1.X;
      if ( p1.Y < ymin ) ymin = p1.Y;
      if ( p1.Y > ymax ) ymax = p1.Y;
      p0 = p1;
    }
    mid_of_r.X = ( xmax + xmin ) / 2;
    mid_of_r.Y = ( ymax + ymin ) / 2;
    mid_of_p.X /= n-1;
    mid_of_p.Y /= n-1;
    minmax.X = xmin-1; minmax.Width  = xmax - xmin + 2;
    minmax.Y = ymin-1; minmax.Height = ymax - ymin + 2;
    Invalidate();
  }

Измените функцию protected override void OnPaint( PaintEventArgs e ), так:

  protected override void OnPaint( PaintEventArgs e )
  { 
    g.DrawString( "Press the left mouse button and move!", Font, redbrush, 0, 0 );
    if ( n < 2 ) return;
    myline = String.Format( "Perimeter= {0}, Area= {1}", (Int32)perimeter, (Int32)area );
    g.DrawString( myline, Font, blackbrush, 0, 2*Font.Height );
    for ( i=0; i < n-1; i++ ) g.DrawLine( blackpen, polygon[i], polygon[i+1] );
    for ( i=0; i < n-3; i+=3 )
      g.DrawBezier( redpen, polygon[i], polygon[i+1], polygon[i+2], polygon[i+3] );
    g.DrawRectangle( greenpen, minmax );
    g.DrawLine( greenpen, mid_of_r.X - 4, mid_of_r.Y    , mid_of_r.X + 4, mid_of_r.Y     );
    g.DrawLine( greenpen, mid_of_r.X    , mid_of_r.Y - 4, mid_of_r.X    , mid_of_r.Y + 4 );
    g.FillEllipse( blackbrush, mid_of_p.X-5, mid_of_p.Y-5, 11, 11 );
  }

Кликните на Start Without Debugging CtrlF5.

Опробуйте программу и отследите зависимости между изменениями в коде OnMouseUp / OnPaint и тем, что вы видите в результате. Обратите внимание что знак перед значением Area меняется в зависимости от направления прорисовки. 

Дополнительные задания

Кликните в главном меню Visual Studio Help -> View Help. Кликните папку Index и вбейте в поле фильтров .NET Framework. Затем перейдите в поле поиска и наберите последовательно ключевые слова: Rectangle, Point, Array, MouseEventArgs, PaintEventArgs, Math . Вы получите статьи, поясняющие назначение, синтаксис и примеры использования соответствующих объектов и методов. Прочтите описание всех использованных в этой работе методов. 
Закройте  Visual Studio, запустите Explorer, сотрите полностью директорию C:\temp\draw1.
Снова запустите Visual Studio и создайте туже программу еще раз и повторяйте процесс, пока не сможете создать аналогичную программу с нуля без описания.
Попробуйте раз личные варианты программы (под разными названиями  draw2, draw3 и т.д.), базе приведенных примеров.

Мини-программы для тренировки

1. MiniDraw без записи и перерисовки:

using System;
using System.Drawing;
using System.Windows.Forms;
public class Form1 : Form
{
   [STAThread] static void Main() { Application.Run( new Form1() ); }
   Graphics g;
   Point p0, p1;
   Pen redpen = new Pen( Color.Red, 5 );
   protected override void OnMouseDown( MouseEventArgs e )
   {
     g = this.CreateGraphics();
     p0 = e.Location;
   }
   protected override void OnMouseMove( MouseEventArgs e )
   {
     if ( e.Button == MouseButtons.None ) return;
     p1 = e.Location;
     g.DrawLine( redpen , p0, p1 );
     g.DrawLine( SystemPens.ControlText, p0, p1 );
     p0 = p1;
   }
}

2. MiniDrawArray со статическим массивом и перерисовкой:

using System;
using System.Drawing;
using System.Windows.Forms;

public class Form1 : Form
{
  [STAThread] static void Main() { Application.Run( new Form1() ); }
  Graphics g;
  const Int16 N = 100;
  Point[] p = new Point[N];
  Int16 n;

  protected override void OnMouseDown( MouseEventArgs e )
  {
    g = this.CreateGraphics();
    p[0] = e.Location;
    n = 1;
    Invalidate();
  }

  protected override void OnMouseMove( MouseEventArgs e )
  {
    if ( e.Button == MouseButtons.None ) return;
    if ( n >= N ) return;
    p[n] = e.Location;
    g.DrawLine( SystemPens.ControlText, p[n-1], p[n] );
    n++;
  }

  protected override void OnPaint( PaintEventArgs e )
  {
    for ( Int16 i = 1; i < n; i++ )
    g.DrawLine( SystemPens.ControlText, p[i-1], p[i] );
  } 
}

3. MiniDrawDynArray с динамическим массивом

using System.Windows.Forms;
using System.Collections;

public class Form1 : Form
{
  [STAThread] static void Main() { Application.Run( new Form1() ); }
  Graphics g;
  Point p0;
  ArrayList p = new ArrayList();
 
  protected override void OnMouseDown( MouseEventArgs e )
  {
    g = this.CreateGraphics();
    p0 = e.Location;
    p.Clear(); p.Add( p0 );
    Invalidate();
  }
 
  protected override void OnMouseMove( MouseEventArgs e )
  {
    if ( e.Button == MouseButtons.None ) return;
    p0 = e.Location;
    g.DrawLine( SystemPens.ControlText, (Point)p[p.Count-1], p0 );
    p.Add( p0 );
    g.FillRectangle( SystemBrushes.Control, 0, 0, 200, 15 );
    String s = "length = " + p.Count.ToString();
    g.DrawString( s, new Font( "Arial", 12 ), SystemBrushes.ControlText, 0, 0 );
  }

  protected override void OnPaint( PaintEventArgs e )
  {
    for ( Int16 i = 1; i < p.Count; i++ )
    g.DrawLine( SystemPens.ControlText, (Point)p[i-1], (Point)p[i] );
  }
}

Удачи! :)