Выделение полигонов и полилиний в программе WPF с использованием C#

WPF позволяет вам делать всевозможные интересные вещи, которые намного сложнее в приложениях Windows Forms. Однако иногда, как в этом примере, это делает простые вещи намного сложнее. (Лозунг WPF должен быть «Дважды гибкий и только в пять раз больше!»)

Возможно, Microsoft пытается «мягко» побудить нас использовать объекты рисования (например, объект Polygon) для рисования фигур вместо того, чтобы пытаться отобразить их в коде. Это определенно проще использовать этот подход. Если бы это была идея Microsoft, возможно, было бы лучше, если бы они просто не разрешали такой вид рендеринга вместо того, чтобы давать нам запутанный и плохо документированный метод для этого.

В любом случае, с разглагольством, позвольте мне объяснить, как работает программа. Класс DrawingContext предоставляет несколько методов рисования, таких как DrawEllipse, DrawLine и DrawRectangle. Логически этот класс должен также предоставлять DrawPolygon, DrawPolyline и другие методы рисования, но это не так. Поэтому для этого примера я решил добавить их в качестве методов расширения. Следующий код показывает частный метод DrawPolygonOrPolyline, который рисует либо полигоны, либо полилинии.

// Нарисуем многоугольник или полилинию.
private static void DrawPolygonOrPolyline(
    this DrawingContext drawingContext,
    Brush brush, Pen pen, Point[] points, FillRule fill_rule,
    bool draw_polygon)
{
    // Сделать StreamGeometry для хранения объектов чертежа.
    StreamGeometry geo = new StreamGeometry();
    geo.FillRule = fill_rule;

    // Откройте контекст для рисования.
    using (StreamGeometryContext context = geo.Open())
    {
        // Начнем с первой точки.
        context.BeginFigure(points[0], true, draw_polygon);
        
        // Добавить точки после первого.
        context.PolyLineTo(points.Skip(1).ToArray(), true, false);
    }

    // Привлечь.
    drawingContext.DrawGeometry(brush, pen, geo);
}

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

После создания объекта StreamGeometry код устанавливает его свойство FillRule. Это может иметь значения EvenOdd или Nonzero. В этом примере используется параметр EvenOdd, поэтому в середине зеленой внешней звезды есть незаполненное отверстие. (См. Рисунок.) Если это свойство было установлено на Nonzero, то внутренность звезды была бы заполнена полностью.

Затем программа «открывает» StreamGeometry, чтобы получить контекст, который он может использовать для рисования. Он вызывает метод BeginFigure контекста для начала последовательности рисования. Вы должны вызвать этот метод до начала рисования. Его первый параметр указывает, где должен начинаться рисование, в этом случае в первой точке массива точек.

Второй параметр BeginFigure указывает, должна ли заполняться фигура. Этот пример устанавливает это значение в true. Если вы не хотите заполнять фигуру, вы можете просто передать этот метод кисти null, чтобы метод не заполнил фигуру ничем.

Последний параметр BeginFigure указывает, должна ли фигура закрываться. Метод использует значение параметра draw_polygon, поэтому этот код закрывает форму только в том случае, если он рисует многоугольник.

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

Чтобы обойти эту проблему, код использует метод расширения LINQ Skip, чтобы пропустить первую точку в массиве точек и передать остальные точки в вызов PolyLineTo .

Второй параметр PolyLineTo определяет, должны ли «сегменты» между точками в полилинии «гладить» (рисовать). Этот пример устанавливает значение true, поэтому точки всегда рисуются. Если вы не хотите рисовать сегменты линии, просто передайте метод a null pen, чтобы метод не рисовал их ни с чем.

Окончательный параметр PolyLineTo указывает, должны ли линии плавно соединяться. Пример устанавливает это значение в false. Если вы хотите, чтобы линии были соединены плавно, вы можете указать свойство LineJoin для пера Rounded. (Описывается в ближайшее время.)

Наконец, после этих коротких, но трудных для понимания шагов программа вызывает метод DrawingContext объекта DrawGeometry для рисования StreamGeometry, содержащего многоугольник или полилиния.

Метод DrawPolygonOrPolyline объявлен private, поэтому он виден только в статическом классе DrawingContextExtensions, который его определяет. Вы можете сделать это public, но тогда основной программе нужно будет использовать тот же метод для рисования как полигонов, так и полилиний. Хотя это не конец света, обычно лучше сделать метод выполнять одну четко определенную задачу вместо того, чтобы сделать один супер-метод, который делает много.

Вместо этого метода public я создал следующие два метода public, которые вызывают private.

// Нарисуем многоугольник.
public static void DrawPolygon(this DrawingContext drawingContext,
    Brush brush, Pen pen, Point[] points, FillRule fill_rule)
{
    drawingContext.DrawPolygonOrPolyline(
        brush, pen, points, fill_rule, true);
}

// Нарисуем полилинию.
public static void DrawPolyline(this DrawingContext drawingContext,
    Brush brush, Pen pen, Point[] points, FillRule fill_rule)
{
    drawingContext.DrawPolygonOrPolyline(
        brush, pen, points, fill_rule, false);
}

Теперь использование этих методов из основной программы просто просто, используя другие методы, предоставляемые классом DrawingContext. Следующий код показывает, как программа рисует зеленую звезду.

// Нарисуем многоугольник.
Pen pen = new Pen(Brushes.Green, line_thickness);
pen.LineJoin = PenLineJoin.Round;
drawingContext.DrawPolygon(Brushes.LightGreen,
    pen, points, FillRule.EvenOdd);

Этот код создает перо и устанавливает его свойство LineJoin в Rounded. Затем он вызывает метод расширения DrawPolygon, передавая ему светло-зеленую кисть, перо, точки (определенные ранее в коде, которые недостаточно интересны для отображения) и требуемое правило заполнения.

Следующий код показывает, как программа рисует меньшую синюю полилинию.

// Рисуем полилинию.
pen = new Pen(Brushes.Blue, line_thickness / 2);
drawingContext.DrawPolyline(null, pen,
    points, FillRule.EvenOdd);

Этот код создает новое перо. Он вызывает метод расширения DrawPolyline, передавая ему кисть null (так что форма не заполнена), перо, точки (переопределенные ранее в коде, который не является 't достаточно интересно показать) и желаемое правило заполнения.

Источник: http://csharphelper.com/blog/2015/04/render-polygons-and-polylines-in-a-wpf-program-using-c/

1 Звезда2 Звезды3 Звезды4 Звезды5 Звезд (Пока оценок нет)
Adblock
detector