System windows forms что это

This article needs to be updated. Please help update this article to reflect recent events or newly available information. (January 2023)

Windows Forms, also known as WinForms, is a free, open-source graphical user interface (GUI) class library for building Windows desktop applications, included as a part of Microsoft .NET, .NET Framework or Mono,[2] providing a platform to write client applications for desktop, laptop, and tablet PCs.[3] While it is seen as a replacement for the earlier and more complex C++ based Microsoft Foundation Class Library, it does not offer a comparable paradigm[4] and only acts as a platform for the user interface tier in a multi-tier solution.[5]

Windows Forms (WinForms)

Other names WinForms
Original author(s) .NET: Microsoft,
Mono: Ximian/Novell
Developer(s) .NET Foundation
Initial release February 13, 2002; 23 years ago
Stable release

v8.0.0
/ November 14, 2023; 17 months ago[1]

Repository
  • github.com/dotnet/winforms
Written in C#
Operating system Microsoft Windows
Platform .NET Framework, .NET, Mono
Type Software framework, widget toolkit
License MIT License
Website learn.microsoft.com/en-us/dotnet/desktop/winforms/

At the Microsoft Connect event on December 4, 2018, Microsoft announced releasing Windows Forms as an open source project on GitHub. It is released under the MIT License. With this release, Windows Forms has become available for projects targeting the .NET Core framework. However, the framework is still available only on the Windows platform, and Mono’s incomplete implementation of Windows Forms remains the only cross-platform implementation.[6][7]

 
This API is a part of .NET Framework 3.0

A Windows Forms application is an event-driven application supported by Microsoft’s .NET Framework. Unlike a batch program, it spends most of its time simply waiting for the user to do something, such as fill in a text box or click a button. The code for the application can be written in a .NET programming language such as C# or Visual Basic.

Windows Forms provides access to native Windows User Interface Common Controls by wrapping the existent Windows API in managed code.[8] With the help of Windows Forms, the .NET Framework provides a more comprehensive abstraction above the Win32 API than Visual Basic or MFC did.[9]

Windows Forms is similar to Microsoft Foundation Class (MFC) library in developing client applications. It provides a wrapper consisting of a set of C++ classes for development of Windows applications. However, it does not provide a default application framework like the MFC. Every control in a Windows Forms application is a concrete instance of a class.

All visual elements in the Windows Forms class library derive from the Control class. This provides the minimal functionality of a user interface element such as location, size, color, font, text, as well as common events like click and drag/drop. The Control class also has docking support to let a control rearrange its position under its parent. The Microsoft Active Accessibility support in the Control class also helps impaired users to use Windows Forms better.[10]

In Visual Studio, forms are created using drag-and-drop techniques. A tool is used to place controls (e.g., text boxes, buttons, etc.) on the form (window). Controls have attributes and event handlers associated with them. Default values are provided when the control is created, but may be changed by the programmer. Many attribute values can be modified during run time based on user actions or changes in the environment, providing a dynamic application. For example, code can be inserted into the form resize event handler to reposition a control so that it remains centered on the form, expands to fill up the form, etc. By inserting code into the event handler for a keypress in a text box, the program can automatically translate the case of the text being entered, or even prevent certain characters from being inserted.

Besides providing access to native Windows controls like button, textbox, checkbox and listview, Windows Forms added its own controls for ActiveX hosting, layout arrangement, validation and rich data binding. Those controls are rendered using GDI+.[10]

Just like Abstract Window Toolkit (AWT), the equivalent Java API, Windows Forms was an early and easy way to provide graphical user interface components to the .NET Framework. Windows Forms is built on the existing Windows API and some controls merely wrap underlying Windows components.[11] Some of the methods allow direct access to Win32 callbacks, which are not available in non-Windows platforms.[11]

In .NET Framework 2.0, Windows Forms gained richer layout controls, Office 2003 style toolstrip controls, multithreading component, richer design-time and data binding support as well as ClickOnce for web-based deployment.[12][13]

With the release of .NET Framework 3.0, Microsoft released a second, parallel API for rendering GUIs: Windows Presentation Foundation (WPF) based on DirectX,[14] together with a GUI declarative language called XAML.[15]

During a question-and-answer session at the Build 2014 Conference, Microsoft explained that Windows Forms was under maintenance mode, with no new features being added, but bugs found would still be fixed.[16] Most recently, improved high-DPI support for various Windows Forms controls was introduced in updates to .NET Framework version 4.5.[17]

XAML backwards compatibility with Windows Forms


edit

For future development, Microsoft has succeeded Windows Forms with a XAML-based GUI entry using frameworks such as WPF and UWP. However, drag and drop placement of GUI components in a manner similar to Windows Forms is still provided in XAML by replacing the root XAML element of the Page/Window with a «Canvas» UI-Control. When making this change, the user can build a window in a similar fashion as in Windows Forms by directly dragging and dropping components using the Visual Studio GUI.

While XAML provides drag and drop placement backwards compatibility through the Canvas Control, XAML Controls are only similar to Windows Forms Controls and are not one-to-one backwards compatible. They perform similar functions and have a similar appearance, but the properties and methods are different enough to require remapping from one API to another.

Alternative implementation


edit

