C# — WinForms Как перевести Json формат в понятный текст


Содержание

Как сохранить содержимое RichTextBox в файл без потери форматирования

24.05.2012, 12:25

RichTextBox без потери формата
Как загрузить в RichTextBox с ворда без потери формата. например чтобы и в ворде был курсив и в.

Копирование в richtextbox из excel без форматирования
Здравствуйте! при копировании текста из экселя и вставке его в richtextbox текст виден как таблица.

Как сохранить RichTextBox в файл? c#
Как сохранить RichTextBox? просто без диалогового окна. Вот код Сохранить как. void.

Как сохранить изображение из RichTextBox в файл?
На форме лежит RichTextBox, в котором EnableAutoDragAndDrop = true. RichTextBox пустой. Открываю.

Как сохранить текст из нескольких richTextBox в один файл
Привет всем. По щелчку кнопки нужно сохранить текст из 2-ух richTextBox в один файл, но текст из.

Элементы управления для использования в формах Windows Forms Controls to Use on Windows Forms

Ниже приведен алфавитный список элементов управления и компонентов, используемых в формах Windows Forms. The following is an alphabetic list of controls and components that can be used on Windows Forms. Помимо элементов управления Windows Forms, описанных в этом разделе, в формы Windows Forms можно добавлять элементы управления ActiveX и пользовательские элементы управления. In addition to the Windows Forms controls covered in this section, you can add ActiveX and custom controls to Windows Forms. Если вам не удается найти нужный элемент управления в этом списке, вы можете создать свой собственный. If you do not find the control you need listed here, you can also create your own. См. раздел Создание элементов управления Windows Forms во время разработки. For details, see Developing Windows Forms Controls at Design Time. Дополнительные сведения о выборе необходимого элемента управления см. в разделе Функциональная классификация элементов управления Windows Forms. For more information about choosing the control you need, see Windows Forms Controls by Function.

Visual Basic элементы управления основаны на классах, предоставляемых .NET Framework. Visual Basic controls are based on classes provided by the .NET Framework.

В этом разделе In This Section

Функциональная классификация элементов управления Windows Forms Windows Forms Controls by Function
Содержит список и описание Windows Forms элементов управления на основе .NET Framework. Lists and describes Windows Forms controls based on the .NET Framework.

Элементы управления со встроенной поддержкой рисования владельцем Controls with Built-In Owner-Drawing Support
Описание возможностей изменения аспектов внешнего вида элемента управления, которые недоступны через свойства. Describes how to alter aspects of a control’s appearance that are not available through properties.

Компонент BackgroundWorker BackgroundWorker Component
Позволяет форме или элементу управления выполнять операцию асинхронно. Enables a form or control to run an operation asynchronously.

Элемент управления BindingNavigator BindingNavigator Control
Представляет собой пользовательский интерфейс для перехода и обработки для элементов управления, которые привязываются к данным. Provides the navigation and manipulation user interface (UI) for controls that are bound to data.

Компонент BindingSource BindingSource Component
Инкапсулирует источник данных для привязки к элементам управления. Encapsulates a data source for binding to controls.

Элемент управления Button Button Control
Представляет стандартную кнопку, которую пользователь может нажать для выполнения действий. Presents a standard button that the user can click to perform actions.

Элемент управления CheckBox CheckBox Control
Указывает, включено или выключено условие. Indicates whether a condition is on or off.

Элемент управления CheckedListBox CheckedListBox Control
Отображает список элементов с флажками слева от каждого элемента. Displays a list of items with a check box next to each item.

Компонент ColorDialog ColorDialog Component
Предоставляет стандартное диалоговое окно для выбора цветов из палитры и добавления в нее дополнительных цветов. Allows the user to select a color from a palette in a pre-configured dialog box and to add custom colors to that palette.

Элемент управления ComboBox ComboBox Control
Отображает данные в раскрывающемся поле со списком. Displays data in a drop-down combo box.

Компонент ContextMenu ContextMenu Component
Предоставляет пользователям быстрый доступ к меню часто используемых команд, связанных с выбранным объектом. Provides users with an easily accessible menu of frequently used commands that are associated with the selected object. Хотя ContextMenuStrip заменяет и добавляет функциональные возможности ContextMenu для управления предыдущими версиями, ContextMenu сохраняется как для обратной совместимости, так и для будущего использования, если это необходимо. Although ContextMenuStrip replaces and adds functionality to the ContextMenu control of previous versions, ContextMenu is retained for both backward compatibility and future use if so desired.

Элемент управления ContextMenuStrip ContextMenuStrip Control
Представляет контекстное меню. Represents a shortcut menu. Хотя ContextMenuStrip заменяет и добавляет функциональные возможности ContextMenu для управления предыдущими версиями, ContextMenu сохраняется как для обратной совместимости, так и для будущего использования, если это необходимо. Although ContextMenuStrip replaces and adds functionality to the ContextMenu control of previous versions, ContextMenu is retained for both backward compatibility and future use if so desired.

Элемент управления DataGrid DataGrid Control
Отображает табличные данные из набора данных и позволяет вносить изменения в источник данных. Displays tabular data from a dataset and allows for updates to the data source.

Элемент управления DataGridView DataGridView Control
Предоставляет гибкую, расширяемую систему для отображения и редактирования табличных данных. Provides a flexible, extensible system for displaying and editing tabular data.

Элемент управления DateTimePicker DateTimePicker Control
Позволяет пользователю выбрать один элемент из списка дат или времени. Allows the user to select a single item from a list of dates or times.

Элементы управления и компоненты диалоговых окон Dialog-Box Controls and Components
Описание набора элементов управления для выполнения пользователем стандартных действий в приложении или системе. Describes a set of controls that allow users to perform standard interactions with the application or system.

Элемент управления DomainUpDown DomainUpDown Control
Отображает текстовые строки, которые пользователь может просматривать и выбирать. Displays text strings that a user can browse through and select from.

Компонент ErrorProvider ErrorProvider Component
Отображает сведения об ошибке для пользователя в фоновом режиме. Displays error information to the user in a non-intrusive way.

Класс FileDialog Предоставляет функциональные возможности базового класса для диалоговых окон файлов. FileDialog Class Provides base-class functionality for file dialog boxes.

Элемент управления FlowLayoutPanel FlowLayoutPanel Control
Представляет панель, которая динамически располагает содержимое по горизонтали или вертикали. Represents a panel that dynamically lays out its contents horizontally or vertically.

Компонент FolderBrowserDialog FolderBrowserDialog Component
Отображает интерфейс, с помощью которого пользователи могут просматривать и выбирать каталоги или создавать их. Displays an interface with which users can browse and select a directory or create a new one.

Компонент FontDialog FontDialog Component
Предоставляет приложениям шрифты, установленные в системе на текущий момент. Exposes the fonts that are currently installed on the system.

Элемент управления GroupBox GroupBox Control
Предоставляет возможность идентифицируемой группировки других элементов управления. Provides an identifiable grouping for other controls.

Компонент HelpProvider HelpProvider Component
Связывает HTML-файл справки с приложением Windows. Associates an HTML Help file with a Windows-based application.

Элементы управления HScrollBar и VScrollBar HScrollBar and VScrollBar Controls
Используются для просмотра длинных списков элементов или большого объема данных с помощью горизонтальной или вертикальной прокрутки окна приложения либо элемента управления. Provide navigation through a list of items or a large amount of information by scrolling either horizontally or vertically within an application or control.

Компонент ImageList ImageList Component
Отображает изображения на других элементах управления. Displays images on other controls.

Элемент управления Label Label Control
Отображает текст, который не может быть изменен пользователем. Displays text that cannot be edited by the user.

Элемент управления LinkLabel LinkLabel Control
Позволяет добавлять веб-ссылки в приложения Windows Forms. Allows you to add Web-style links to Windows Forms applications.

Элемент управления ListBox ListBox Control
Позволяет пользователю выбрать один или несколько элементов из заранее определенного списка. Allows the user to select one or more items from a predefined list.

Элемент управления ListView ListView Control
Отображает список элементов со значками в стиле проводника Windows. Displays a list of items with icons, in the manner of Windows Explorer.

Компонент MainMenu MainMenu Component
Отображает меню во время выполнения. Displays a menu at run time. Несмотря MenuStrip наточтофункцияMainMenu заменяет и добавляет функции к управлениюпредыдущимиверсиями,сохраняетсякакдляобратнойсовместимости,такидлябудущегоиспользованияпривыборе.MainMenu Although MenuStrip replaces and adds functionality to the MainMenu control of previous versions, MainMenu is retained for both backward compatibility and future use if you choose.

Элемент управления MaskedTextBox MaskedTextBox Control
Ограничивает формат вводимых пользователем данных в форме. Constrains the format of user input in a form.

Элемент управления MenuStrip MenuStrip Control
Предоставляет систему меню для формы. Provides a menu system for a form. Несмотря MenuStrip наточтофункцияMainMenu заменяет и добавляет функции к управлениюпредыдущимиверсиями,сохраняетсякакдляобратнойсовместимости,такидлябудущегоиспользованияпривыборе.MainMenu Although MenuStrip replaces and adds functionality to the MainMenu control of previous versions, MainMenu is retained for both backward compatibility and future use if you choose.

