2015-09-09 3 views
1

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

мой код в основном это (округляется до минимума):

protected override CreateParams CreateParams 
{ 
    get 
    { 
     CreateParams cp = base.CreateParams; 
     cp.ExStyle |= 0x20; 
     return cp; 
    } 
} 

protected override void OnPaintBackground(PaintEventArgs e) 
{ 
    if(this.BackColor != Color.Transparent) 
    { 
     base.OnPaintBackground(e); 
    } 
} 
+2

Winforms/sigh ... Вы можете попытаться аннулировать все элементы управления ('form.Invalidate()'), но это вызовет много мерцания. Затем вы попытаетесь уменьшить мерцание (двойная буферизация, растровые изображения и т. Д.). И затем вы переключаетесь на wpf. – Sinatr

+0

@Sinatr Я бы с удовольствием переключился на wpf, к сожалению, мой босс, похоже, считает, что кривая обучения слишком велика, а крайний срок проекта слишком короткий ... любые другие предложения? –

+1

Вы не перекраиваете фон и, следовательно, не перерисовываете пиксели старого текста. Так что это вполне ожидаемо. UserControl поддерживает прозрачность, просто установите для BackColor значение Transparent. Удалите два метода, которые вы опубликовали.Рисование текста на прозрачном фоне вообще неразумно, пиксели сглаживания будут иметь неправильные цвета, что делает текст очень уродливым. Лучше всего описывается как «бобби». Чтобы избежать этого, вы должны использовать TextRenderingHint.SingleBitPerPixelGridFit. –

ответ

1

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

Таким образом, после объединения нескольких ответов от всех моих поисков, основном this one о недействительности определенного прямоугольника родителя, и this one о получении расположения управления на форме,
я пришел с этим:

// Make the Text property browsable again, call Refresh when changed. 
[Browsable(true), 
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] 
public override string Text 
{ 
    get { return _Text; } 
    set 
    { 
     if(_Text != value) 
     { 
      this.Refresh(); 
      _Text = value; 
     } 
    } 
} 

// Override Refresh to invalidate the relevant part of the parent form 
public override void Refresh() 
{ 
    Form form = this.FindForm(); 
    // only for transparent controls that has text and no background image 
    if (this.BackColor == Color.Transparent && 
     !string.IsNullOrEmpty(this.Text) && 
     (this.Gradient.BackColor2==Color.Transparent || !this.Gradient.IsGradient) && 
     this.BackgroundImage == null && 
     form != null) 
    { 
     Point locationOnForm = form.PointToClient(
            this.Parent.PointToScreen(this.Location) 
           ); 
     // Invalidate the rectangle of the form that's behind the current control 
     form.Invalidate(new Rectangle(locationOnForm, this.Size)); 
    } 
    base.Invalidate(); 
} 

я все равно придется иметь дело с родительскими управления между текущим контролем и формы, но сейчас это достаточно хорошо для меня.

0

Я думаю, что мы близки по этому.

Во-первых, вы не можете подавить OnPaintBackground таким образом и ожидать, что остальная часть winforms будет запущена, как ожидалось, это означает, что ничего не окрашивается в этот регион вообще, поэтому мы оставили GDI + или окна или предположительно какую-нибудь другую конструкцию, чтобы "заполнить пробелы ". Элементы управления формы, которые непрозрачны, могут захотеть вызвать ваш UserControl, чтобы получить его фон, поэтому нам нужно что-то нарисовать ...

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

public Glass() 
    { 
     InitializeComponent(); 
     this.SetStyle(ControlStyles.Opaque, true); 
     this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false); 
    } 

    protected override CreateParams CreateParams 
    { 
     get 
     { 
      CreateParams cp = base.CreateParams; 
      cp.ExStyle |= 0x20; 
      return cp; 
     } 
    } 

    private bool rePaintState = false; 
    protected override void OnPaintBackground(PaintEventArgs e) 
    { 
     base.OnPaintBackground(e); 
     if (this.BackColor == Color.Transparent) 
     { 
      // we want to invalidate and force it to re-paint but just once 
      if (rePaintState) 
      { 
       rePaintState = false; 
      } 
      else 
      { 
       rePaintState = true; 
       this.Invalidate(); 
      } 
     } 
    } 

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

Я знаю его не огромная помощь, но WPF очень хорошо для этих типов вопросов UX^-^

+0

Спасибо за ваш ответ, но это не очень помогает много. мой контроль также имеет некоторые другие свойства, такие как цвет градиента и закругленные углы, и это плохо работает с ними. –

Смежные вопросы

 Смежные вопросы