Mono is a project led by Xamarin (formerly by Ximian, then Novell) to create an Ecma standard compliant .NET Framework compatible set of tools.

In 2011, Mono’s support for System.Windows.Forms as of .NET 2.0 was announced as complete;[18]
System.Windows.Forms 2.0 works natively on Mac OS X.[19]
However, System.Windows.Forms has not been actively developed on Mono.[20]
Full compatibility with .NET was not possible, because Microsoft’s System.Windows Forms is mainly a wrapper around the Windows API, and some of the methods allow direct access to Win32 callbacks, which are not available in platforms other than Windows.[11]
A more significant problem is that, since version 5.2,[21]
Mono has been upgraded so that its default is to assume a 64 bit platform.
However, System.Windows.Forms on Mono for the Macintosh OS X platform has been built using a 32 bit subsystem, Carbon.[22]
As of this date[when?], a 64-bit version of System.Windows.Forms for use on Mac OS X remains unavailable and only .NET applications built for the 32 bit platform can be expected to execute.

  • Microsoft Visual Studio
  • ClickOnce
  • Abstract Window Toolkit (AWT), the equivalent GUI application programming interface (API) for the Java programming language
  • Visual Component Library (VCL) from Borland
  • Visual Test, test automation
  1. ^ «v8.0.0». github.com. 2023-11-14. Retrieved 2023-11-21.
  2. ^ Sells, Chris (September 6, 2003). Windows Forms Programming in C# (1st ed.). Addison-Wesley Professional. p. xxxviiii.
  3. ^ «Design and Implementation Guidelines for Web Clients by Microsoft Pattern and Practices». Microsoft. November 2003.
  4. ^ Sells, Chris; Weinhardt, Michael (May 16, 2006). «Appendix B». Moving from MFC, Windows Forms 2.0 Programming (2nd ed.). Addison-Wesley Professional.
  5. ^ «Introduction to Windows Forms» (Visual Studio 2003 documentation). Microsoft 2003.
  6. ^ Martin, Jeff (4 December 2018). «Microsoft Open Sources WPF, WinForms, and WinUI». InfoQ. Retrieved 2018-12-06.
  7. ^ Hanselman, Scott (4 December 2018). «Announcing WPF, WinForms, and WinUI are going Open Source». Retrieved 2018-12-06.
  8. ^ De Smet, Bart (January 4, 2011). «Chapter 5». C# 4.0 Unleashed. Sams Publishing.
  9. ^ Griffiths, Ian; Adams, Matthew (March 2003). NET Windows Forms in a Nutshell. O’Reilly Media. p. 4.
  10. ^ a b Griffiths, Ian; Adams, Matthew (March 2003). NET Windows Forms in a Nutshell. O’Reilly Media. pp. 27–53.
  11. ^ a b c «FAQ: Winforms». mono-project.com. It is very unlikely that the implementation will ever implement everything needed for full compatibility with Windows.Forms. The reason is that Windows.Forms is not a complete toolkit, and to work around this problem some of the underlying Win32 foundation is exposed to the programmer in the form of exposing the Windows message handler
  12. ^ Sells, Chris; Weinhardt, Michael (May 16, 2006). «Appendix A. What s New in Windows Forms 2.0». Windows Forms 2.0 Programming (2nd ed.). Addison-Wesley Professional.
  13. ^ Noyes, Brian (January 12, 2006). «Preface». Data Binding with Windows Forms 2.0: Programming Smart Client Data Applications with .NET (1st ed.). Addison-Wesley Professional. ISBN 978-81-317-4823-7.
  14. ^ Hall, Gary (December 27, 2010). «DirectX, not GDI+». Pro WPF and Silverlight MVVM: Effective Application Development with Model (2010 ed.). Apress. p. 2.
  15. ^ Smith, Josh (2007-09-05). «WPF vs. Windows Forms». Josh Smith on WPF. Retrieved 2011-08-25. WPF is not intended to replace Windows Forms. […] Windows Forms is still alive and well, and will continue to be enhanced and supported by Microsoft for years to come. WPF is simply another tool for Windows desktop application developers to use, when appropriate.
  16. ^ «A WPF Q&A». infoq.com. 2014-04-03. Retrieved 2014-04-21. Windows Forms is continuing to be supported, but in maintenance mode. They will fix bugs as they are discovered, but new functionality is off the table
  17. ^ Allen, Jonathan (2014-05-06). «High DPI Improvements for Windows Forms in .NET 4.5.2». InfoQ. Retrieved 2015-02-10.
  18. ^ «WinForms». mono-project.com. Retrieved 2011-07-30. Support for Windows Forms 2.0 is complete. At this point, we are largely just fixing bugs and polishing our code.
  19. ^ «WinForms». mono-project.com. Retrieved 2011-07-30. Does Winforms run on OSX? Yes, as of Mono 1.9, Winforms has a native OSX driver that it uses by default
  20. ^ de Icaza, Miguel (2011-03-07). «GDC 2011». Retrieved 2011-07-30. For tools that are mostly OpenGL/DirectX based, use Windows.Forms, keeping in mind that some bug fixing or work around on their part might be needed as our Windows.Forms is not actively developed.
  21. ^ «Introduction to Mono on macOS». mono-project.com. Retrieved 2019-11-12.
  22. ^ Martin, Jess. «Windows.Forms Comes to 64-bit Mac OS X». Retrieved 2019-11-12.
  • MSDN: Building Windows Forms applications
  • MSDN : Windows.Forms reference documentation
  • MSDN : Windows Forms Technical Articles — Automating Windows Form with Visual Test