Элемент управления MonthCalendar MonthCalendar Control
Предоставляет интуитивно понятный графический интерфейс для пользователей для просмотра и задания сведений о дате. Presents an intuitive graphical interface for users to view and set date information.

Компонент NotifyIcon NotifyIcon Component
Отображает значки для процессов, выполняемых в фоновом режиме и не имеющих пользовательских интерфейсов. Displays icons for processes that run in the background and would not otherwise have user interfaces.

Элемент управления NumericUpDown NumericUpDown Control
Отображает числовые значения, которые пользователь может просматривать и выбирать. Displays numerals that a user can browse through and select from.

Компонент OpenFileDialog OpenFileDialog Component
Позволяет пользователям открывать файлы в стандартном диалоговом окне. Allows users to open files by using a pre-configured dialog box.

Компонент PageSetupDialog PageSetupDialog Component
Предоставляет стандартное диалоговое окно для задания параметров страницы для печати. Sets page details for printing through a pre-configured dialog box.

Элемент управления Panel Panel Control
Предоставляет возможность идентифицируемой группировки других элементов управления, а также прокрутку. Provide an identifiable grouping for other controls, and allows for scrolling.

Элемент управления PictureBox PictureBox Control
Отображает рисунки в формате точечного рисунка, GIF, JPEG, метафайла или значка. Displays graphics in bitmap, GIF, JPEG, metafile, or icon format.

Компонент PrintDialog PrintDialog Component
Служит для выбора принтера, печатаемых страниц и других параметров печати. Selects a printer, chooses the pages to print, and determines other print-related settings.


Компонент PrintDocument PrintDocument Component
Задает свойства, описывающие содержимое для печати, и печатает документ в приложениях Windows. Sets the properties that describe what to print, and prints the document in Windows-based applications.

Элемент управления PrintPreviewControl PrintPreviewControl Control
Позволяет создавать собственный компонент или диалоговое окно PrintPreview , вместо использования стандартных версий. Allows you to create your own PrintPreview component or dialog box instead of using the pre-configured version.

Элемент управления PrintPreviewDialog PrintPreviewDialog Control
Выводит документ в том виде, как он будет выглядеть при печати. Displays a document as it will appear when it is printed.

Элемент управления ProgressBar ProgressBar Control
Графически показывает ход выполнения действия. Graphically indicates the progress of an action towards completion.

Элемент управления RadioButton RadioButton Control
Представляет набор из двух или более взаимоисключающих вариантов выбора для пользователя. Presents a set of two or more mutually exclusive options to the user.

Элемент управления RichTextBox RichTextBox Control
Позволяет пользователям вводить, отображать и изменять текст с форматированием. Allows users to enter, display, and manipulate text with formatting.

Компонент SaveFileDialog SaveFileDialog Component
Служит для выбора сохраняемых файлов и места их сохранения. Selects files to save and where to save them.

SoundPlayer, класс Позволяет легко включать звуки в приложения. SoundPlayer Class Enables you to easily include sounds in your applications.

Элемент управления SplitContainer SplitContainer Control
Позволяет пользователю изменять размер закрепленного элемента управления. Allows the user to resize a docked control.

Элемент управления Splitter Splitter Control
Разрешает пользователю изменять размер закрепленного элемента управления (.NET Framework версии 1. x). Allows the user to resize a docked control (.NET Framework version 1.x).

Элемент управления StatusBar StatusBar Control
Отображает сведения о состоянии элемента управления, который находится в фокусе. Displays status information related to the control that has focus. Хотя StatusStrip заменяет и расширяет элемент управления StatusBar предыдущих версий, StatusBar сохраняется для обеспечения обратной совместимости и использования в будущем при его выборе. Although StatusStrip replaces and extends the StatusBar control of previous versions, StatusBar is retained for both backward compatibility and future use if you choose.

Элемент управления StatusStrip StatusStrip Control
Предоставляет элемент управления Windows «Строка состояния». Represents a Windows status bar control. Хотя StatusStrip заменяет и расширяет элемент управления StatusBar предыдущих версий, StatusBar сохраняется для обеспечения обратной совместимости и использования в будущем при его выборе. Although StatusStrip replaces and extends the StatusBar control of previous versions, StatusBar is retained for both backward compatibility and future use if you choose.

Элемент управления TabControl TabControl Control
Отображает несколько вкладок, содержащих рисунки и другие элементы управления. Displays multiple tabs that can contain pictures or other controls.

Элемент управления TableLayoutPanel TableLayoutPanel Control
Представляет панель, в которой содержимое динамически отображается в сетке, состоящей из строк и столбцов. Represents a panel that dynamically lays out its contents in a grid composed of rows and columns.

Элемент управления TextBox TextBox Control
Позволяет пользователю вводить изменяемый текст из нескольких строк. Allows editable, multiline input from the user.

Компонент Timer Timer Component
Вызывает событие через определенные интервалы. Raises an event at regular intervals.

Элемент управления ToolBar ToolBar Control
Отображает меню и кнопки с растровыми изображениями, активирующие команды. Displays menus and bitmapped buttons that activate commands. Вы можете расширить функциональные возможности элемента управления и изменить его внешний вид и поведение. You can extend the functionality of the control and modify its appearance and behavior. Несмотря ToolStrip наточтофункцияToolBar заменяет и добавляет функции к управлениюпредыдущимиверсиями,сохраняетсякакдляобратнойсовместимости,такидлябудущегоиспользованияпривыборе.ToolBar Although ToolStrip replaces and adds functionality to the ToolBar control of previous versions, ToolBar is retained for both backward compatibility and future use if you choose.

Элемент управления ToolStrip ToolStrip Control
Создает пользовательские панели инструментов и меню в приложениях Windows Forms. Creates custom toolbars and menus in your Windows Forms applications. Несмотря ToolStrip наточтофункцияToolBar заменяет и добавляет функции к управлениюпредыдущимиверсиями,сохраняетсякакдляобратнойсовместимости,такидлябудущегоиспользованияпривыборе.ToolBar Although ToolStrip replaces and adds functionality to the ToolBar control of previous versions, ToolBar is retained for both backward compatibility and future use if you choose.

Элемент управления ToolStripContainer ToolStripContainer Control
Предоставляет панели на каждой стороне формы для закрепления, нависания и упорядочения ToolStrip элементов управления, а также для использования в качестве центра ToolStripContentPanel для традиционных элементов управления. Provides panels on each side of a form for docking, rafting, and arranging ToolStrip controls, and a central ToolStripContentPanel for traditional controls.

Элемент управления ToolStripPanel ToolStripPanel Control
Предоставляет одну панель для стыковки, нависания и упорядочения ToolStrip элементов управления. Provides one panel for docking, rafting and arranging ToolStrip controls.

Элемент управления ToolStripProgressBar ToolStripProgressBar Control Overview
Графически показывает ход выполнения действия. Graphically indicates the progress of an action towards completion. ToolStripProgressBar Обычно содержится StatusStripв. The ToolStripProgressBar is typically contained in a StatusStrip.

Компонент ToolTip ToolTip Component
Отображает текст при наведении указателя мыши на другие элементы управления. Displays text when the user points at other controls.

Элемент управления TrackBar TrackBar Control
Служит для перемещения по большому объему данных или для визуальной настройки числовых параметров. Allows navigation through a large amount of information or visually adjusting a numeric setting.

Элемент управления TreeView TreeView Control
Отображает иерархию узлов, которые можно разворачивать и сворачивать. Displays a hierarchy of nodes that can be expanded or collapsed.

Элемент управления WebBrowser WebBrowser Control
Содержит веб-страницы и обеспечивает возможности просмотра интернет-страниц в приложении. Hosts Web pages and provides Internet Web browsing capabilities to your application.

Создание списка для выбора элементов в Windows Forms Windows Forms Controls Used to List Options
Описание набора элементов управления, используемых для предоставления пользователям списка вариантов для выбора. Describes a set of controls used to provide users with a list of options to choose from.

Элементы управления Windows Forms Windows Forms Controls
Описание использования элементов управления Windows Forms и важных понятий для работы с ними. Explains the use of Windows Forms controls, and describes important concepts for working with them.

Создание элементов управления Windows Forms во время разработки Developing Windows Forms Controls at Design Time
Ссылки на разделы с инструкциями, рекомендации по выбору создаваемого элемента управления, а также другие сведения о создании собственных элементов управления. Provides links to step-by-step topics, recommendations for which kind of control to create, and other information about creating your own control.

Сравнение элементов управления и программируемых объектов в разных языках и библиотеках Controls and Programmable Objects Compared in Various Languages and Libraries
Предоставляет таблицу, которая сопоставляет элементы управления в Visual Basic 6,0 с соответствующим элементом управления в Visual Basic .NET. Provides a table that maps controls in Visual Basic 6.0 to the corresponding control in Visual Basic .NET. Обратите внимание, что элементы управления теперь являются классами в .NET Framework. Note that controls are now classes in the .NET Framework.

