Member 12599869 Ответов: 2

Большой красный крест на кнопках winform C#


I am working on windows application and in one of my system it shows red big cross on buttons only when I am using application for long time.
I am using paint event of button for giving it 3D effect.
For that I am using following code:

  [DllImport("Gdi32.dll", EntryPoint = "CreateRoundRectRgn")]
        private static extern IntPtr CreateRoundRectRgn
        (
        int nLeftRect, // x-coordinate of upper-left corner
        int nTopRect, // y-coordinate of upper-left corner
        int nRightRect, // x-coordinate of lower-right corner
        int nBottomRect, // y-coordinate of lower-right corner
        int nWidthEllipse, // height of ellipse
        int nHeightEllipse // width of ellipse
        );

 private void button1_Paint(object sender, PaintEventArgs e)
        {
          
                var button1 = sender as Button;
                button1.Region = System.Drawing.Region.FromHrgn(CreateRoundRectRgn(2, 2, button1.Width, button1.Height, 2, 2));

                ControlPaint.DrawBorder3D(e.Graphics, ((Control)sender).ClientRectangle, Border3DStyle.Raised);

          
        }

Please provide solution to this porblem. 
Thanks in Advance.


Что я уже пробовал:

Я попытался избавиться от графического объекта в конце события paint, но он вызывает ошибку нулевой ссылки.

2 Ответов

Рейтинг:
14

OriginalGriff

Во-первых, не пытайтесь избавиться от графического контекста в событии Paint: он не Ваш, чтобы играть с ним! : смех: только утилизируйте графические объекты, которые вы создаете.

Я уже сказал это, если вы посмотрите на документацию: Функция CreateRoundRectRgn (Windows)[^] это ясно говорит:
"Когда вам больше не нужен объект HRGN, вызовите функцию DeleteObject, чтобы удалить его."
Вы этого не делаете, поэтому у системы заканчиваются ручки, и вы получаете проблемы.
Создайте свой регион и сохраните его, а затем используйте DeleteObject, чтобы освободить дескриптор, когда вы закончите с ним:

InPtr hRgn = CreateRoundRectRgn(2, 2, button1.Width, button1.Height, 2, 2);
button1.Region = System.Drawing.Region.FromHrgn(hRgn);
ControlPaint.DrawBorder3D(e.Graphics, ((Control)sender).ClientRectangle, Border3DStyle.Raised);
DeleteObject(hRgn);

Вам также нужно будет добавить DllImport:
DllImport("gdi32.dll", EntryPoint = "DeleteObject")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool DeleteObject([In] IntPtr hObject);

[править]опечатки [/править]


Member 12599869

Большое спасибо за ваш ответ. Это действительно сработало для меня. :)

OriginalGriff

Пожалуйста!

Рейтинг:
0

Sergey Alexandrovich Kryukov

Как правило, это плохая идея использовать P/Invoke, когда не критически важно достичь чего-то, что вы не можете сделать в чистом .NET FCL. Это не только делает код более подверженным ошибкам, но и, что еще хуже, ставит под угрозу совместимость вашей платформы. И вы уже продемонстрировали ошибку, приводящую к утечке памяти, неспособности избавиться от области.

Зачем вам это делать в вашем случае? Если вам нужно создать какой-либо Region например, сделайте это с помощью .NET FCL, System.Drawing:
Класс Региона (System.Рисование).

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

Этот класс все еще использует неуправляемый ресурс внутри себя, поэтому вам нужно избавиться от него. В любом случае, вам нужно избавиться от всех экземпляров всех объектов, реализующих интерфейс System.IDisposable Самый надежный способ сделать это - using заявление:
оператор using (Справочник по c# ),
смотреть также IDisposable Интерфейс (Система).

—СА