From Wikibooks, open books for an open world

To create a Windows desktop application we use the library represented by System.Windows.Forms namespace. Some commonly used classes in this namespace include:

  • Control — generic class from which other useful classes, like Form, TextBox and others listed below are derived
  • Form — this is the base class for the program window. All other controls are placed directly onto a Form or indirectly on another container (like TabPage or TabControl) that ultimately resides on the Form. When automatically created in Visual Studio, it is usually subclassed as Form1.
  • Button — a clickable button
  • TextBox — a singleline or multiline textbox that can be used for displaying or inputting text
  • RichTextBox — an extended TextBox that can display styled text, e.g. with parts of the text colored or with a specified font. RichTextBox can also display generalized RTF document, including embedded images.
  • Label — simple control allowing display of a single line of unstyled text, often used for various captions and titles
  • ListBox — control displaying multiple items (lines of text) with ability to select an item and to scroll through it
  • ComboBox — similar to ListBox, but resembling a dropdown menu
  • TabControl and TabPage — used to group controls in a tabbed interface (much like tabbed interface in Visual Studio or Mozilla Firefox). A TabControl contains a collection of TabPage objects.
  • DataGrid — data grid/table view

The Form class (System.Windows.Forms.Form) is a particularly important part of that namespace because the form is the key graphical building block of Windows applications. It provides the visual frame that holds buttons, menus, icons, and title bars together. Integrated development environments (IDEs) like Visual C# and SharpDevelop can help create graphical applications, but it is important to know how to do so manually:

using System.Windows.Forms;

public class ExampleForm : Form    // inherits from System.Windows.Forms.Form
{
    public static void Main()
    {
        ExampleForm wikibooksForm = new ExampleForm();

        wikibooksForm.Text = "I Love Wikibooks";  // specify title of the form
        wikibooksForm.Width = 400;                // width of the window in pixels
        wikibooksForm.Height = 300;               // height in pixels
        Application.Run(wikibooksForm);           // display the form
    }
}

The example above creates a simple Window with the text «I Love Wikibooks» in the title bar. Custom form classes like the example above inherit from the System.Windows.Forms.Form class. Setting any of the properties Text, Width, and Height is optional. Your program will compile and run successfully, if you comment these lines out, but they allow us to add extra control to our form.

This section is a stub.
You can help Wikibooks by expanding it.

An event is an action being taken by the program when a user or the computer makes an action (for example, a button is clicked, a mouse rolls over an image, etc.). An event handler is an object that determines what action should be taken when an event is triggered.

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

public class ExampleForm : Form    // inherits from System.Windows.Forms.Form
{
    public ExampleForm()
    {
        this.Text = "I Love Wikibooks";           // specify title of the form
        this.Width = 300;                         // width of the window in pixels
        this.Height = 300;                        // height in pixels

        Button HelloButton = new Button();
        HelloButton.Location = new Point(20, 20); // the location of button in pixels
        HelloButton.Size = new Size(100, 30);     // the size of button in pixels
        HelloButton.Text = "Click me!";           // the text of button

        // When clicking the button, this event fires
        HelloButton.Click += new System.EventHandler(WhenHelloButtonClick);

        this.Controls.Add(HelloButton);
    }

    void WhenHelloButtonClick(object sender, System.EventArgs e)
    {
        MessageBox.Show("You clicked! Press OK to exit this message");
    }

    public static void Main()
    {
        Application.Run(new ExampleForm());       // display the form
    }
}

This section is a stub.
You can help Wikibooks by expanding it.

The Windows Forms namespace has a lot of very interesting classes. One of the simplest and important is the Form class. A form is the key building block of any Windows application. It provides the visual frame that holds buttons, menus, icons and title bars together. Forms can be modal and modalless, owners and owned, parents and children. While forms could be created with a notepad, using a form editor like VS.NET, C# Builder or Sharp Develop makes development much faster. In this lesson, we will not be using an IDE. Instead, save the code below into a text file and compile with command line compiler.

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

public class ExampleForm : Form    // inherits from System.Windows.Forms.Form
{
    public ExampleForm()
    {
        this.Text = "I Love Wikibooks";         // specify title of the form
        this.BackColor = Color.White;
        this.Width = 300;                       // width of the window in pixels
        this.Height = 300;                      // height in pixels

        // A Label
        Label TextLabel = new Label();
        TextLabel.Text = "One Label here!";
        TextLabel.Location = new Point(20, 20);
        TextLabel.Size = new Size(150, 30);
        TextLabel.Font = new Font("Arial", 12); // See! we can modify the font of text
        this.Controls.Add(TextLabel);           // adding the control to the form

        // A input text field
        TextBox Box = new TextBox();            // inherits from Control
        Box.Location = new Point(20, 60);       // then, it have Size and Location properties
        Box.Size = new Size(100, 30);
        this.Controls.Add(Box);                 // all class that inherit from Control can be added in a form
    }