Цукерберг рекомендует:  Кому нужны дипломы

Практическое руководство. Добавление элементов управления ActiveX в Windows Forms How to: Add ActiveX Controls to Windows Forms
В этой статье описывается использование элементов управления ActiveX в формах Windows Forms. Describes how to use ActiveX controls on Windows Forms.

Работа с JSON в Microsoft SQL Server

В СУБД Microsoft SQL Server, начиная с 2020 версии, существует возможность встроенной работы с форматом данных JSON, и сегодня мы поговорим о том, что это за формат, где и для чего он используется и, конечно же, подробно рассмотрим функционал SQL сервера для работы с этим форматом.

Как я уже сказал, функционал для работы с JSON в SQL сервере появился в 2020 версии, обзор всех нововведений этой версии можете посмотреть в материале — Microsoft SQL Server 2020 – обзор новых возможностей. Сегодня, как Вы уже поняли, мы остановимся на одном нововведении SQL Server 2020 — это поддержка JSON.

Что такое JSON?

JSON (Object Notation JavaScript) – это простой, удобный для чтения как человеком, так и компьютером текстовый формат обмена данными. Он представляет собой текст в виде пар параметр-значение. JSON позволяет передавать не только сами данные, но и их структуру, что напоминает формат данных XML.

JSON на текущий момент очень популярный формат обмена данными, так как он простой и понятный, в связи с этим он широко используется для обмена данными в современных веб — и мобильных приложениях. Встроенная поддержка JSON есть во многих языках программирования и СУБД, например, в языке программирования PHP такая поддержка существует уже достаточно давно, функционал PHP для работы с JSON мы с Вами уже рассматривали в материале PHP — примеры работы с форматом JSON.

В качестве типа значения параметра в формате JSON могут выступать:

  • Объект (значение в фигурных скобках <>);
  • Массив (значение в квадратных скобках []);
  • Строка (значение в кавычках «Пример»);
  • Число;
  • Логический тип (true, false);
  • NULL.

Благодаря тому, что в JSON есть возможность выделять объекты и массивы мы можем с помощью простой строки JSON передать целую структуру. Ниже представлен пример строки JSON, т.е. формата JSON:

Для более подробного изучения формата JSON можете посетить на официальный сайт JSON.

Функционал MS SQL Server для работы с JSON

Ранее, до 2020 версии SQL сервера, разработчикам баз данных в случае необходимости обработки данных в формате JSON, приходилось изобретать собственные инструменты (функции, процедуры), в SQL Server 2020 компания Microsoft решила облегчить жизнь программистам и добавила встроенные инструменты для работы с JSON, а какие мы сейчас и узнаем.

И для начала хотелось бы сказать, что в SQL сервере для хранения данных в формате JSON не предусмотрен отдельный тип данных (как например, для XML), для хранения данных JSON необходимо использовать обычный тестовый тип VARCHAR.

Как и в случае с XML мы можем преобразовывать табличные данные в формат JSON и, наоборот, при получении данных в формате JSON преобразовывать их в табличные или просто извлекать какие-то скалярные значения.

Итак, для работы с форматом JSON в SQL сервере существуют следующие функции и инструкции:

  • ISJSON – функция для проверки строки на наличие данных JSON;
  • JSON_VALUE — это функция для извлечения скалярного значения из строки JSON;
  • JSON_QUERY – это функция для извлечения объекта или массива из строки JSON;
  • JSON_MODIFY – функция для изменения данных в строке JSON;
  • OPENJSON – табличная функция для преобразования данных JSON в табличный вид;
  • FOR JSON – инструкция для преобразования данных SQL сервера в формат JSON.

А теперь давайте посмотрим примеры использования этих функций в языке T-SQL.

Исходные данные для примеров

Для того чтобы посмотреть на работу представленных выше функций, давайте создадим тестовую базу данных TestBase, а в ней тестовую таблицу TestTable, в которой будет три столбца: идентификатор, столбец для хранения JSON данных и столбец, характеризующий эти данные.


Затем добавим в тестовую таблицу три строки, первая с JSON данными, вторая будет содержать просто текст, а третья ничего не будет содержать (NULL).

Для примера давайте представим, что строка с JSON данными будет содержать некий заказ и хранить информацию об этом заказе в структурированном виде, а именно: несколько общих свойств заказа, товары, входящие в этот заказ, с указанием их цены и количества, и список телефонов ответственных лиц, т.е. менеджеров по этому заказу.

В данной структуре я попытался задействовать все те возможные типы значений, которые можно использовать для формирования JSON строки. Другими словами, в представленной ниже строке JSON будут значения и в виде простого текста (Title), чисел (Id), значения в виде вложенного объекта (Properties), в виде массива с объектами (Goods), а также массива с простыми значениями (ManagerPhones).

Примечание! В качестве SQL сервера у меня выступает редакция Microsoft SQL Server 2020 Express.

Скрипт создания тестовых объектов на SQL сервере

ISJSON

Данная функция, как я уже сказал, нужна нам для того, чтобы определять является ли строка данными JSON. Принимает она один параметр, понятное дело строку для проверки, и возвращает 1, если строка представляет собой JSON данные, 0, если нет и NULL, если мы передали NULL.

Давайте напишем простой запрос, который нам покажет, какая из строк является данными JSON, а какая нет.

Как видим, функция отработала правильно.

JSON_VALUE

Для того чтобы получить скалярное значение из JSON данных в SQL сервере существует функция JSON_VALUE. У нее два параметра: первый это непосредственно сами данные JSON, например, переменная или столбец, содержащий JSON строку и второй это путь до значения, которое нужно извлечь. Для примера давайте извлечем из наших тестовых JSON данных наименование второго товара, его стоимость, дату создания заказа и первый телефон менеджера, для этого пишем следующий запрос.

Для того чтобы работать только с JSON данными я отфильтровал строки нашей таблицы, указав в предложение WHERE функцию ISJSON.

JSON_QUERY

С помощью данной функции можно извлекать из JSON строки ее часть, т.е. мы можем извлечь объект или массив. Функция принимает два параметра: первый это также данные JSON, а второй это путь до объекта или массива, который необходимо извлечь. Возвращает данная функция также JSON данные.

JSON_MODIFY

Для изменения данных JSON в SQL сервере предусмотрена функция JSON_MODIFY. Для примера давайте в наших тестовых данных изменим цену товара (например, монитора), а также добавим дополнительный номер телефона менеджера.

Как видим, все получилось.

OPENJSON

Этой табличной функцией можно преобразовать JSON данные в табличный вид. Принимает она два параметра: первый это как всегда JSON данные, а второй, необязательный параметр, путь к объекту или массиву. Для указания конкретной спецификации табличного вида можно использовать инструкцию WITH. Например, давайте получим в табличном виде список товаров в заказе. Сначала попробуем это сделать без инструкции WITH, а потом с ней и посмотрим на результаты.

FOR JSON

Инструкция FOR JSON используется в SQL сервере для преобразования табличных данных в JSON строку. У данной инструкции два режима AUTO и PATH. В случае с AUTO SQL сервер автоматически распознает инструкцию SELECT и преобразует данные в строку JSON. В случае с PATH структуру JSON документа Вы можете задать сами. Давайте сделаем простую выборку из нашей таблицы, и полученные данные преобразуем в JSON документ.

Более подробную информацию о работе с JSON в MS SQL Server можете найти в официальной технической документации, а у меня на этом все, пока!

Переводчик на C# Windows Forms

Структура пояснительной записки:

Глава 1. Теоретические аспекты разработки переводчика

1.1 Разработка требований к приложению

1.2 Обоснование выбора языка программирования С# и среды разработки Visual Studio

1.3 Использование возможностей Яндекс API для осуществления переводов

Глава 2. Практическая реализация приложения

2.1 Реализация интерфейсной части программы

2.2 Реализация программного кода приложения

2.3 Разработка справочной системы

Список использованной литературы

Требования к приложению:

  • При запуске программы должна отображаться главная форма с полем для ввода текста и поле для получения перевода.
  • На главной форме должны быть следующие кнопки: кнопка для смены направления перевода, кнопка «О программе», кнопка, вызывающая форму со справочной информацией, кнопка сохранения перевода, кнопка с сохраненными переводами, кнопка с настройками и кнопка для перевода текста.
  • В программе, на главной форме, должна отображаться информация о количестве символов, которые находятся в текстовом поле переводимого текста.
  • Должна быть реализована функция сохранения переводов.
  • В программу должна быть встроена справка.
  • Программа должна иметь понятный интерфейс.
  • Программа должна возвращать сразу несколько переводов для отдельных слов.
  • Сохраненные переводы должны храниться в текстовом документе и загружаться в программу при ее запуске.
  • В программе должны быть реализованы следующие основные настройки: изменение величины шрифта, изменение API-ключей для составления запроса к Яндекс API.
  • Возможность использования некоторых функций приложения с помощью горячих клавиш.
  • При первом запуске, перед показом главной формы, должно быть показано приветственное окно, с подсказками и ключевыми особенностями программы.
  • Настройки должны сохраняться перед закрытием программы и применяться в тот момент, когда программа открывается.

