Posso suspender redesenho de uma forma até que eu tenha realizado todas as atualizações?
-
03-07-2019 - |
Pergunta
Usando C # e .Net 2.0, estou usando uma forma irregular (TransparencyKey, FormBorderStyle = None, etc ...) e quer permitir o modo "normal" fronteira.
Eu mudar a cor de volta para o padrão de Lime Eu mudar FormBorderStyle para FixedSingle Eu mudar o TransparencyKey para Colour.None
Unfortuanately isso parece uma bagunça completa na tela com a imagem pulando alguns pixels para baixo e para o lado e Lime forma verde.
Eu acho que isso é causado pela forma sendo redesenhado depois de cada linha de código, é possível suspender o desenho do formulário até que eu fiz as minhas alterações e, em seguida, apenas redesenhar o formulário uma vez?
G
Solução
NEW resposta:. Substituir o WndProc e bloquear a mensagem WM_PAINT enquanto você aplicar as novas propriedades da janela
velha resposta:. Substituir o WndProc, e bloquear a mensagem WM_ERASEBKGND
Explicação do que o código abaixo faz:
Quando a região de uma janela é invalidada, o Windows envia uma série de mensagens ao controle que resultam em um widget recém-pintada. Uma mensagem no início desta série é WM_ERASEBKGND
. Normalmente, em resposta a esta mensagem, o controlo pinta-se um sólido cor. Mais tarde, em resposta à mensagem WM_PAINT
(que normalmente é consumido por nós no evento OnPaint) o desenho real é feito. Se este desenho não é trivial, haverá um atraso antes que o widget é atualizado e você terá uma cintilação irritante.
Olhando para o código novamente eu estava resolvendo claramente um problema diferente. Experimente este novo exemplo. Ele irá bloquear a pintura do formulário / controle se o sinalizador bAllowPaint
é desactivado.
O NEW exemplo:
private const int WM_PAINT = 0x000F;
protected override void WndProc(ref Message m)
{
if ((m.Msg != WM_PAINT) ||
(bAllowPaint && m.Msg == WM_PAINT))
{
base.WndProc(ref m);
}
}
O OLD exemplo:
private const int WM_ERASEBKGND = 0x0014;
protected override void WndProc(ref Message m)
{
if (m.Msg != WM_ERASEBKGND) // ignore WM_ERASEBKGND
{
base.WndProc(ref m);
}
}
Outras dicas
Tente a propriedade Form.DoubleBuffered. Configurá-lo para 'true'.
Além disso, se o seu formulário tem os controles filho, também definir DoubleBuffered a verdade para aqueles, bem como (e filhos de filhos, etc, para baixo da linha).
Por fim, chamada SuspendLayout antes de suas alterações e ResumeLayout depois. Tenha em mente isso só afeta colocação de controles filho. Se você estiver fazendo qualquer desenho personalizado a propriedade DoubleBuffered lhe dará mais para bater a bola.
Você está modificando as propriedades que têm uma bastante grande impacto em um formulário. TransparencyKey e FormBorderStyle exigem alteração dos bits de estilo janela. O Windows não permitir que esses bits de estilo a ser alterado. Windows Forms implementa-los, destruindo completamente a janela e re criando-lo a partir do zero. truque, mas isso leva tempo e forma será pintada novamente a cada vez que você muda o estilo. Fazendo com que o efeito visual desagradável que você vê.
Tente isto: 1. Definir opacidade para 0 para que o formulário se torna invisível 2. Mudança BackColor, não há problema 3. Mudança FormBorderStyle, a janela seja recriado 4. Altere TransparencyKey, a janela seja recriado 5. Alterar opacidade para 1, a janela seja recriado, em seguida, visível
Por exemplo:
this.Opacity = 0;
this.BackColor = Color.FromKnownColor(KnownColor.Control);
this.FormBorderStyle = FormBorderStyle.Sizable;
this.TransparencyKey = Color.Empty;
this.Opacity = 1;
Se tudo isso falhar, você pode tentar alguns baixo nível de hackers bloqueando todas as mensagens de pintura ao seu formulário.
AVISO: Eu não estou promovendo o uso deste método, mas você pode experimentá-lo se você realmente quer. Ele me ajudou no passado.
Win32.LockWindowUpdate(this.Handle);
try
{
//make your changes here
}
finally
{
//release the lock
Win32.LockWindowUpdate((IntPtr)0);
}
Este código baseia-se no código de suporte seguinte:
public class Win32
{
private Win32() { }
/// <summary>
/// Lock ore relase the wndow for updating.
/// </summary>
[DllImport("user32")]
public static extern int LockWindowUpdate(HWND hwnd);
}
A maneira de enviar toda a "imagem" do formulário para a tela em uma única etapa é permitir DoubleBuffer.
No construtor você pode definir as ControlStyles
VB.NET:
SetStyle(ControlStyles.DoubleBuffer, True)