    public static void Main()
    {
        Application.EnableVisualStyles();
        Application.Run(new ExampleForm());     // display the form
    }
}

Это бесплатная глава книги Библия C#. В новом издании эта глава переписана с учетом универсальных при-ложений Windows, а старая версия главы, которая не потеряла еще своей актуаль-ности стала бесплатной и доступной всем.

Начнем с создания пустого приложения и посмотрим, что для нас сгенерирует
мастер Visual Studio, чтобы на экране появилось окно программы, и из чего все это состоит. Для создания проекта выполняем команду меню File | New | Project и в открывшемся окне выбираем Windows Forms Application в разделе языка программирования Visual C# | Windows (рис. 5.1). Я назвал свое новое приложение OurFirstVisualApplication.

Давайте посмотрим, какие модули добавлены в решение. Их всего два: Form1.cs (этот модуль состоит из нескольких файлов) и Program.cs. Начнем со второго файла, потому что именно с него начинается выполнение программы, и там находится
метод Main(). Код файла вы можете увидеть в листинге 5.1.

Листинге 5.1. Содержимое файла Program.cs

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

namespace OurFirstVisualApplication
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Создание нового проекта в Visual Studio

Рис. 5.1. Окно создания нового проекта (выделен пункт для создания визуального приложения)

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

Файл Program.cs нужен только в качестве заглушки, в которой объявлен класс с методом Main(). Он не несет в себе никакой логики, кроме создания приложения
и отображения главного окна программы. Чаще всего в этот файл вы заглядывать не будете, но знать о его существовании желательно.

5.1.1. Пространства имен

В самом начале файл Program.cs подключает три пространства имен, с которыми будет происходить работа. На самом деле для компиляции программы достаточно только двух пространств: первого и третьего. Второе пространство не нужно, и в данном коде не используется, поэтому мы не будем его пока рассматривать. Это пространство имен относится к коллекциям, а это тема отдельного и очень серьезного разговора главы 8.

Из необходимых остаются два пространства имен:

  • System — мы подключали это пространство имен для всех приложений, которые писали до сих пор, — точнее, мастер подключал его вместо нас. В этом пространстве в .NET объявлены основные типы данных и все, без чего не проживет ни одно приложение .NET, которое хоть что-то делает;
  • System.Windows.Forms — в этом пространстве имен расположено все, что необходимо для функционирования формы. Формами в .NET называют проект будущего окна. Если класс — это спецификация, по которой создается объект, то форма — это спецификация, по которой создается окно. Мы планируем работать с визуальным интерфейсом, поэтому это пространство имен просто необходимо.

Как узнать, какие пространства имен подключать, а какие не нужно? Тут может помочь файл помощи и MSDN, где при описании каждого класса, метода или свойства обязательно указывается, в каком пространстве имен его можно найти. Откройте файл помощи — командой меню Help | Index (Помощь | Индекс) — и введите в строку поиска Look for (Искать) в левой панели открывшегося окна: Application class. Щелкните по найденному имени двойным щелчком, и откроется страница помощи по этому классу (рис. 5.2).

Файл помощи по классу Application

Рис. 5.2. Файл помощи по классу Application

На рис. 5.2 я выделил рамкой тот фрагмент, где как раз и написано, в каком пространстве имен находятся описание и сборка (DLL-файл) с реализацией класса. Нас больше интересует именно пространство имен, а не сборка. Мне ни разу не приходилось использовать файл сборки, по крайней мере этот. Все основные файлы добавляются в раздел References проекта автоматически при создании проекта. Но если вы будете использовать что-либо специфическое, то может потребоваться подключение нужного файла сборки самостоятельно.

Второй метод узнать пространство имен — не думать о нем, а возложить всю головную боль на среду разработки. У Visual Studio голова достаточно хорошая, и она с легкостью решит такую задачу.

Попробуйте сейчас ввести где-нибудь в коде метода Main() слово OleDbConnection. Это класс, который используется для соединения с базами данных, — компилятор не найдет его среди подключенных пространств имен и конечно же подчеркнет. Теперь вы можете щелкнуть правой кнопкой по подчеркнутому имени, в контекстном меню раскрыть пункт Resolve (Разрешить), и в его подменю будут перечислены пространства имен, в которых среда разработки смогла найти указанное слово (рис. 5.3).

 Контекстное меню позволяет решить проблему подключения пространств имен

Рис. 5.3. Контекстное меню позволяет решить проблему подключения пространств имен

В контекстом меню доступны два варианта решения проблемы, между которыми находится разделитель. Выше разделителя указаны варианты, которые добавляют в начало модуля кода оператор using с выбранным пространством имен. Варианты ниже разделителя изменяют короткое имя метода на полное. То есть, в случае с типом данных OleDbConnection, если вы выберете вариант ниже разделителя, то тип данных заменится на System.Data.OleDb.OleDbConnection. Если вы знаете, что это единственное обращение к такому типу данных, то можно использовать полный путь, но если в модуле кода вы станете использовать этот тип данных много раз, то проще будет сразу добавить его в раздел using.