Если после покупки появятся какие-либо вопросы, пишите в комментарии — помогу.

Присоединяйся

Зарегестрируйся с помощью социальных сетей.

C# read xml. C# create xml. Работа с xml в Visual Studio

XML — текстовый формат, предназначенный для хранения структурированных данных. По сути – это база данных в текстовом структурированном файле. XML имеет реализации парсеров для всех современных языков программирования и средств разработки.

В Visual Studio существует множество способов работы с xml (все они находятся в пространстве имен System.Xml):

  • XmlTextReader, XmlTextWriter;
  • XmlDocument;
  • Linq.XDocument;
  • Schema.XmlSchema.

На мой взгляд, самый простой, гибкий и интуитивно понятный способ обработки xml файла – с помощью классов XmlTextReader и XmlTextWriter. К тому же он показывает весьма неплохие результаты по скорости работы.

Материал подается последовательно, поэтому если вам нужно просто посмотреть пример работы с xml, можете сразу перейти к интересующему разделу:

Первым делом создадим консольное приложение в Visual Studio. Назовем его XMLReadWrite. Будем изучать чтение и запись xml на C# на примере xml файла, содержащего сведения об авторе и его книгах. Создайте в папке XMLReadWrite \bin\Debug xml-файл author.xml со следующим содержимым:

Подключим в нашем проекте пространства имен:

Для демонстрации примера нам понадобятся два класса: «Автор» и «Книга»:

Класс Author содержит сведения об авторе: ФИО, дата рождения, пол и список книг.

Класс Book содержит идентификатор книги (уникальный в пределах одного автора), название и количество страниц.


C# read xml

Напишем функцию ReadXml по чтению xml файла. На вход подадим имя нашего файла author.xml, на выходе получим прочитанного автора.

На C# read xml осуществляется с помощью класса XmlTextReader. Он доступен во всех версиях .Net Framework, начиная с 1.0. XmlTextReader реализует методы «только вперед», т.е. обеспечивает строго последовательный обход XML-файла. За счет этого достигается весьма хорошая скорость обработки данных.

Примечание: при чтении тега, который подразумевает вложенность, нужно помимо проверки reader.IsStartElement(«Книга») еще проверять, что этот элемент не пустой !reader.IsEmptyElement. Иначе при наличии такой конструкции (т.е. открывающийся тег является и закрывающимся) программа войдет во вложенный цикл и уже не выйдет из него до окончания xml файла.

C# create xml

Теперь напишем функцию WriteXml. На вход подадим имя нового файла newAuthor.xml и сформированный предыдущей функцией Author.

Для создания на C# create xml файла будем использовать класс XmlTextWriter . С помощью него можно задавать параметры форматирования xml. Например, в нашей функции для отступа тегов используется один знак табуляции.

Функция WriteStartDocument() формирует объявление XML. Это строка, указывающая версию XML документа. В версии 1.0 объявление XML может отсутствовать, в версии 1.1 оно является обязательным. Также здесь указывается кодировка символов. В нашем случае функция версия вернет строку

Вложенные теги создаются с помощью функции WriteStartElement(). На каждый WriteStartElement() должен быть закрывающий его WriteEndElement().

В основной функции программы Main создадим экземпляр класса Author, вызовем функцию ReadXml по чтению данных об авторе из xml-файла author.xml, а затем создадим новый файл newAuthor.xml с помощью WriteXml и запишем в него сведения об авторе. По окончании работы программы у нас должно быть два одинаковых xml-файла.

полный листинг программы на C# xml read and create

В конце статьи приведен полный листинг программы:

Подводные камни WPF

Засорение памяти экземплярами ResourceDictionary

Зачастую разработчики явно включают необходимые словари ресурсов прямо в XAML разметке пользовательских элементов управления вот таким образом:

На первый взгляд, в таком подходе нет никакой проблемы — просто для элемента управления указываем минимально необходимый набор стилей. Предположим, в нашем приложении SomeControl существует в 10 экземплярах на одном из окон. Проблема заключается в том, что при создании каждого из этих экземпляров, указанный словарь будет заново вычитываться, обрабатываться и храниться отдельной копией в памяти. Чем больше подключаемые словари, чем больше экземпляров — тем больше уходит времени на инициализацию содержащего их представления и тем больше памяти расходуется впустую. Мне на практике приходилось иметь дело с приложением, в котором перерасход памяти из-за лишних ResourceDictionary был порядка 200 мегабайт.

Мне известно два варианта решения этой проблемы. Первый — подключать все необходимые словари стилей только в App.xaml и больше нигде. Вполне может подойти для небольших приложений, но для сложных проектов может быть неприемлем. Второй — вместо стандартного ResourceDictionary использовать его наследника, который кеширует словари таким образом, что каждый из них хранится в памяти только в одном экземпляре. К сожалению, WPF по какой-то причине не предоставляет такую возможность «из коробки», но ее легко реализовать самостоятельно. Одно из наиболее полных решений можно найти в последнем ответе здесь — http://stackoverflow.com/questions/6857355/memory-leak-when-using-sharedresourcedictionary.

Утечки памяти

Утечки на событиях

Даже в среде с автоматической сборкой мусора можно легко получить утечки памяти. Наиболее частая причина утечек, и не только в WPF проектах — подписка на события без последующего удаления обработчика. Хоть это и не проблема самой технологии, на ней стоит остановиться поподробнее, так как в WPF проектах события используются часто и вероятность появления ошибки высока.

Например, в приложении есть список объектов, свойства которых можно изменять в окне редактирования. Для реализации этого окна понадобилось устанавливать IsModified в true внутри его модели представления при изменении любого свойства редактируемого объекта.

Предположим, модель представления для редактирования реализована так:

Здесь конструктор устанавливает «сильную» ссылку между бизнес-сущностью и моделью представления редактора. Если создавать экземпляр EntityEditorViewModel при каждом показе окна, то такие объекты будут накапливаться в памяти и удалятся только в том случае, если ссылающаяся на них бизнес-сущность станет «мусором».

Один из вариантов решения проблемы — предусмотреть удаление обработчика. Например, реализовать IDisposable и в методе Dispose() «отписываться» от события. Но тут сразу стоит сказать, что обработчики, заданные лямбда-выражениями как в примере, не могут быть удалены простым способом, т.е. вот такое не сработает:

Для правильного решения задачи нужно объявить отдельный метод, поместить в него установку IsModified и использовать в качестве обработчика, как всегда и делалось до появления лямбда-выражений в C#.

Но подход с явным удалением не гарантирует отсутствие утечек памяти — можно банально забыть позвать Dispose(). Помимо этого, может быть очень проблематично определить тот момент, когда нужно его вызвать. В качестве альтернативы можно рассмотреть более громоздкий, но действенный подход — Weak Events. Общая идея их реализации в том, что между источником события и подписчиком устанавливается «слабая» ссылка, и подписчик может быть автоматически удален, когда на него больше не станет «сильных» ссылок.

Объяснение реализации паттерна Weak Events выходит за рамки этот статьи, поэтому просто укажу ссылку, где эта тема рассмотрена очень подробно: http://www.codeproject.com/Articles/29922/Weak-Events-in-C.

Утечки при байндинге

Помимо потенциальной проблемы, описанной выше, в WPF есть как минимум два типа утечек, которые специфичны именно для этой технологии.

Предположим, у нас есть простой объект:

И мы привязываемся к этому свойству из какого-либо элемента управления:

Если свойство, к которому идет привязка, не является DependencyProperty, либо объект, содержащий его, не реализует INotifyPropertyChanged — механизм байндинга использует событие ValueChanged класса System.ComponentModel.PropertyDescriptor для отслеживания изменений. Проблема здесь в том, что фреймворк держит у себя ссылку на экземпляр PropertyDescriptor, который в свою очередь ссылается на исходный объект, и неясно, когда этот экземпляр можно будет удалить. Следует отметить, что в случае с OneTime байндингом проблема не актуальна, так как не нужно отслеживать изменения.

Информация об этой проблеме есть и в Microsoft Knowledge Base: https://support.microsoft.com/en-us/kb/938416, но в ней указано одно дополнительное условие возникновения утечки. Если применить его к предыдущему примеру, то получим, что экземпляр SomeModelEntity должен прямо или косвенно ссылаться на TextBox, чтобы произошла утечка. С одной стороны, такое условие довольно редко выполняется на практике, но в реальности лучше всегда придерживаться более «чистого» подхода — либо явно указывать OneTime режим байндинга, если не нужно следить за изменениями, либо реализовывать INotifyPropertyChanged на объекте-источнике, либо делать свойство DependencyProperty (имеет смысл для свойств визуальных компонентов).

