VB.NET Custom Control (пользовательский рисунок) Обновить проблему - PullRequest
2 голосов
/ 09 февраля 2009

Я создал простое решение с 2 проектами. Первый проект (библиотека классов) содержит пользовательский элемент управления «Контейнер», который рисует сам с закругленными углами. 2-й проект (формы Windows) - это тестовое приложение.

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

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

Я могу вызвать Container1.Refresh () в событии Form1.Move, но я не хочу устанавливать это каждый раз, потому что это также означает, что мне нужно вызывать Container1.Refresh () в событии Form1.Resize и кто знает, какое еще событие ...

Есть ли событие в самом классе Container (control), где я должен вызвать Me.Refresh () или Me.Update () или Me.Invalidate ()?

Для справки (Form1.vb)

Public Class Form1

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

End Sub

Private Sub Form1_Move(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Move
    Me.Container1.Refresh()
End Sub
End Class

для справки (Container.vb):

Imports System.Windows.Forms
Imports System.Drawing
Imports System.Drawing.Drawing2D

Public Class Container : Inherits Control
    Private _Gp As GraphicsPath

    Private Sub Container_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

        Dim r As Rectangle = e.ClipRectangle
        Dim gp As New GraphicsPath
        Dim cs As Integer = 25 'CornerSize'

        r.Inflate(-5, -5)

        gp.AddArc(r.X, r.Y, cs, cs, 180, 90)
        gp.AddArc(r.X + r.Width - cs, r.Y, cs, cs, 270, 90)
        gp.AddArc(r.X + r.Width - cs, r.Y + r.Height - cs, cs, cs, 0, 90)
        gp.AddArc(r.X, r.Y + r.Height - cs, cs, cs, 90, 90)

        Dim t As Single = cs / 2 + r.Y
        gp.AddLine(r.X, r.Y + r.Height - cs, r.X, t)

        e.Graphics.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias
        e.Graphics.DrawPath(Pens.Black, gp)
    End Sub

End Class

Ответы [ 3 ]

4 голосов
/ 09 февраля 2009

Это ваша проблема:

Dim r As Rectangle = e.ClipRectangle

Измените его на:

Dim r As Rectangle = Me.ClientRectangle
3 голосов
/ 09 февраля 2009

Мне кажется, что ваш Container класс не рисует всю свою область - обычно за его весь прямоугольник отвечает элемент управления.

Чтобы иметь элемент управления, который этого не делает, - который имеет прозрачные области (например, ваши закругленные углы), - вам нужно предоставить свой элемент управления WS_EX_TRANSPARENT. Обратите внимание, что это тема Windows API, а не .NET, поэтому вы идете в направлении какого-то незначительного вуду.

Хотя она написана на C #, статья CodeProject Создание прозрачных элементов управления с помощью C # и .NET 3.5 действительно имеет прямое отношение к тому, чего вы пытаетесь достичь.

Чтобы процитировать эту статью, вам сначала нужно переопределить конструктор вашего UserControl и настроить фон:

public TranspControl()
{
     SetStyle(ControlStyles.SupportsTransparentBackColor, true);
     SetStyle(ControlStyles.Opaque, true);
     this.BackColor = Color.Transparent;
}

Затем необходимо переопределить метод CreateParams(), чтобы установить стиль элемента управления WS_EX_TRANSPARENT:

protected override CreateParams CreateParams
{
    get
    {
        CreateParams cp = base.CreateParams;
        cp.ExStyle |= 0x20;
        return cp;
    }
}
1 голос
/ 09 февраля 2009

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

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

e.Graphics.Clear(BackColor)

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

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

...