Чаще всего в этом подменю будет приведен только один вариант — и до разделителя, и после, но некоторые имена могут быть объявлены как для Windows, так и для Web. В таких случаях требуется выбрать нужную сборку. Это не сложно, потому что для Интернета чаще всего используется пространство имен System.Web. Например, класс Application для интернет-программирования находится в пространстве имен Microsoft.Web.Administration. Это определяется ключевым словом Web, которое находится в середине.

Обратите также внимание, что мастер создания проекта поместил весь код нашего проекта в пространство имен, идентичное имени проекта. Всегда обрамляйте код в пространство имен.

Пространство имен по умолчанию для вашего проекта можно изменить. Для этого щелкните правой кнопкой мыши по имени проекта и выберите в контекстном меню пункт Properties, чтобы изменить свойства проекта. Здесь в разделе Application
в поле Default namespace (Пространство имен по умолчанию) вы можете изменить имя пространства имен. При этом уже существующий код останется в старом пространстве имен. То есть, существующий код изменяться автоматически не будет, а вот новые файлы, которые будут добавляться в проект, станут попадать уже в новое пространство. Если вам нужно перенести существующий код в новое пространство, то следует сделать это руками, изменяя текущее пространство имен на новое. Можно оставить и старое имя, потому что в одной сборке могут быть и два, и три разных пространства имен, если вас это устраивает.

5.1.2. Потоки

Обратите внимание, что перед методом Main() в квадратных скобках стоит ключевое слово STAThread (см. листинг 5.1). Оно указывает на то, что модель разделения потоков для приложения будет одиночная (Single Thread Apartment model). Такой атрибут должен быть указан для всех точек входа в WinForms-приложения. Если он будет отсутствовать, то компоненты Windows могут работать некорректно.

Дело в том, что без атрибута STAThread приложение будет пытаться использовать многопоточную модель разделения MTAThread (Multi Threaded Apartment model), которая не поддерживается для Windows Forms.

5.1.3. Класс Application

В листинге 5.1 в методе Main() все строки кода являются обращением к классу Application, который предоставляет статичные свойства и методы (это значит, что не нужно создавать экземпляр класса, чтобы их вызвать) для поддержки работы приложения. Основными методами являются запуск и останов приложения, а также обработка сообщений Windows. При возникновении каких-либо ситуаций ОС отправляет окну событие, и окно должно отработать это событие. Например, если пользователь нажал на кнопку закрытия окна, то этому окну направляется событие WM_CLOSE (если мне не изменяет память). Поймав это событие, окно должно отреагировать, освободить запрошенные ресурсы и приготовиться к уничтожению. Любой ввод пользователя, включая нажатие клавиш на клавиатуре и движение курсора мыши, обрабатывает ОС, а потом с помощью сообщений отправляет изменения в приложение.

Чтобы отлавливать сообщения, которые направляет приложению операцион-
ная система, в приложении должен быть запущен цикл. В таких языках, как
С/С++, цикл получает от ОС сообщение, обрабатывает его и ожидает следующего сообщения. Этот цикл продолжается до тех пор, пока не произойдет выхода из программы.

Класс Application берет на себя всю ответственность за получение сообщений от системы и перенаправление их в окна, чтобы вы могли эти сообщения обработать. Чуть позже мы научимся ловить сообщения, а пока нам нужно знать, что за подготовку сообщения для обработки отвечает именно класс Application.

Рассмотрим методы, которые вызываются в классе, который сгенерировал нам мастер Visual Studio. Первый метод класса Application, который мы вызываем:

EnableVisualStyles(). Этот метод включает отображение в стилях ОС, на которой запущено приложение. Если удалить эту строку и запустить программу, то все элементы управления будут выглядеть в стиле Windows 9x с квадратными углами даже в Windows 7. Не вижу смысла возвращаться в доисторические времена визуального интерфейса, но если вам вдруг это понадобится, теперь вы знаете, какую строку нужно удалить.

Следующий метод приложения, который вызывает программа: SetCompatibleTextRenderingDefault(). Некоторые элементы управления могут отображать текст с помощью старых функций GDI или с помощью новых функций GDI+. Если методу SetCompatibleTextRenderingDefault() передать значение false, то будут использоваться функции GDI+.

Это все были подготовительные методы, а последний метод: Run() является наиболее важным. Этот метод запускает скрытый цикл обработки сообщений ОС и делает видимой форму, которая передается в качестве параметра. В нашем примере
в качестве параметра передается инициализация объекта класса Form1, для чего вызывается конструктор класса с помощью оператора new, как мы это делали ранее. Просто мы всегда присваивали результат выполнения new переменной, а в этом случае нам переменная не нужна, и мы больше не будем использовать объект
в методе Мain(), поэтому, нигде ничего не сохраняя, сразу передаем новый объект методу. То же самое можно было написать так:

   Form1 form = new Form1();
   Application.Run(form);

Все исходные коды главы 5 Библии C#

Chapter 19. The System.Windows.Forms Namespace

The

System.Windows.Forms namespace contains the

classes that you use to build rich client applications—the

windows, buttons, drop-down lists, and labels that make up the UIs

with which you are familiar. At the center of this universe is the

Control class. Any window that appears on the

screen, from dialogs to checkboxes, is derived from

Control, and this class provides almost all the

basic behavior a window needs. All the common windows controls

provide relatively minor modifications or extensions to