Другая возможная проблема при установке байндингов — привязка к коллекциям, которые не реализуют интерфейс INotifyCollectionChanged. Механизм возникновения утечек в этом случае очень похож на предыдущий. Способ борьбы очевиден — нужно либо явно указывать OneTime режим привязки, либо использовать коллекции, реализующие INotifyCollectionChanged — например, ObservableCollection.

Наследование визуальных компонентов и стили

Иногда возникает надобность в наследовании стандартных элементов управления для расширения их функциональности, изменения поведения. На первый взгляд, это элементарно:

Но если в приложении используются стили элементов, отличные от стилей по умолчанию, проблема при использовании такого наследника будет заметна сразу. Следующий фрагмент скриншота показывает разницу в отображении базового элемента управления и производного при включенной теме PresentationFramework.Aero.

Самый простой способ это исправить — в XAML файле после включения ресурсов темы определить стиль для производного элемента, как унаследованного от базового. Это легко осуществляется с помощью атрибута BasedOn:

Но получается, что при использовании производного элемента управления нужно всегда помнить и о добавлении стиля в ресурсы. Или же сделать файл с этим производным стилем и подключать его каждый раз, когда нужно использовать новый элемент.

Цукерберг рекомендует:  Вакансии Foji

Есть один способ обойтись без изменений в XAML — в конструкторе производного элемента явно устанавливать ему стиль, взятый с базового:

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

Ошибки байндинга

Декларативное связывание элементов управления с полями модели, конечно же, имеет свои преимущества, но за его целостностью не так уж просто следить. Если по какой-то причине свойство, указанное в байндинге, не найдено — ошибка будет написана в лог отладки… И всё. По умолчанию пользователь не увидит никаких сообщений, при запуске без отладки ни в каких логах этих ошибок не будет.

Чтобы сделать такие ошибки более заметными для разработчика, можно написать специальный Trace Listener, который будет выводить их в виде сообщений:

И затем активировать его при старте приложения:

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

Стандартные средства валидации

В WPF существует несколько способов валидации данных.

ValidationRule — наследуя этот класс можно создавать специализированные правила валидации, которые затем привязываются к полям в XAML разметке. Из «условных» плюсов — не требуются изменения классов модели для выполнения валидации, хотя в некоторых случаях это может быть не самым оптимальным вариантом. Но при этом есть значительный недостаток — ValidationRule не наследует DependencyObject, соответственно в наследниках нет возможности создавать свойства, на которые в последствии можно будет байндиться. Это означает, что нет простого очевидного способа производить валидацию свойств в связке друг с другом — например, если значение одного не может быть больше значения другого. Валидационное правило, реализованное таким способом, может иметь дело только с текущим значением поля и фиксированными значениями свойств, которые были указаны при создании экземпляра этого правила.

IDataErrorInfo, INotifyDataErrorInfo — реализуя эти интерфейсы в классах моделей представления можно легко осуществлять валидацию как отдельных свойств, так и нескольких свойств в связке друг с другом. Обычно для уменьшения количества кода один из этих интерфейсов реализуют в базовом классе моделей и предоставляют средства лаконичного описания правил в наследниках. Например, через регистрацию правил в статическом конструкторе для каждого из типов:

Или через атрибуты:

Но и подход с использованием DataErrorInfo интерфейсов не покрывает все валидационные задачи — в случаях, когда для проверки правила нужно иметь доступ к объектам за пределами валидируемой сущности, начинают возникать проблемы. Например, проверка на уникальность требует доступа к полной коллекции объектов, а это означает что каждый элемент такой коллекции должен иметь ссылку на нее, что сильно усложняет работу с объектом.


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

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

А также пример использования:

Таким образом, все валидационные правила находятся внутри самой сущности. Те из них, которые не требуют «внешних» объектов, используются в реализации IDataErrorInfo из базового класса. Для проверки остальных достаточно позвать функцию Validate в нужном месте и использовать результат для принятия решений о дальнейших действиях.

Неправильное использование события PropertyChanged

Мне довольно часто приходилось встречать код подобного вида в WPF проектах:

Причем во многих случаях это был обработчик собственных событий, т.е. «слушал» изменения свойств того же класса, где и был объявлен.

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

Можно сформулировать следующий критерий для самопроверки, правильно ли используется обработчик события PropertyChanged: если алгоритм внутри обработчика не зависит от конкретных названий свойств, то все в порядке. В противном случае нужно искать более удачное решение. Примером правильного применения может быть, например, установка свойства IsModified в true при изменении какого-либо свойства модели представления.

Избыточное использование Dispatcher

Неоднократно встречал в WPF проектах принудительное выполнение операций на UI потоке даже в тех случаях, когда это не нужно. Для того, чтобы описать масштаб проблемы, приведу пару цифр, полученных с помощью простых тестов на ноутбуке c процессором Core i7-3630QM 2.4GHz:

  • Время, затраченное Dispatcher.Invoke сверх «полезной» нагрузки при вызове из того же потока, к которому принадлежит Dispatcher — 0.2 мкс на один вызов.
  • Тот же показатель, но при вызове из другого потока — 26 мкс на вызов.

Первая цифра не выглядит страшной, но и вызывать что-то через Dispatcher, когда известно, что код и так будет выполняться на UI потоке — тоже неправильно. А вот вторая цифра уже выглядит заметной. Следует учесть, что в реальных сложныx приложениях, особенно при диспетчеризации с нескольких параллельных потоков, это время может быть значительно больше. А на более слабых устройствах — еще больше.

Чтобы уменьшить вред для производительности, достаточно придерживаться простых правил:

  • Диспетчеризировать только то, что действительно нельзя выполнить на фоновом потоке. Например, есть кусок кода, который что-то читает из WEB-сервиса, потом делает расчет по какому-то алгоритму, потом устанавливает пару свойств на модели представления. В этом случае только установка свойств должна диспетчеризироваться (т.к. в свою очередь вызывает обработчики PropertyChanged, среди которых есть код, работающий с UI).
  • Избегать циклов, внутри которых есть обращение к Dispatcher. Например, нужно прочитать список с сервера, и по данным каждого элемента сделать обновление UI. В этом случае лучше сначала просчитать на фоновом потоке все, что нужно будет обновлять на UI, и только потом одним вызовом Dispatcher.Invoke сделать обновление. Вызов Invoke после обработки каждого элемента списка будет крайне неоптимальным решением.

Модальные диалоги

Использование стандартных модальных сообщений (MessageBox) в WPF проектах не приветствуется, так как кастомизировать их внешний вид в соответствии с визуальными стилями приложения попросту невозможно. Вместо стандартных сообщений приходится писать свои реализации, которые можно условно разделить на два типа:

  • Отдельное модальное окно (Window.ShowDialog), стилизованное нужным образом.
  • «Эмуляция» модального окна через добавление панели в визуальное дерево основного окна, которая находится «над» всем остальным содержимым, тем самым перекрывая его.

У каждого подхода есть свои плюсы и минусы. Первый вариант прост в реализации, но не позволяет достичь таких эффектов, как «затемнение» всего содержимого окна, над которым показывается модальный диалог. В некоторых приложения может возникнуть надобность в диалоге нестандартной формы, что с обычным окном сделать не совсем просто.

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

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

Рассмотрим одну из наиболее простых реализаций «эмулированного» диалога.

В первую очередь объявим интерфейс менеджера диалогового окна, через который модель представления будет показывать диалоги. Для начала не будем учитывать возможность получать «ответ» от окна — просто покажем диалог с кнопкой «Закрыть».

Далее реализуем элемент управления, который будет «привязываться» к менеджеру и показывать окно поверх остальных элементов, когда это необходимо:

Опять же, для упрощения, этот контрол рассчитан на то, что в модели представления есть экземпляр реализации IModalDialogHelper в свойстве DialogHelper. В более универсальном решении должна быть возможность подставлять любое свойство.

Я не буду здесь приводить пример простейшей реализации IModalDialogHelper, так как она очевидна: методы Show() и Close() устанавливают соответствующим образом IsVisible, команда CloseCommand просто вызывает метод Close(). Show() еще устанавливает свойство Text.

Вроде бы все просто: вызываем метод Show() с нужным текстом сообщения, он делает видимым панель с сообщением и кнопкой, последующее нажатие на кнопку Close устанавливает IsVisible в исходное значение и «диалог» пропадет с экрана. Но тут уже есть первая проблема — последовательный показ нескольких сообщений приводит к тому, что пользователь видит только последнее, так как метод Show() не ожидает закрытия предыдущего диалога.

Для решения этой проблемы немного изменим прототип метода Show:

Возможность ожидать завершения этого метода через await дает стразу несколько преимуществ:

  • Показ нескольких сообщений подряд с одного и того же потока будет корректно работать, в отличие от предыдущего примера.
  • Можно реализовать метод так, что даже вызов сообщения из разных потоков будет работать корректно и дожидаться закрытия уже показанного диалога.
  • Можно возвращать модальный результат как в «старом» MessageBox.Show().

