Опубликован: 25.03.2010 | Уровень: для всех | Доступ: платный
Лекция 12:

Классы Application и Form

Наследование форм

До сих пор мы делали все неправильно, потому, что создавали в своем классе композицию объектов Form. Поэтому мы имели возможность использовать только общедоступные ( public ) методы и свойства этого класса. Но класс Form имеет подавляющее большинство свойств и методов, доступных для наследников ( protected ). Поэтому более правильным будет подход создания нашего класса как наследника класса Form с последующим расширением его функциональности. Следует помнить, что C# поддерживает только одиночное наследование.

  • Переименуйте в панели Solution Explorer файл FirstClass в DerivedClass
  • То же самое сделайте в коде этого файла ( либо через панель Properties, предварительно выделив через Object Browser или через Class View ), переименовав имя класса в DerivedClass
  • Объявите класс DerivedClass наследующим базовому классу Form
public class DerivedClass : Form
  • Внесите изменения, чтобы класс выглядел так
using System;
using System.Windows.Forms;
using System.Drawing;
  
namespace FirstProject
{
  public class DerivedClass : Form
  {
  static void Main()
  {
  DerivedClass frm = new DerivedClass();
  frm.Text = "Наш класс - наследник от Form";
  frm.BackColor = Color.Red;
  
  Application.Run(frm);
  }
  }
}
Листинг 12.22 . Наш класс наследует от класса Form

При создании экземпляра нашего класса в функции Main() мы использовали синтаксис вызова конструктора по умолчанию. Круглые скобки в этом случае всегда обязательны при создании экземпляра класса. Но если бы мы определили в своем классе хотя бы один конструктор, то система по умолчанию нам его уже не предоставит и нужно объявлять свой конструктор по умолчанию, пусть даже с пустым телом.

using System;
using System.Windows.Forms;
using System.Drawing;
  
namespace FirstProject
{
  public class DerivedClass : Form
  {
  int width = 600, height = 300;
  
  // Общий конструктор
  public DerivedClass(int width, int height)
  {
  Width = width;
  Height = height;
  Text = "Общий конструктор";
  BackColor = Color.Red;
  }
  
  // Конструктор по умолчанию
  public DerivedClass()
  {
  Width = width;
  Height = height;
  Text = "Конструктор по умолчанию";
  BackColor = Color.Blue;
  }
  
  static void Main()
  {
  DerivedClass frm = new DerivedClass(300, 600);
  Application.Run(frm);
  }
  }
}
Листинг 12.23 . Несколько перегружаемых конструкторов

Вынесение точки входа в отдельный класс

Разгрузим функцию Main от лишнего кода, да и вынесем ее в другой класс (свой единоличный), чтобы не засорять пользовательский класс несвойственным ему кодом. Функция Main должна обязательно принадлежать какому-нибудь классу, поскольку глобальные функции в C# запрещены.

using System;
using System.Windows.Forms;
using System.Drawing;
  
namespace FirstProject
{
  public class DerivedClass : Form
  {
  public DerivedClass()// Конструктор
  {
  // Прямое обращение к свойствам класса Form
  Text = "Наследник от Form";
  BackColor = Color.Red;
  StartPosition = FormStartPosition.CenterScreen;
  this.Height /= 2; // this - удобно для  IntelliSense
  }
  }
  
  class EntryPoint
  {
  static void Main()
  {
  // Создание экземпляра и передача 
  // его в главный цикл сообщений
  // Так все и делают !!!
  Application.Run(new DerivedClass());
  }
  }
}
Листинг 12.24 . Вынесение точки входа в отдельный класс

Устранение неопределенности при нескольких точках входа

В программе функция Main может размещаться в нескольких класса. В этом случае разработчик должен определить стартовый класс.

using System;
using System.Windows.Forms;
using System.Drawing;
  
namespace FirstProject
{
  public class DerivedClass : Form
  {
  int width = 600, height = 300;
  