Control to add their own behaviors (painting,

click handling, etc.), so a good understanding of the

Control class goes a long, long way.

Figures Figure 19-1 and Figure 19-2

show many of the types in this namespace. Figure 19-3 shows many of this

namespace’s event arguments, and Figure 19-4 shows the delegates. The components are shown

in Figure 19-5 and the controls are shown in Figures Figure 19-6 and Figure 19-7.

Many types from the System.Windows.Forms namespace

Figure 19-1. Many types from the System.Windows.Forms namespace

More types from the System.Windows.Forms namespace

Figure 19-2. More types from the System.Windows.Forms namespace

Event arguments in the System.Windows.Forms namespace

Figure 19-3. Event arguments in the System.Windows.Forms namespace

Figure 19-4. Delegates from System.Windows.Forms …

Graphical User Interface (GUI) with Windows.Forms

Windows.Forms is the standard GUI toolkit for the .NET Framework. It is
also supported by Mono. Like every other thing in the world it has its
strong and weak points. Another GUI supported by .NET is Gtk#.
Which outguns which is up to you to judge. But before you can do that,
get a feel for Windows.Forms by going throught this tutorial.

Note 1: To compile programs using Windows.Forms you will need to
include -r:System.Windows.Forms in the compile command. E.g. if
you save the examples in the file MyFirstForm.n, compile them with:

ncc MyFirstForm.n -r:System.Windows.Forms -o MyFirstForm.exe

Note 2: I am not going to go too much into details of every single
thing you can do with Windows.Forms. These can be pretty easily checked in the
Class reference.
I will just try to show you how to put all the bricks together.

Table of Contents

    • The first step

      • Buttons, labels and the rest
      • A simple menu
      • Basic events
      • Cleaning up
    • The second step

      • Painting
      • Overriding event handlers
      • A simple animation with double-buffering
      • Bitmaps and images
      • Adding icons to the menu

The first step

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

class MyFirstForm : Form {
   public static Main() : void {
      Application.Run(MyFirstForm());
   }
}

This is not too complex, is it? And it draws a pretty window on the
screen, so it is not utterly useless, either :)

Let us now try to customize the window a little. All the customization
should be placed in the class constructor.

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

class MyFirstForm : Form {
   public this() {
      Text="My First Form";        //title bar
      ClientSize=Size(300,300);    //size (without the title bar) in pixels
      StartPosition=FormStartPosition.CenterScreen;     //I'm not telling
      FormBorderStyle=FormBorderStyle.FixedSingle;      //not resizable
   }

   public static Main() : void {
      Application.Run(MyFirstForm());
   }
}

An empty Windows.Forms form.

Buttons, labels and the rest

Wonderful. Now the time has come to actually display something in our window. Let us add a slightly customized button. All you need to do is to add the following code to the constructor of your Form class (i.e. somewhere between public this() { and the first } after it).

def button=Button();
   button.Text="I am a button";
   button.Location=Point(50,50);
   button.BackColor=Color.Khaki;
   Controls.Add(button);

def label=Label();
   label.Text="I am a label";
   label.Location=Point(200,200);
   label.BorderStyle=BorderStyle.Fixed3D;
   label.Cursor=Cursors.Hand;
   Controls.Add(label);

I hope it should pretty doable to guess what is which line responsible for. Perhaps you could only pay a little more attention to the last one. Buttons, labels, textboxes, panels and the like are all controls, and simply defining them is not enough, unless you want them to be invisible.
Also, the button we have added does actually nothing. But fear not, we shall discuss
a bit of events very soon.

A simple menu

Menus are not hard. Just take a look at the following example:

def mainMenu=MainMenu();

def mFile=mainMenu.MenuItems.Add("File");
def mFileDont=mFile.MenuItems.Add("Don't quit");
def mFileQuit=mFile.MenuItems.Add("Quit");

def mHelp=mainMenu.MenuItems.Add("Help");
def mHelpHelp=mHelp.MenuItems.Add("Help");

Menu=mainMenu;

It will create a menu with two drop-down submenus: File (with
options Don’t Quit and Quit) and Help with just
one option, Help.

A button, a label and a menu.

It is also pretty easy to add context menus to controls. Context menus are the ones which become visible when a control is right-clicked. First, you need to define the whole menu, and than add a reference to it to the button definition:

def buttonCM=ContextMenu();
   def bCMWhatAmI=buttonCM.MenuItems.Add("What am I?");
   def bCMWhyAmIHere=buttonCM.MenuItems.Add("Why am I here?");
...
def button=Button();
   ...
   button.ContextMenu=buttonCM;

A context menu.

Basic events

Naturally, however nice it all might be, without being able to actually
serve some purpose, it is a bit pointless. Therefore, we will need to
learn handling events. There are in fact two ways to do it. Let us take
a look at the easier one for the begnning.

The first thing you will need to do is to add the System namespace:

You can skip this step but you will have to write
System.EventArgs and so on instead of EventArgs.

Then, you will need to add a reference to the event handler to your
controls. It is better to do it first as it is rather easy to forget
about it after having written a long and complex handler.

button.Click+=button_Click;
...
mFileDont.Click+=mFileDont_Click;
mFileQuit.Click+=mFileQuit_Click;
...
mHelpHelp.Click+=mHelpHelp_Click;