Тут я приведу один из вариантов реализации интерфейса IModalDialogHelper с асинхронным Show, которая соответствует указанным выше пунктам (хоть в данной реализации всегда возвращается один и тот же модальный результат, сделать его зависимым от нажатой кнопки не составит труда).

Основная идея этого решения заключается в том, что для каждого вызова Show создается экземпляр TaskCompletionSource. Ожидание задачи, созданной внутри него будет продолжаться до тех пор, пока не указан результат через вызов SetResult. Show до показа своего сообщения ждет все задачи, которые уже есть в очереди, после показа — ждет свою собственную, а Close устанавливает результат выполнения текущей задачи, тем самым завершая ее.

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

Проблема в том, что e.Cancel всегда будет true для кода, вызвавшего Window_Closing, так как await не останавливает выполнение потока, а создает возможность «вернуться» в нужное место в методе после завершения асинхронной задачи. Для вызвавшего кода, Windows_Closing завершится сразу после установки e.Cancel в true.

Правильное решение заключается в том, что тело условия должно оперировать уже не e.Cancel, а явно вызывать «отмененное» действие таким образом, чтобы оно гарантированно выполнилось без дополнительных запросов, минуя повторный вызов этого обработчика. В случае закрытия главного окна программы, например, это может быть явный вызов завершения всего приложения.

Анализ производительности отображения

Многие разработчики знают, что такое «профайлер» и знают, какие есть средства для анализа производительности приложения и анализа потребления памяти. Но в WPF приложениях часть нагрузки на процессор исходит, например, из механизма обработки XAML разметки – парсинг, разметка, рисование. «Стандартными» профайлерами непросто определить, на какую именно активность, связанную с XAML, тратятся ресурсы.

Не буду подробно останавливаться на возможностях существующих инструментальных средств, просто перечислю ссылки на информацию о них. Разобраться с тем, как ими пользоваться, не составит труда любому разработчику.

  • Наиболее развитые средства по отладке и профилированию WPF приложений включены в Visual Studio 2015 — http://blogs.msdn.com/b/wpf/archive/2015/01/16/new-ui-performance-analysis-tool-for-wpf-applications.aspx
  • Для более старых версий Visual Studio можно воспользоваться WPF Performance Suite — https://msdn.microsoft.com/en-us/library/aa969767%28v=vs.110%29.aspx

И еще немного о INotifyPropertyChanged

Одна из самых популярных тем споров в рамках технологии WPF — как наиболее рационально реализовывать INotifyPropertyChanged. Самый лаконичный вариант — использовать АОП, как я уже описывал в одном из примеров в статье об Aspect Injector. Но не всем этот подход нравится, и в качестве альтернативы можно использовать сниппеты. Но тут возникает вопрос о наиболее оптимальном содержимом сниппета. Сперва приведу примеры не самых удачных вариантов.

В данном случае имя свойства указано константой, и не важно — будет оно в именованной константе или, как в примере, «захардкоджено» прямо в вызове метода оповещения — проблема остается той же: при переименовании самого свойства существует вероятность оставить старое значение константы. Эту проблему многие решают следующим изменением метода NotifyPropertyChanged:

В этом случае вместо названия можно указать лямбда-выражение, возвращающее нужное свойство:

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

В .NET 4.5 стал доступным специальный атрибут CallerMemberNameAttribute, благодаря которому можно решить первую из приведенных выше проблем:

Если параметр, помеченный этим атрибутом, не указан явно, компилятор подставит в него имя члена класса, вызывающего метод. Таким образом вызов NotifyPropertyChanged() из примера выше равнозначен NotifyPropertyChanged(“Name”). Но что делать, если нужно сообщить об изменении какого-либо свойства «снаружи», не из его сеттера?

Например, у нас есть «калькулируемое» свойство:

При добавлении, удалении или изменении элементов коллекции items нам нужно сообщать об изменении TotalPrice, чтобы интерфейс пользователя всегда отображал его актуальное значение. Учитывая недостатки первых двух решений, приведенных выше, можно сделать следующий ход — все-таки использовать Reflection для получения имени свойства из лямбда-выражения, но сохранять его в статической переменной. Таким образом для каждого отдельно взятого свойства «тяжелая» операция будет выполняться только один раз.

Саму статическую функию GetPropertyName можно положить и в базовый класс для всех «notifiable» сущностей — это не принципиально. Проверка на UnaryExpression нужна, чтобы функция нормально обрабатывала свойства значимых типов, т.к. компилятор добавляет операцию боксинга, чтобы привести указанное свойство к object.


Если ваш проект уже использует C# 6.0, то ту же задачу получения имени другого свойства можно решить намного проще — с помощью ключевого слова nameof. Надобности в статической переменной, которая запоминает имя, уже не будет.

В качестве итога можно сказать, что если использование АОП для INotifyPropertyChanged по каким-либо причинам не устраивает, то можно воспользоваться сниппетами следующего содержания:

  • Если проект еще не перешел на использование .NET 4.5 — для каждого свойства добавлять статическое поле, которое при инициализации будет заполняться именем свойства через функцию GetPropertyName, как показано выше. A cеттер, в свою очередь, будет передавать в NotifyPropertyChanged значение этого поля.
  • Если .NET 4.5 уже используется — то для большинства свойств будет достаточно решения с CallerMemberNameAttribute. А для тех случаев, когда этого решения недостаточно — подойдет либо вариант со статическим полем имени свойства, либо ключевое слово nameof, если проект уже использует C# 6.0.

Вместо послесловия

WPF — неплохая технология, которую Microsoft по-прежнему позиционирует как основной фреймворк для разработки «настольных» приложений. К сожалению, при написании программ сложнее «калькулятора» обнаруживается ряд проблем, не заметных с первого взгляда, но все они решаемы. Согласно недавним заявлениям Microsoft, они инвестируют в развитие технологии, и в новой версии уже есть много улучшений. В первую очередь они относятся к инструментальным средствам и производительности. Хочется надеяться, что в будущем новые возможности будут добавлены не только в инструментальные средства, но и в сам фреймворк, облегчая работу программиста и избавляя от «хаков» и «велосипедов», которые приходится делать сейчас.

UPD: изменил второе решение в разделе «Наследование визуальных компонентов и стили» на более оптимальное из комментариев и добавил в раздел о INotifyPropertyChanged решение с nameof() для C# 6.0

UPD2: изменил пример реализации хелпера для модального диалога на более лаконичный с использованием TaskCompletionSource.

Programming stuff

Страницы

вторник, 17 марта 2009 г.

Многопоточность в Windows Forms. Control.Invoke().

public partial class Form1 : Form

//на форме расположен TextBox и Button.

//В TextBox будет выводиться количество сработок таймера,

//таймер запускается по нажатию на кнопку Button

timer = new Timer ( AsyncHandler );

private void button1_Click ( object sender , EventArgs e )

timer . Change (1000, 1000);

private void AsyncHandler ( object data )

textBox1 . Text = tickCount . ToString ();

private readonly System . Threading . Timer timer ;

private int tickCount ;

private void AsyncHandler ( object data )

Action int > action = DoChangeTicks ;

Invoke ( action , tickCount );

private void DoChangeTicks ( int count )

textBox1 . Text = tickCount . ToString ();

private void AsyncHandler ( object data )

Action action = () => textBox1 . Text = tickCount . ToString ();

/// Расширения облегчающие работу с элементами управления в многопоточной среде.

public static class ControlExtentions

/// Вызов делегата через control.Invoke, если это необходимо.

Делегат с некоторым действием

public static void InvokeIfNeeded ( this Control control , Action doit )

if ( control . InvokeRequired )

control . Invoke ( doit );

/// Вызов делегата через control.Invoke, если это необходимо.

/// Тип параметра делегата

Делегат с некоторым действием

Аргумент делагата с действием

public static void InvokeIfNeeded T >( this Control control , Action T > doit , T arg )

if ( control . InvokeRequired )

control . Invoke ( doit , arg );

private void AsyncHandler ( object data )

() => textBox1 . Text = tickCount . ToString ()

10 комментариев:

Прикольно! Блин, как много нужно прочитать.

Хорошей альтернативой которую можна использовать не только в Windows Forms а всюда где надо маршалить вызовы между потоками будет SynchronizationContext .

Конечно, согласен. Но, как и во многих других вопросах, специализированные решения оказываются более простые в рамках одной задачи.
Здесь тоже самое. Способ, описанный выше — один из самых удобных способов работы с многопоточностью в Windows Forms, но при этом он не универсален.
Хотя знание общих подходов и принципов также весьма полезно.

Боюсь, что для того чтобы использовать SynchronizationContext в других сферах кроме WinForms и WPF придется изрядно попотеть, т.к. сам по себе класс SynchronizationContext не предоставляет нужную функциональность для маршалинга вызовов в определенный поток. В случае Send() он использует ThreadPool.QueueUserWorkItem, а в случае Post() вызывает метод в том же потоке. Поэтому если хочется иметь возможность делать маршалинг вызова в определенный поток, то придется этот механизм реализовывать вручную. В .net есть только 2 готовых реализации — для WinForms (WindowsFormsSynchronizationContext) и для WPF (DispatcherSynchronizationContext). Кстати, WindowsFormsSynchronizationContext реализован именно через механизм Control.BeginInvoke.

