Почему появилась эта публикация?
Недавно пришла мысль в голову: пора переходить на использование WPF! Ну и, соответственно, изучить надо его, чтобы также «виртуозно» использовать, как и WinForms. Заодно и более старшим, консервативным, коллегам доказать, что WPF использовать более эффективно и продуктивно. (И ПО на WPF работает «шутстрее».)
Вот и решил я этой публикацией «мешок зайцев настрелять»:
— Сравнить разработку компонента на WinForms (Ссылка на статью) и WPF;
— Доказать коллегам, что WPF – это продуктивно и эффективно;
— И сделать небольшой простой урок по освоению WPF (особенно для тех, кто привык к WinForms).
Изучение WPF для тех, кто с WinForms
В прошлой публикации ссылка я рассказал о разработке компонента на WinForms. Поэтому, цель следующая: сделать такой же «по-смыслу» компонент, но на WPF. В целом, подход такой же и советы для WinForms работают и на WPF.
Забегая вперёд, получился следующий компонент, представленный на рисунке ниже.
Компонент (далее – «dpkEditWPF»), так же как и его «собрат» на WinForms является «partial» (разделён на несколько файлов (partial class), для удобства разработки).
У него также есть Свойство «Значение слова ДПК» (32 разряда) и «Текстовая метка» (чтобы там время отображать). Событие клика по «битовой ячейке» с номером бита также имеется, но только оно стало «маршрутизируемым».
/*Общедоступные свойства, события, генераторы событий*/ public partial class DpkWordEditWPF { /// <summary> /// Значение слова ДПК (32 разряда) /// </summary> uint _dpkValue; /// <summary> /// Свойство - Значение слова ДПК (32 разряда) /// </summary> public uint DpkValue { get { return _dpkValue; } set { _dpkValue = value; Paint(); InvalidateVisual(); } } /// <summary> /// Текстовая метка (добавляется к текстовому значению слова ДПК) /// </summary> string _txtMark; /// <summary> /// Свойство - Текстовая метка (добавляется к текстовому значению слова ДПК) /// </summary> public string TextMark { get { return _txtMark; } set { _txtMark = value; Paint(); InvalidateVisual(); } } /******/ /// <summary> /// Событие - клик по значению /// </summary> public event ReturnEventHandler<int> ClickByValue; /// <summary> /// Генератор события клик по значению /// </summary> /// <param name="index">номер бита (0-31)</param> void OnClickByValue(int index) { if (ClickByValue != null) ClickByValue(this, new ReturnEventArgs<int>(index)); } }
Расчёт размеров dpkEditWPF также – относительный, на основе текущих размеров.
/// <summary> /// Установка пропорций /// </summary> void SetProportions() { _hPropTextMark = 0.2; _hPropAddress = 0.2; _hPropAddressBinVal = 0.2; _hPropData = 0.2; _hPropDataBinVal = 0.2; } /// <summary> /// Установка размеров /// </summary> void SetSizes() { /*TextMark*/ _heightTextMark = RenderSize.Height * _hPropTextMark; /*Address*/ _heightAddress = RenderSize.Height * _hPropAddress; /*AddressBinValue*/ _heightAddressBinVal = RenderSize.Height * _hPropAddressBinVal; _widthCellAddressBV = RenderSize.Width / 8.0; /*Data*/ _heightData = RenderSize.Height * _hPropData; /*DataBinValue*/ _heightDataBinVal = RenderSize.Height * _hPropDataBinVal; _widthCellDataBV = RenderSize.Width / 24.0; /*points*/ _ptTextMark = new Point(0,0); _ptAddress = new Point(0,_heightTextMark); _ptAddressBinVal = new Point(0, _heightTextMark + _heightAddress); _ptData = new Point(0, _heightTextMark + _heightAddress + _heightAddressBinVal); _ptDataBinVal = new Point(0, _heightTextMark + _heightAddress + _heightAddressBinVal + _heightDataBinVal); }
Отрисовка компонента также разделена на несколько визуальных буферов и соответственно -процедур отрисовки.
/// <summary> /// визуальный Буфер значения слова ДПК + текстовая метка /// </summary> DrawingVisual _imgTextMark; /// <summary> /// визуальный буфер значения адреса /// </summary> DrawingVisual _imgAddress; /// <summary> /// визуальный буфер двоичного значения адреса (кликабельные ячейки) /// </summary> DrawingVisual _imgAddressBinVal; /// <summary> /// визуальный буфер значения данных /// </summary> DrawingVisual _imgData; /// <summary> /// визуальный буфер двоичного значения данных (кликабельные ячейки) /// </summary> DrawingVisual _imgDataBinVal;
/// <summary> /// Отрисовка области текстового значения Адреса /// </summary> void PaintAddress() { if (_imgAddress == null) return; using (DrawingContext dc = _imgAddress.RenderOpen()) { dc.DrawRectangle(Brushes.LightBlue, new Pen(Brushes.DarkGray, 1), new Rect(_ptAddress, new Size(RenderSize.Width, _heightAddress))); string str = "Адрес: 0x" + (_dpkValue & 0xFF).ToString("X").PadLeft(2, '0'); DrawTxt(dc, str, _ptAddress, new Size(RenderSize.Width, _heightAddress), Brushes.Black); } }
Реализация клика по ячейке двоичного значения («битовой ячейке» с номером бита) реализована с помощью обработчика MouseUp, в котором генерируется событие клика по ячейке.
/// <summary> /// Обработка клика по ячейке /// </summary> void DpkWordEditWPF_ClickByValue(object sender, ReturnEventArgs<int> e) { uint mask = (uint)0x1 << e.Result; if ((_dpkValue & mask) > 0) _dpkValue &= (~mask); else _dpkValue |= mask; Paint(); InvalidateVisual(); } /// <summary> /// обработка клика мыши (превращение в клик по ячейке) /// </summary> protected override void OnMouseUp(MouseButtonEventArgs e) { base.OnMouseUp(e); Point curPt = e.GetPosition(this); /*Клик в области адреса*/ if ((curPt.X >= _ptAddressBinVal.X) && (curPt.X <= (_ptAddressBinVal.X+RenderSize.Width))) if ((curPt.Y >= _ptAddressBinVal.Y) && (curPt.Y <= (_ptAddressBinVal.Y + _heightAddressBinVal))) { if ((curPt.X % _widthCellAddressBV) == 0) return; int index = (int)(curPt.X / _widthCellAddressBV); OnClickByValue(index); return; } /*клик в области данных*/ if ((curPt.X >= _ptDataBinVal.X) && (curPt.X <= (_ptDataBinVal.X + RenderSize.Width))) if ((curPt.Y >= _ptDataBinVal.Y) && (curPt.Y <= (_ptDataBinVal.Y + _heightDataBinVal))) { if ((curPt.X % _widthCellDataBV) == 0) return; int index = (int)(curPt.X / _widthCellDataBV); OnClickByValue(index + 8); return; } }
Масштабирование и вывод на экран сделаны по тому же принципу, что и в компоненте на WinForms. Масштабирование – вызов отрисовки в буфер и вывод на экран. Вывод на экран – отрисовка визуальных буферов.
/// <summary> /// первая отрисовка при появлении /// </summary> protected override void OnInitialized(EventArgs e) { base.OnInitialized(e); _imgTextMark = new DrawingVisual(); _imgAddress = new DrawingVisual(); _imgAddressBinVal = new DrawingVisual(); _imgData = new DrawingVisual(); _imgDataBinVal = new DrawingVisual(); Paint(); InvalidateVisual(); } /// <summary> /// обработка вывода на экран /// </summary> protected override void OnRender(DrawingContext drawingContext) { base.OnRender(drawingContext); if (System.ComponentModel.DesignerProperties.GetIsInDesignMode(this)) { /*режим дизайнера*/ _dpkValue = 0xFFa42312; Paint(); } drawingContext.DrawDrawing(_imgTextMark.Drawing); drawingContext.DrawDrawing(_imgAddress.Drawing); drawingContext.DrawDrawing(_imgAddressBinVal.Drawing); drawingContext.DrawDrawing(_imgData.Drawing); drawingContext.DrawDrawing(_imgDataBinVal.Drawing); }
Компонент написан на MS Visual Studio 2010, .Net Framework 4. Ссылка на проект: Ссылка на проект
Вывод
В целом код получился компактнее, чем на WinForms и работает «шустрее». Два тестовых проекта были запущены на машине со следующими характеристиками: Windows XP SP2, процессор 1-ядерный, 1 Гб ОЗУ.
WPF продемонстрировал работу без фризов при изменении размеров формы, WinForms – в свою очередь, изрядно «подтормаживал» при тех же манипуляциях.
P.S. Надеюсь, скоро все проекты на WPF будем на заводе делать.
P.P.S. Трудно бороться с консерватизмом!
ссылка на оригинал статьи http://habrahabr.ru/post/266725/
Добавить комментарий