Mind the += operator instead of = used when customizing
the controls.

Finally, you will need to write the handlers. Do not forget
to define the arguments they need, i.e. an object and an
EventArgs. Possibly, you will actually not use them but you have
to define them anyway. You can prefix their names with a _ to avoid
warnings at compile time.

private button_Click(_sender:object, _ea:EventArgs):void{
   Console.WriteLine("I was clicked. - Your Button");
}

private mFileQuit_Click(_sender:object, _ea:EventArgs):void{
   Application.Exit();
}

This is the way you will generally want to do it. But in this very case
the handlers are very short, and like all handlers, are not very often
used for anything else than handling events. If so, we could rewrite them
as lambda expressions which will save a good bit of space and clarity.

button.Click+=fun(_sender:object, _ea:EventArgs){
   Console.WriteLine("I wrote it. - button_Click as a lambda");
};

mFileQuit.Click+=fun(_sender:object, _ea:EventArgs){
   Application.Exit();
};

Cleaning up

After you are done with the whole application, you should clean
everything up. In theory, the system would do it automatically anyway
but it certainly is not a bad idea to help the system a bit. Especially
that it is not a hard thing to do at all, and only consists of two steps.

The first step is to add a reference to System.ComponentModel
and define a global variable of type Container:

using System.ComponentModel;
...

class MyFirstForm : Form {
   components : Container = null;
...

In the second and last step, you will need to override the Dispose
method. It could even fit in one line if you really wanted it to.

protected override Dispose(disposing : bool) : void {
   when (disposing) when (components!=null) components.Dispose();
   base.Dispose(d);
}

The second step

You should now have a basic idea as to what a form looks like. The time
has come to do some graphics.

Painting

There is a special event used for painting. It is called Paint and you
will need to create a handler for it.

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

class MySecondForm : Form {
   public this() {
      Text="My Second Form";
      ClientSize=Size(300,300);

      Paint+=PaintEventHandler(painter);
   }

   private painter(_sender:object, pea:PaintEventArgs):void{
      def graphics=pea.Graphics;
      def penBlack=Pen(Color.Black);
      graphics.DrawLine(penBlack, 0, 0 , 150, 150);
      graphics.DrawLine(penBlack, 150, 150, 300, 0);
   }

   public static Main():void{
      Application.Run(MySecondForm());
   }
}

A reference to the painter method should be added in the form class
constructor (it affects the whole window), but this time it is a
PaintEventHandler. Same as PaintEventArgs in the handler
itself. In the handler, you should first define a variable of type
PaintEventArgs.Graphics. This is the whole window. This is where you will
be drawing lines, circles, strings, images and the like (but not pixels;
we will discuss bitmaps later on). To draw all those things you will
need pens and brushes. In our example we used the same pen twice. But
sometimes you will only need it once. In such case, there is no point
in defining a separate variable for it. Take a look at the next example.

Painting in Windows.Forms.

Overriding event handlers

Another way to define a handler is to override the default one provided
by the framework. It is not at all complicated, it is not dangerous and
in many cases it will prove much more useful. Take a look at the example
overriding the OnPaint event handler:

protected override OnPaint(pea:PaintEventArgs):void{
   def g=pea.Graphics;
   g.DrawLine(Pen(Color.Black), 50, 50, 150, 150);
}

Naturally, when you override the handler, there is no need any longer
to add a reference to it in the class constructor.

By the same token can you override other events. One of the possible
uses is to define quite complex clickable areas pretty easily:

protected override OnPaint(pea:PaintEventArgs):void{
   def g=pea.Graphics;
   for (mutable x=0; x<300; x+=10) g.DrawLine(Pen(Color.Blue), x, 0, x, 300);
}

protected override OnMouseDown(mea:MouseEventArgs):void{
   when (mea.X%10<4 && mea.Button==MouseButtons.Left)
      if (mea.X%10==0) Console.WriteLine(&quot;You left-clicked a line.&quot;)
      else Console.WriteLine($&quot;You almost left-clicked a line ($(mea.X%10) pixels).&quot;);
}

Easily creating a complex clickable image map.

A simple animation with double-buffering

What is an animation without double-buffering? Usually, a flickering
animation. We do not want that. Luckily enough, double-buffering is as
easy as abc in Windows.Forms.
In fact, all you need to do is to set three style flags and override the
OnPaint event handler instead of writing your own handler and assigning
it to the event.

class Animation:Form{
   mutable mouseLocation:Point;         //the location of the cursor

   public this(){
      Text=&quot;A simple animation&quot;;
      ClientSize=Size(300,300);
      SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint |
               ControlStyles.DoubleBuffer, true);         //double-buffering on
   }

   protected override OnPaint(pea:PaintEventArgs):void{
      def g=pea.Graphics;
      g.FillRectangle(SolidBrush(Color.DimGray),0,0,300,300);  //clearing the window

      def penRed=Pen(Color.Red);
      g.FillEllipse(SolidBrush(Color.LightGray),
                    mouseLocation.X-15, mouseLocation.Y-15, 29, 29);
      g.DrawEllipse(penRed, mouseLocation.X-15, mouseLocation.Y-15, 30, 30);
      g.DrawLine(penRed, mouseLocation.X, mouseLocation.Y-20,
                 mouseLocation.X, mouseLocation.Y+20);
      g.DrawLine(penRed, mouseLocation.X-20, mouseLocation.Y,
                 mouseLocation.X+20, mouseLocation.Y);
   }