Как вариант, мне больше нравится:
this.Invoke(new EventHandler(delegate
<
textBox1.Text = tickCount.ToString()
>));
Подсмотрено на http://www.codeproject.com/KB/threads/ThreadingDotNet2.aspx


Из плюсов нет необходимости в дополнительных классах а логика программы так-же прозрачна

Ну, твой код ничем не отличается от приведенного:
Action action = () => textBox1.Text = tickCount.ToString();
if (InvokeRequired)
<
Invoke(action);
>
else
<
action();
>
Только используется синтаксис анонимных делегатов из C# 2.0, а этот вариант использует синтаксис C# 3.0.
Причем, если рассмотреть приведенный мною вариант без проверки на InvokeRequired, то код будет таким:

Цукерберг рекомендует:  Архитектура веб-сервисов

Action action = () => textBox1.Text = tickCount.ToString();
textBox.Invoke(action);

Что, как по мне, короче, понятнее и красивее:)

2Денис: чем тебе не нравится новый синтаксис анонимных делегатов в C#3.0?

«чем тебе не нравится новый синтаксис анонимных делегатов в C#3.0?»

Тем, что это синтаксис 3.0 ! FrameWork 3.0 не поддерживается на Windows 2000, поэтому приходится писать на FrameWork 2.0

2Drakosha: а откуда Вы знаете под какую винду Денис пишет код?
Я же не говорил абстрактно, я задавал вопрос конкретному человеку, который, насколько я помню пишет именно под .net 3.5 :)

У меня вопрос. Уже во втором посте я вижу, что вы пытаетесь заменить отдельные функции лямбдами. Я же читал (честно — не помню где), что более «православно» разделять функционал на как можно более мелкие функции и стремиться к тому, чтобы код фукции влазил на один экран. Лично мне тоже проще понять, что происходит в фукции, если она маленькая.

Учитывая это, могли бы вы объяснить свой подход?
Спасибо.

H Реализация Drag and Drop на языке C# в Visual Studio в черновиках Из песочницы Tutorial

.collapse»>Содержание

Вступление

Доброго времени суток, уважаемые хабрчане. Данный пост не будет особо отличать оригинальностью, уникальностью или гениальностью. Я бы назвал его руководство по пользованию. Думаю многие бывалые программисты сделают множество замечаний, за что я в целом буду только благодарен, тем более если это будет конструктивная критика. Но, в целом, мой пост ориентирован больше на начинающих программистов, так как бывалые скорее всего сталкивались с такой задачей и уже решили её сами.

Итак, о чем же будет сегодняшний наш разговор. Как вы поняли из названия, я расскажу как реализовать Drag and Drop на языке C# в Visual Studio. Думаю многие начинающие программисты сталкивались с такой проблемой, когда существует несколько списков и вы хотите перетащить элементы из одного в другой, но придумать как это сделать или найти понятный мануал не могли. И ведь так хочется, чтоб в вашем приложении было все красиво и современно, а приходилось обходится простым выбором элемента и переносом его в другой по нажатию на кнопку. Надеюсь сегодня этим простым руководством я смогу всё-таки помочь парочек юных бойцов(я и сам такой, как мне кажется) и развеять любые проблемы связанные с реализацией данного функционала.

Хочу заметить, что я не буду подробно рассматривать как найти или добавить тот или другой элемент на форму, не буду также подробно описывать свойства объектов.

С чего все начиналось

Вкратце расскажу с чего все начиналось и что мы с вами должны будем сделать(ТЗ). Началось всё с того, что моей задачей стала реализация автомата с напитками, причём полная реализация, с учетом всех нюансов, таких как замена напитков, их цен, пополнение кассы автомата без использование кода и многое другое, что могло быть опущено при других обстоятельствах. Но я подумал, если делать, то максимально реалистичнои решил добавить drag and drop денег из кошелька в слот для денег с чем пришлось изрядно помучатся, но что придало моей программе изюминку.

Техническое задание

У нас имеется два объекта: ListView, который представляет наш кошелёк и ListBox, в котором при перетаскивании будет появляться название купюры либо монеты. Необходимо создать программу, которая позволит перетаскивать элементы из объекта ListView в ListBox без дополнительных кнопок.

Ну, что ж, вызов принят. Приступим.

Шаг 1 Создание рабочей области

Создаем новый проект Windows Form Applicarion и добавляем на форму следующие элементы:

  1. ListView. Наш кошелёк откуда мы будем перетаскивать денежку. Напомню, что все элементы будут представлены в виде изображений монет и купюр.
  2. ListBox. Список, куда мы будем всё это перетаскивать, в котором будут отображаться названия номиналов.
  3. ImageList. Именно отсюда мы получим наши изображения денег.
  4. Label. Вспомогательный элемент, который будет показывать в какую позицию будет добавлено название в ListBox.

Шаг 2 Подготовка элементов

Добавляем в ImageList картинки отсюда. Называем их так, чтоб вам потом было понятно, где какая картинка. Позже поймете для чего. В свойствах ListView есть поле View, я выбрал режим просмотра Large icon, но вы можете выбрать Small icon. В зависимости от выбора в поле LargeImageList или SmallImageList выбираете имя вашего объекта ImageList. Но это еще не всё. Теперь открываем свойство Items для всё того же ListView и добавляем новый элемент. Для него в поле значение ImageIndex изображение, а в поле Tag прописываем текст, согласно номиналу на изображении. И так добавляем все необходимые нам элементы.
Теперь все картинки отображаются в ListView и имеют «название»(Tag). Настраиваем по размерам все объекты и балуемся настройками внешнего вида на свой вкус. Советую каждый элемент называть так, чтоб было понятно для чего он.
Вот что получилось у меня:

Шаг 3 Код

Пришло время самой важной и самой сложной части. В целом, скопировать и вставить будет не сложно, но важно понять код! Выжпрограммисты;)

Добавляем события для объектов.
Для ListView:

  1. MouseDown
  2. MouseUp
  3. MouseMove

Для ListBox:

  1. DragOver
  2. DragDrop
  3. DragEnter
  4. DragLeave

Теперь всё готов для написания кода. Включаем внимательность, отключаем мобильные телефоны и другие отвлекающие факторы(кота тоже можно отключить).
В первую очередь добавим в начало класса переменные, которые нам пригодятся в дальнейшем. Описывать их не буду, так как их предназначение вы поймете в коде.

ListView MouseDown

Это событие будем происходить в тот момент, когда вы нажмете на левую кнопку мыши в объекте ListView.

ListView MouseUp

Отпустив кнопку мышь мы автоматически «бросаем» объект.

ListView MouseMove

Двигая мышку мы вызываем это событие, причём работать оно начинает только если мы вышли за пределы нашего «кошелька».
Хочу обратить ваше внимание на строку:

Ее можно так же запрограммировать не только на удаление, но и на уменьшение количества таких элементов в списке, если их несколько. В данном случае всё зависит от цели и вашей фантазии. Выбор действия(перемещение или копирование) описан в части DragOver.

ListBox DragOver

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

  • По умолчанию все элементы будут перемещаться
  • При зажатом Ctrl все элементы будут копироваться
ListBox DragDrop

Добавление перетаскиваемого объекта в новый список. Здесь самое важное это аргумент sender, который является нашим перетаскиваемым элементом. И здесь снова включается ваша фантазия. В данном случае, я просто получаю значение Tag из полученного объекта(помните мы добавляли в поле Tag названия номиналов?). Точно таким же образом вы можете реализовать всё, что пожелает ваша душа.

ListBox DragEnter,DragLeave

Наконец, самое последнее, это «сброс» нашего Label. Так как если этого не сделать, то он продолжить нам показывать в какое место списка будет добавлен файл, даже если файл уже добавлен.

Заключение

Остается только запустить приложение и удостовериться, что всё работает(не забудьте протестировать программу с зажатым Ctrl). Теперь, сделав всё написанное выше, вы сможете адаптировать этот код под свои цели. Добавить счетчики для подсчета объектов, перетаскивать объекты не только из списков в списки, но и многое другое теперь можно реализовать в кратчайшие сроки.

Задание на дом

1. Добавьте учет количества монет в ListView(с помощью счетчика или любым другим удобным способом). Реализуйте не удаление монеты из ListView, а уменьшение их количества.
2. Добавьте любой новый объект(какой именно вы должны определить сами) и перетащите в него изображение из ListView. Каждое новое перетаскивание должно удалять предыдущее изображение.
Примечание: Можно добавить сразу ListView и добавлять в него фото в виде новых элементов. Не забудьте учесть, что если монетка(купюра) были добавлены ранее, то необходимо не добавлять новый элемент, а увеличить количество старых элементов.

На этом я заканчиваю свое руководство, надеюсь, что оно кому-то будет полезным. Спасибо за внимание!