  // Общий конструктор
  public DerivedClass(int width, int height)
  {
  Width = width;
  Height = height;
  Text = "Общий конструктор";
  BackColor = Color.Red;
  }
  
  // Конструктор по умолчанию
  public DerivedClass()
  {
  Width = width;
  Height = height;
  Text = "Конструктор по умолчанию";
  BackColor = Color.Blue;
  }
  
  static void Main()
  {
  // Создание экземпляра и передача 
  // его в главный цикл сообщений
  // Так все и делают !!!
  Application.Run(new DerivedClass(300, 600));
  }
  }
  
  class EntryPoint
  {
  static void Main()
  {
  // Создание экземпляра и передача 
  // его в главный цикл сообщений
  // Так все и делают !!!
  Application.Run(new DerivedClass());
  }
  }
}
Листинг 12.25 . Две точки входа в одном приложении

При запуске приложения будет ошибка о неопределенной точке входа. Теперь нужно определить, какой из классов, содержащих точки входа, будет стартовым в приложении.

  • Выполните команду главного меню оболочки Project/Properties и установите в открывшемся окне вкладки Common Properties/General параметр Startup Object в значение класса с нужной точкой входа.

Отключение консольного окна

Операционная система при запуске нашего приложения параллельно создает и консольное окно, поскольку имеет установку на то, что тип приложения является консольным. Отменим эту установку для компилятора.

  • Выполните команду главного меню оболочки Project/Properties
  • Установите параметр Output Type компилятора в значение Windows Application. Примените установку и закройте окно.

  • Запустите приложение и убедитесь, что консольное окно больше не появляется.
  • Верните таким же способом режим компилятора в значение Console Application, поскольку для испытаний средств языка C# такой режим нам еще нужен.

Переопределение стандартного обработчика, наследуемого из базового класса формы

Теперь, вместо того, чтобы самому регистрировать событие Paint и конструировать его обработчик, мы воспользуемся унаследованным от класса System.Windows.Forms.Control обработчиком OnPaint(),который вызывается формой автоматически при разрушении ее вида. Мы хотим контролировать этот обработчик своим кодом. В базовом классе этот обработчик объявлен виртуальным ( virtual ), поэтому его нужно переопределить в наследнике с ключевым словом override.

using System;
using System.Windows.Forms;
using System.Drawing;
  
namespace FirstProject
{
  public class DerivedClass : Form
  {
  public DerivedClass()// Конструктор
  {
  // Прямое обращение к свойствам класса Form
  Text = "Переопределение наследуемого "
       + "обработчика OnPaint";
  BackColor = Color.Blue;// Синий фон
  StartPosition = FormStartPosition.CenterScreen;
  // this - удобнее для вызова IntelliSense
  this.Height /= 2; 
  this.Width *= 2;
  }
  
  // Замещающий метод обработки события Paint
  // Переопределение наследуемого обработчика OnPaint()
  protected override void OnPaint(PaintEventArgs e) // Набрать вручную !!!
  {
  System.Drawing.Graphics gr = e.Graphics;
  System.String str = "Привет из замещенного "
       + "обработчика OnPaint";
  System.Int32 x = 0, y = 0; // то же, что int - псевдоним
    gr.DrawString(str, Font, // Применить как у владельца (формы)
    Brushes.White, // Белый текст
    x, y); // Привязка текста к клиентской области
  Console.WriteLine("Сработал замещенный "
          + "обработчик OnPaint");
  
  // Обработчик базового класса
  base.OnPaint (e);
  }
  }
  
  class EntryPoint
  {
  static void Main()
  {
  // Создание экземпляра и передача 
  // его в главный цикл сообщений
  // Так все и делают !!!
  Application.Run(new DerivedClass());
  }
  }
}
Листинг 12.26 . Переопределение наследуемого обработчика OnPaint()
Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?

Денис Пашков
Денис Пашков
Россия
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974