   protected override OnMouseMove(mea:MouseEventArgs):void{
      mouseLocation=Point(mea.X,mea.Y);
      Invalidate();       //redraw the screen every time the mouse moves
   }

   public static Main():void{
      Application.Run(Animation());
   }
}

As you can see, the basic structure of a window with animation is
pretty easy. Main starts the whole thing as customized in the
constructor. The OnPaint event handler is called immediately. And
then the whole thing freezes waiting for you to move the mouse. When
you do, the OnMouseMove event handler is called. It checks the
new position of the mouse, stores it in mouseLocation and tells
the window to redraw (Invalidate();).

Try turning double-buffering off (i.e. comment the SetStyle…
line) and moving the mouse slowly. You will see the viewfinder
flicker. Now turn double-buffering back on and try again. See the
difference?

Well, in this example you have to move the mouse slowly to actually
see any difference because the viewfinder we are drawing is a pretty
easy thing to draw. But you can be sure that whenever anything more
complex comes into play, the difference is very well visible without
any extra effort.

A simple animation with double-buffering.

Bitmaps and images

I promised I would tell you how to draw a single pixel. Well, here we are.

protected override OnPaint(pea:PaintEventArgs):void{
   def g=pea.Graphics;
   def bmp=Bitmap(256,1);   //one pixel height is enough; we can draw it many times
   for (mutable i=0; i<256; ++i) bmp.SetPixel(i, 0, Color.FromArgb(i,0,i,0));
   for (mutable y=10; y<20; ++y) g.DrawImage(bmp, 0, y);
}

So, what do we do here? We define a bitmap of size 256,1. We draw onto
it 256 pixels in colours defined by four numbers: alpha (transparency),
red, green, and blue. But as we are only manipulating alpha and green,
we will get a nicely shaded green line. Finally, we draw the bitmap onto
the window ten times, one below another.

Mind the last step, it is very important. The bitmap we had defined is
an offset one. Drawing onto it does not affect the screen in any way.

Now, that you know the DrawImage method nothing can stop you from
filling your window with all the graphic files you might be having on
your disk, and modifying them according to your needs.

class ImageWithAFilter:Form{
   img:Image=Image.FromFile(&quot;/home/johnny/pics/doggy.png&quot;);  //load an image
   bmp:Bitmap=Bitmap(img);       //create a bitmap from the image

   public this(){
      ClientSize=Size(bmp.Width*2, bmp.Height);
   }

   protected override OnPaint(pea:PaintEventArgs):void{
      def g=pea.Graphics;
      for (mutable x=0; x<bmp.Width; ++x) for (mutable y=0; y<bmp.Height; ++y)
         when (bmp.GetPixel(x,y).R>0){
            def g=bmp.GetPixel(x,y).G;
            def b=bmp.GetPixel(x,y).B;
            bmp.SetPixel(x,y,Color.FromArgb(255,0,g,b));
         }
      g.DrawImage(img,0,0);            //draw the original image on the left
      g.DrawImage(bmp,img.Width,0);    //draw the modified image on the right
   }

   ...
}

This example draws two pictures: the original one on the left and the
modified one on the right. The modification is a very simple filter
entirely removing the red colour.

A simple graphic filter.

Adding icons to the menu

Adding icons is unfortunately a little bit more complicated than other
things in Windows.Forms.

You will need to provide handlers for two events: MeasureItem
and DrawItem, reference them in the right place, and set the menu
item properly.

mFileQuit.Click+=EventHandler( fun(_) {Application.Exit();} );
mFileQuit.OwnerDraw=true;
mFileQuit.MeasureItem+=MeasureItemEventHandler(measureItem);
mFileQuit.DrawItem+=DrawItemEventHandler(drawItem);
private measureItem(sender:object, miea:MeasureItemEventArgs):void{
   def menuItem=sender:>MenuItem;
   def font=Font(&quot;FreeMono&quot;,8);   //the name and the size of the font
   miea.ItemHeight=(miea.Graphics.MeasureString(menuItem.Text,font).Height+5):>int;
   miea.ItemWidth=(miea.Graphics.MeasureString(menuItem.Text,font).Width+30):>int;
}

private drawItem(sender:object, diea:DrawItemEventArgs):void{
   def menuItem=sender:>MenuItem;
   def g=diea.Graphics;
   diea.DrawBackground();
   g.DrawImage(anImageDefinedEarlier, diea.Bounds.Left+3, diea.Bounds.Top+3, 20, 15);
   g.DrawString(menuItem.Text, diea.Font, SolidBrush(diea.ForeColor),
                diea.Bounds.Left+25, diea.Bounds.Top+3);
}

A menu with an icon.

Понравилась статья? Поделить с друзьями:
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
  • Настройка сервера с нуля windows server
  • Командная строка windows sleep
  • Изменение размера файла подкачки windows 11
  • Сервер ip телефонии для windows
  • Защитник windows или антивирус касперского