Сохранение глифов Adorner сверху для выбранного элемента управления в Winforms Designer - PullRequest
0 голосов
/ 29 января 2020

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

Этот вопрос касается конструкторов элементов управления для Winforms: когда пользователь помещает элемент управления на поверхность конструктора, я хочу отобразить график c над клиентской областью элемента управления. В некоторой степени мне удалось сделать это для элемента управления TableLayoutPanel (TLP), переопределив его обработчик события OnPaint, а затем используя объект e.Graphics, доступный для рисования прямоугольника персикового цвета. Ниже приведено изображение, показывающее результаты: нарисованный график c, который охватывает ширину элемента управления и имеет высоту 35 пикселей. Помните, это экземпляр конструктора элемента управления, размещенного на поверхности конструктора (созданный с помощью BasicLoader):

enter image description here

Однако в конструкторе, если я изменяю размер элемента управления, график c всегда оказывается ниже глифа изменения размера (глифа, который имеет стрелки север / юг и запад / восток на нем):

enter image description here

Я пытался создавать и поддерживать различные логические флаги для подавления сообщения OnPaint в разделе определенные обстоятельства. Например, я установил флаг, чтобы указать, что элемент управления был только что изменен (чтобы увидеть, как я это сделал, см. Мой недавний вопрос: Событие BeginResize / EndResize для элемента управления в WinForms Design Surface ), чтобы подавить рисование графика c, но это не сработало, потому что событие OnPaint неизбежно возникает после того, как я очистил флаг. Я не хочу оседлать этот вопрос деталями всех флагов и мест, которые я пытался использовать / установить, но достаточно сказать, что я кропотливо проводил часы, экспериментируя - безрезультатно. Я пришел к выводу, что должен быть лучший способ.

Как я могу обеспечить, чтобы глифы оставались сверху при рисовании моей графики?

Спасибо!

1 Ответ

1 голос
/ 01 февраля 2020

Я могу придумать несколько решений, включая следующие:

  • Использование отступов TableLayoutPanel
  • Использование Adorner и Glyph
  • Создание пользовательских панель с заголовком и редактируемым содержимым

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

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

Решение 1 - Использование заполнения для TableLayoutPanel

Это решение предназначено как для времени разработки, так и для времени выполнения

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

enter image description here

public class MyTLP : TableLayoutPanel
{
    public MyTLP()
    {
        Padding = new Padding(0, 30, 0, 0);
    }
    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        e.Graphics.FillRectangle(Brushes.Orange,
            new Rectangle(0, 0, ClientRectangle.Width, Padding.Top));
    }
}

Решение 2 - Использование Adorner и Glyph

Это решение предназначено только для времени разработки

Для рендеринга во время разработки я буду обрабатывать его, используя Adorner и Glyph.

Если я создавал свой собственный конструктор, весь код принадлежит конструктору элементов управления, но поскольку вы не хотите создавать новый конструктор элементов управления для TableLayoutPanel, то так же, как я вставил новое настраиваемое действие в списки действий , здесь я получу BehaviorService, и я добавлю ярлык для украшателей элемента управления во время разработки, и это будет результатом:

enter image description here

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

Обратите внимание: Это решение, разработанное во время разработки, а рисование только выполняется дизайнером. Если вам нужно решение во время выполнения, вам нужно совершенно другое решение.

Вот код:

using System;
using System.ComponentModel.Design;
using System.Drawing;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Windows.Forms.Design.Behavior;
public class MyTLP : TableLayoutPanel
{
    private IDesignerHost designerHost;
    private BehaviorService behaviorService;
    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);
        if (DesignMode && Site != null)
        {
            designerHost = Site.GetService(typeof(IDesignerHost)) as IDesignerHost;
            behaviorService = designerHost?.GetService(typeof(BehaviorService))
                as BehaviorService;
            if (behaviorService != null)
            {
                var adorner = new Adorner();
                behaviorService.Adorners.Insert(0, adorner);
                adorner.Glyphs.Add(new MyTLPGlypg(behaviorService, this));
            }
        }
    }
}
class MyTLPGlypg : Glyph
{
    Control control;
    BehaviorService behaviorSvc;
    public MyTLPGlypg(BehaviorService behaviorSvc, Control control) :
        base(new MyBehavior())
    {
        this.behaviorSvc = behaviorSvc;
        this.control = control;
    }
    public override Rectangle Bounds
    {
        get
        {
            var edge = behaviorSvc.ControlToAdornerWindow(control);
            var h = 30;
            return new Rectangle(edge.X, edge.Y - h, control.Size.Width, h);
        }
    }
    public override Cursor GetHitTest(Point p)
    {
        //Uncomment if you want to attach a specific behavior
        //if (Bounds.Contains(p)) return Cursors.Hand;
        return null;
    }
    public override void Paint(PaintEventArgs pe)
    {
        pe.Graphics.FillRectangle(Brushes.Orange, Bounds);
    }
}
class MyBehavior : Behavior
{
    public override bool OnMouseUp(Glyph g, MouseButtons button)
    {
        //Do something and return true, meand eventhandled
        return true;
    }
}

Примечание:

Чтобы узнать больше о якорях, глифах и поведении, взгляните на следующие ссылки:

Решение 3 - Создание Пользовательская панель с заголовком и редактируемым содержимым

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

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

Я разместил подробный ответ здесь: UserControl с заголовком и содержимым - Разрешить удаление элементы управления на панели содержимого и предотвращение удаления элементов управления в заголовке во время разработки

...