2014-10-25 3 views
2

Рассмотрим следующий код:Как я могу избавиться от исключения «Out of memory», созданного дизайнером Visual Studio?

Главная шаблон формы модель:

public partial class CustomForm : Form 
{ 
    public CustomForm() 
    { 
     InitializeComponent(); 
     DoubleBuffered = true; 
    } 
} 

Конкретная шаблон формы модели:

public partial class PopupForm : CustomForm 
{ 
    public PopupForm() 
    { 
     InitializeComponent(); 
     BTN_Maximize.Hide(); 
    } 
} 

Производные формы:

public partial class SiteAccess : CustomForm 
{ 
    public SiteAccess() 
    { 
     InitializeComponent(); 
     this.SizeGripStyle = SizeGripStyle.Show; 
    } 
} 

(основной вид)

+

public partial class Edition : PopupForm 
{ 
    public Edition() 
    { 
     InitializeComponent(); 
    } 
} 

+

public partial class Preferences : PopupForm 
{ 
    public Preferences() 
    { 
     InitializeComponent(); 
    } 
} 

+

public partial class About : PopupForm 
{ 
    public About() 
    { 
     InitializeComponent(); 
    } 
} 

В моей форме шаблон модели PopupForm, я определил обработчик события Paint для пустой панели, например, так:

private void PNL_TitleBar_Paint(object sender, PaintEventArgs e) 
{ 
    Brush gradientBrush = new LinearGradientBrush(new Point(0, 0), 
          new Point((int)e.ClipRectangle.Right, 0), 
          Color.Gray, 
          Color.FromArgb(255, 50, 50, 50)); 

    Pen gradientPen = new Pen(gradientBrush); 

    e.Graphics.DrawLine(gradientPen, 
         new Point((int)e.ClipRectangle.Left, (int)e.ClipRectangle.Bottom - 1), 
         new Point((int)e.ClipRectangle.Right, (int)e.ClipRectangle.Bottom - 1)); 

    gradientPen.Dispose(); 
    gradientBrush.Dispose(); 
} 

Чтобы это было коротко, оно просто рисует линию градиента в нижней части панели.

Проблема возникает из-за того, что всякий раз, когда я пытаюсь вставить новый элемент управления из панели инструментов в одном из производных форм PopupForm (издание, Preferences или О), я получаю сообщение:

OutOfMemoryException

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

Кстати, я должен указать несколько вещей:

  1. Исключения, выбрасываемый из визуальной точки зрения студии конструктора только (после компиляции).
  2. Сама программа работает отлично (никаких исключений вообще).
  3. Если я запустил программу, закройте ее и вернитесь в конструктор, при вставке элементов управления в форму не будет выбрано никаких исключений.
  4. Однако, если я перестрою решение (без выполнения программы) и вернусь к конструктору, исключение будет отображаться при вставке элементов управления в форму.

    • Я попытался использовать инструкцию 'using' вместо прямого вызова функции Dispose(), но все равно ничего. Кроме того, имейте в виду, что у меня есть действительно похожий код в другом обработчике событий Paint в моей форме SiteAccess, поэтому я действительно сомневаюсь, что этот код является реальной проблемой.

Любой идея об этом странном поведении?

+1

В вашем событии рисования не рисуйте заголовок в режиме ['design mode'] (https://stackoverflow.com/questions/73515/how-to-tell-if-net-code-is- Быть-за-визуально-студийным дизайнером) – dbc

+0

Я предполагаю, что я должен способствовать тому, чтобы ответить? – dbc

+1

Удивительный! Я не знал, что все так просто. Благодаря тонну. –

ответ

6

Это вызвано ошибкой в ​​коде. Исключением является исключение GDI +, созданное конструктором LinearGradientBrush. Печально известный тем, что трудно интерпретировать, он становится намного хуже, когда это происходит во время разработки. Технически это может пойти не так и во время выполнения, что менее вероятно. Вы можете последовательно его воспроизводить, внеся небольшое изменение в свой код:

 Brush gradientBrush = new LinearGradientBrush(new Point(0, 0), 
        new Point((int)0, 0),   // <=== here 
        Color.Gray, 
        Color.FromArgb(255, 50, 50, 50)); 

Kaboom. Неправильно использовать e.ClipRectangle для инициализации кисти, градиент, который вы получите, очень непредсказуем. Значение e.ClipRectangle изменяется в зависимости от того, какая часть окна должна быть перекрашена, теперь вы полностью зависите от того, что это все окно. Это будет не в случае, если вы, скажем, перетащите окно с края экрана. Визуальный артефакт должен быть весьма заметным.

Fix:

 Brush gradientBrush = new LinearGradientBrush(new Point(0, 0), 
        new Point(this.ClientSize.Width, 0), 
        Color.Gray, 
        Color.FromArgb(255, 50, 50, 50)); 

Вызов DrawLine() должен быть закреплен, а также, чтобы получить линию, чтобы появиться в согласованном положении. Не волнуйтесь об обрезке, Windows уже позаботится об этом автоматически.

Вынос должен быть очень, тщательно используя свойство e.ClipRectangle, он работает слишком часто случайно, но почти никогда не используется тем, что вы действительно хотите использовать. Только когда-либо используйте его, чтобы проверить, можете ли вы пропустить детали чертежа, потому что они находятся за пределами области отсечения. Кодекс, который довольно сложно сделать, окупится, он просто не очень часто встречается в современных версиях Windows с включенным Aero. Не беспокойтесь.

+0

Отлично, вы просто ответили на другой вопрос, который я собирался спросить (вне артефактов экрана). –

3

В вашем Paint обработчика, вы можете проверить DesignMode свойства и пропустить рисунок в заголовке окна, когда в конструкторе форм:

void PNL_TitleBar_Paint(object sender, PaintEventArgs e) 
    { 
     if (DesignMode) 
      return; 
     using (Brush gradientBrush = new LinearGradientBrush(new Point(0, 0), 
           new Point((int)e.ClipRectangle.Right, 0), 
           Color.Gray, 
           Color.FromArgb(255, 50, 50, 50))) 
     using (Pen gradientPen = new Pen(gradientBrush)) 
     { 

      e.Graphics.DrawLine(gradientPen, 
           new Point((int)e.ClipRectangle.Left, (int)e.ClipRectangle.Bottom - 1), 
           new Point((int)e.ClipRectangle.Right, (int)e.ClipRectangle.Bottom - 1)); 
     } 
    } 

Это будет работать в вашем методе Paint и в большинстве других ситуаций. Для обсуждения необычных случаев, например, что делать внутри конструктора, см. here.

(Suggest также заменить явные вызовы Disposeusing с заявлением.)

+0

Это не проблема, картина в дизайне-времени прекрасна, и основной механизм, который дает Winforms, контролирует внешний вид WYSIWYG в дизайнере. –