Есть ли способ создать формат файла?

Я создаю собственный формат файла для приложения, которое я написал в C # .NET, для хранения информации о сохранении и, возможно, для активов проекта линии. Существует ли какой-либо стандарт о том, как это сделать? Я просто перешел в Serialize мои объекты в двоичный файл и создал заголовок, который расскажет мне, как разбирать файл. Это плохой подход?

4 ответа

Самый простой метод — это, вероятно, сериализация вашей структуры в XML с помощью XMLSerializer . Вам, вероятно, не нужно будет создавать отдельную структуру заголовка и тела, но сериализуйте все активы в XML. Это позволяет вам легко проверять /редактировать файловую структуру вне вашей собственной программы и легко управляться.

Однако, если ваша файловая структура действительно сложна, она содержит много разных активов разных типов, так что сериализация всей структуры в XML слишком обременительна, вы можете посмотреть на сериализацию каждого актива отдельно и скомпилировать их в один пакет, используя Packaging на C #. По сути, это то, как создаются форматы .docx, .xslx, .pptx и другие форматы офисных файлов.

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

Сделайте волшебный номер очень уникальным, чтобы детекторы формата файла людей для других форматов не ошибочно идентифицировали его как ваш. Если вы используете двоичный код, выделите 8 или 16 случайно сгенерированных байтов в начале двоичного формата для магического номера. Если вы используете XML, выделите правильное пространство имен в своем домене, чтобы он не мог столкнуться с другими людьми. Если вы используете JSON, бог вам поможет. Может быть, кто-то сейчас разобрал решение этой мерзости формата.

Планирование обратной совместимости. Сохраните номер версии формата так или иначе, чтобы более поздние версии вашего программного обеспечения могли иметь дело с различиями.

Если файл может быть большим или есть разделы, которые люди могут пропустить по какой-то причине, убедитесь, что есть хороший способ сделать это. XML, JSON и большинство других текстовых форматов особенно ужасны для этого, потому что они заставляют читателя анализировать все данные между начальным и конечным элементами, даже если они не заботятся об этом. EBML несколько лучше, потому что он хранит длину элементов, позволяя вам пропустить весь путь до конца. Если вы создаете собственный двоичный формат, существует довольно распространенная конструкция, в которой вы храните идентификатор фрагмента и длину, как первую вещь в заголовке, а затем читатель может пропустить весь фрагмент.

Сохраните все строки в UTF-8.

Если вам нужна долгосрочная расширяемость, сохраните все целые числа в форме переменной длины.

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

Хорошо, бывают моменты, которые вы описываете, могут быть очень плохим подходом. Это предполагает, что когда вы говорите «сериализовать», вы говорите об использовании способности языка /рамки просто брать объект и выводить его непосредственно на какой-то двоичный поток. Проблема заключается в изменении структуры классов за эти годы. Сможете ли вы перезагрузить файл, сделанный в предыдущей версии вашего приложения, если все ваши классы меняются в более новом?

Для обеспечения долговременной стабильности формата файла, я нашел, что лучше немного свернуть рукава и конкретно написать собственные методы «сериализации» /«потокового» в ваших классах. т.е. вручную обрабатывать запись значений в поток. Напишите заголовок, когда вы укажете, что описывает версию формата, а затем данные, которые вы хотите сохранить в том порядке, в котором вы хотите. На стороне чтения обработка различных версий формата файла становится намного проще.

Другим вариантом, конечно же, является XML или JSON. Не обязательно самый большой для бинарного тяжелого контента, но простой и понятный для человека . большой плюс для долгосрочной жизнеспособности.

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

Я лично реализовал несколько форматов файлов для своей работы, и я перешел к использованию формата XML-файла. Мои требования и аппаратные средства, с которыми я взаимодействую, постоянно меняются, и я не знаю, что мне нужно будет добавить в формат в будущем. Одним из основных преимуществ XML является то, что он полуструктурирован . По этой причине я вообще избегаю автоматической XML-сериализации, которую предоставляет .NET, потому что я считаю, что она заставляет его ожидать точный формат.

Моя цель заключалась в создании формата XML, который позволял добавлять новые элементы и атрибуты в будущем, и чтобы порядок тегов не имел значения, когда это возможно. Если вы уверены, что можете загрузить весь свой файл в память, то XPATH , вероятно, хороший выбор.

Если вы имеете дело с особенно большими файлами или по другим причинам не можете загрузить файл все сразу, то вам, вероятно, остается использовать XmlStreamReader и сканировать известные элементы и рекурсировать в эти элементы с помощью ReadSubtree и снова проверять. .

Введение в C# (C Sharp): программирование простым языком

Начинаем писать статьи направленные на формирование представления о простейших составляющих написания кода для людей. Сегодня материал для тех, кто только начавших изучение языка C# Sharp (Си Шарп). Всяк ступивший на стезю сотворения алгоритма да не убоится неизвестности, бардака и самозабвения.

О языке программирования C#

Каждый человек, решивший обучиться написанию кода рано или поздно сталкивается с необходимостью посмотреть в справочнике информацию касательно какой-либо функции. И в большинстве случаев издание очень расстраивает из-за своей научности.

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

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

С# (С Sharp, Си Шарп) – объектно-ориентированный язык программирования. Что это означает? Объект – участок кода, содержащий в себе данные и инструкции по их обработке.

Пример

Объект «попугай» содержит в себе данные о сытости и настроении, действия «есть», «подражать голосу хозяина» и «кусаться». Будет птица дразниться или кусаться зависит от текущего настроя: если питомец весел, то он скорее будет играть, чем травмировать своего кормильца.

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

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

Алгоритмы и компиляторы

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

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

Прежде всего, компиляторы (программы, в которой пишутся программы) очень чувствительны к регистру. Все операторы, переменные и команды нужно запоминать и писать в точности так, как они написаны в справочниках. То есть, переменная a и переменная A – совершенно разные переменные, а если будет написана строчка console.writeline(“”); вместо Console.WriteLine(“”); то будет выведена ошибка и, если повезет, правильно указано ее местоположение.

Пунктуация

Следующий «подводный камень» — пунктуация. Ситуация сравнима с диктантом по русскому языку у придирчивого преподавателя. Пропустите знак хоть в одном месте – программа откажется работать.

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

Для начала разберемся с основными значками:

  • Знак «;»
  • Знаки «//» и пара «/*» и «*/»
  • Знаки «< >»
  • Знаки «» «»

Знак «;» прописывается в конце строки. Он обозначает для компьютера конец команды и разрешение приступить к следующей. Его смысл аналогичен точке в конце предложения: «Я есть Грут; Грут самый лучший юморист; Правда ли он симпатяга;».

Да, с эмоциями здесь натянуто. Впрочем, можно высказаться внутри знаков «//» и «/* */». Первый используется для заметок размером в одну строку, второй нужен для более распространенного текста. Они говорят компьютеру, что содержимое внутри пространства, обрамленного такими значками, не имеет к нему никакого отношения. Программист заключает в них комментарии, помогающие при отладке кода. «< >» нужны для обозначения границ конкретно взятого объекта.

Грубо говоря, их можно сравнить с обложкой тетради. Их функция – заключения внутри себя участка кода. Они являются привычным атрибутом многострочного программного текста, заключенного внутри команды. А парочка «” “» используется внутри текстовых операторов для помещения непосредственно текста для выведения на экран.

Начало программы

Каждая программа начинается со строк using. Это библиотека. Если перевести на понятный язык, using присоединяет к программе особую библиотеку, в которой хранятся команды с описанием выполняемых действий по запросу.

Так, Console.WriteLine хранится в библиотеке System.Text, в которой сказано, что программа должна вывести на экран текст внутри кавычек. Минимальный набор выглядит таким образом:

Следующая немаловажная деталь – Main(). В переводе с английского «главный», что прямо намекает на его назначение. Исполнение алгоритма начинается с кода, заключенного внутри Main().

Текст внутри данного оператора можно сравнить с главной страницей сайта. Сюда записывается основная последовательность действий, сопроводительная информация и ссылки в другие части программы. В показанном примере главное тело присутствует с характеристикой void.

Это включение предполагает, что программа, исполнив свою инструкцию, удалит все данные. Напоминает вывеску в столовой: «Поел – убрал за собой». Напоследок можно разобрать две простейшие команды: Console.WriteLine и Console.ReadLine.

Console.WriteLine(“”); призвана вывести на экран текст, заключенный внутри кавычек. Пример с этим оператором разобран в скриншоте выше, поэтому сразу перехожу к другой команде.

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

Заключение

Подытожим. Теперь нам известны основные правила синтаксиса, а также мы получили образное представление о базовых элементах кода. Неплохо для одного дня. Для тех кто программирует Ардуино нужно понимать, что этот микроконтроллер программируется языком C++. Но мы все знаем, что изучив даже один язык программирования довольно легко выучить и другие. Всем хорошего настроения. Дорогу осилит идущий.

Понравилась статья? Поделиться с друзьями:
Все языки программирования для начинающих