Нарисуйте границу вокруг элемента управления Button_Click - PullRequest
5 голосов
/ 03 февраля 2010

Когда пользователь нажимает кнопку подтверждения ( в моем приложении C #, WinForm, .net 3.5 ), я хотел бы нарисовать границу вокруг определенного элемента управления, если он пуст. Скажем, текстовое поле с именем tbxLastName Я думал, что мне нужно сделать что-то вроде этого ->

ControlPaint.DrawBorder(Graphics.FromHwnd(this.Handle), 
    tbxLastName.ClientRectangle, Color.Firebrick, ButtonBorderStyle.Solid);

К сожалению, я понятия не имею, что поставить для графического объекта, поскольку то, что у меня есть, НИЧЕГО не делает.

Все примеры, с которыми я сталкивался, MSDN - ЗДЕСЬ , содержат этот код в событии рисования. Вот так ->

private void panel1_Paint(object sender, PaintEventArgs e)
{    
    ControlPaint.DrawBorder(e.Graphics, this.panel1.ClientRectangle, 
        Color.DarkBlue, ButtonBorderStyle.Solid);
}

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


Многие предложения предлагают использовать контейнерный объект для хранения текстового поля и вызова его Paint_Event. Я сделал это, и появляется окно, но НЕ вокруг элемента управления. Появляется в верхнем левом углу Контейнер Контроля. Вот что я делаю ->

    private void grpImmunizationCntrl_Paint(object sender, PaintEventArgs e)
    {
        if (lkuNOImmunizationReason.Text.Equals(string.Empty)
        {
           ControlPaint.DrawBorder(
                    e.Graphics, lkuNOImmunizationReason.ClientRectangle,
                        Color.Firebrick, ButtonBorderStyle.Solid);
        }
    }

EDIT

Это то, что я придумал, сочетая здесь предложения с тем, что мне помогало.

    public static void HighlightRequiredFields(Control container, Graphics graphics, Boolean isVisible)
    {
        Rectangle rect = default(Rectangle);
        foreach (Control control in container.Controls)
        {
            if (control.Tag is string && control.Tag.ToString() == "required")
            {
                rect = control.Bounds;
                rect.Inflate(3, 3);
                if (isVisible && control.Text.Equals(string.Empty))
                {
                    ControlPaint.DrawBorder(graphics, rect, Color.FromArgb(173,216,230), ButtonBorderStyle.Solid);
                }
                else
                {
                    ControlPaint.DrawBorder(graphics, rect, container.BackColor, ButtonBorderStyle.None);
                }
            }

            if (control.HasChildren)
            {
                foreach (Control ctrl in control.Controls)
                {
                    HighlightRequiredFields(ctrl, graphics, isVisible);
                }
            }
        }
    }

Я звоню из Paint_Event любого Контейнера, который мне нужен.

Ответы [ 5 ]

3 голосов
/ 03 февраля 2010

Вы можете использовать поле со списком действий в форме и добавлять или удалять собственные рисунки:

// field
List<Action<Graphics>> drawings = new List<Action<Graphics>>();

// on click event:
drawings.Add(delegate(Graphics g) {
    var rect = tbxLastName.Bounds;
    rect.Inflate(1, 1); // make rectange a bit larger than textbox
    ControlPaint.DrawBorder(g, rect, 
    Color.DarkBlue, ButtonBorderStyle.Solid);
});
// make sure you added only once or clear before
panel1.Refresh(); // refresh panel to force painting


// Paint method:
foreach (var draw in drawings) {
    draw(e.Graphics);
}

Таким образом, вы можете добавить более одной границы

2 голосов
/ 06 февраля 2010

Я только что сделал нечто подобное с VB.Net, с помощью этой темы.У меня есть контейнер Panel вокруг каждого набора моих элементов управления, и в обработчике OnPaint для Panel я перебираю все дочерние элементы управления в Panel и рисую границы вокруг них, если они имеют tag="required".Я отображаю границы только для «Правка» или «Новый», поэтому я создал параметр fVisible, чтобы включать и выключать их.Когда я хочу это отключить, я звоню Panel.Refresh(), чтобы он вызвал событие OnPaint.Таким образом, все, что мне нужно сделать, это установить теги на требуемые элементы управления во время разработки и добавить обработчик для панелей контейнера, и все это работает динамически.

Вот общая функция, которую я вызываю из всехOnPaint обработчиков событий моей панели.(Извините, я знаю, что вы используете C #, и это VB, но это довольно просто.)

Friend Sub HighlightRequiredFields(ByVal pnlContainer As Panel, ByVal gr As Graphics, ByVal fVisible As Boolean)
    Dim rect As Rectangle
    For Each oControl As Control In pnlContainer.Controls
        If TypeOf oControl.Tag Is String AndAlso oControl.Tag.ToString = "required" Then
            rect = oControl.Bounds
            rect.Inflate(1, 1)
            If fVisible Then
                ControlPaint.DrawBorder(gr, rect, Color.Red, ButtonBorderStyle.Solid)
            Else
                ControlPaint.DrawBorder(gr, rect, pnlContainer.BackColor, ButtonBorderStyle.None)
            End If
        End If
        If TypeOf oControl Is Panel Then HighlightRequiredFields(DirectCast(oControl, Panel), gr, fVisible)
    Next
End Sub
1 голос
/ 03 февраля 2010

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

private void grpImmunizationCntrl_Paint(object sender, PaintEventArgs e)
{
    if (lkuNOImmunizationReason.Text.Equals(string.Empty)
    {
       ControlPaint.DrawBorder(
                e.Graphics, new Rectangle(lkuNOImmunizationReason.Left, lkuNOImmunizationReason.Top, lkuNOImmunizationReason.ClientRectangle.Width, lkuNOImmunizationReason.ClientRectangle.Height),
                    Color.Firebrick, ButtonBorderStyle.Solid);
    }
}
1 голос
/ 03 февраля 2010
    protected override void OnTextChanged(EventArgs e)
    {
        base.OnTextChanged(e);
        if (string.IsNullOrEmpty(Text))
        {
            this.BorderStyle = BorderStyle.FixedSingle;
        }
        else 
        {
            this.BorderStyle = BorderStyle.Fixed3D;
        }
    }
1 голос
/ 03 февраля 2010

Текстовые поля не вызывают метод OnPaint (см. Note раздел this page). Чтобы обойти это, поместите текстовое поле на панель, которая немного больше. Затем меняйте цвет фона при каждом нажатии кнопки. У темы на форумах MSDN есть несколько решений.

Редактировать Чтобы прояснить решение панели, просто создайте панель и добавьте в нее текстовое поле: например,

private void MyForm_Load(object sender, EventArgs e)
{
     myPanel.Controls.Add(tbxLastName); //Make sure the panel size is slightly bigger than the text box (so that it looks like a border)
}

Затем обработайте событие нажатия кнопки:

private void myButton_Click(object sender, EventArgs e)
    {
        if (tbxLastName.Text == "")
        {
            myPanel.BackColor = Color.Red;
        }
        else
        {
            myPanel.BackColor = Color.Transparent;
        }
    }
...