Como impedir que um UserControl (ou seja ScrollableControl) chame o ScrollWindow?
A redeUserControl
(que desce deScrollableControl
) tem a capacidade de exibir barras de rolagem horizontais e verticai
O chamador pode definir a visibilidade e o alcance dessas barras de rolagem horizontais e verticais:
UserControl.AutoScroll = true;
UserControl.AutoScrollMinSize = new Size(1000, 4000); //1000x4000 scroll area
Nota OUserControl
(ou seja,ScrollableControl
) usa o mecanismo padrão do Windows para especificarWS_HSCROLL
eWS_VSCROLL
estilos de janela para fazer aparecer as barras de rolagem. Ou seja: eles não criam controles de rolagem separados para Windows ou .NET, posicionando-os à direita / parte inferior da janela. O Windows possui um mecanismo padrão para exibir uma ou ambas as barras de rolage
Se o usuário rolar o controle, oUserControl
é enviado umWM_HSCROLL
ouWM_VSCROLL
mensagem. Em resposta a essas mensagens, desejo que o ScrollableControl invalide a área do cliente, o que aconteceria no Win32 nativo:
switch (uMsg)
{
case WM_VSCROLL:
...
GetScrollInfo(...);
...
SetScrollInfo(...);
...
InvalidateRect(g_hWnd,
null, //erase entire client area
true, //background needs erasing too (trigger WM_ERASEBKGND));
break;
}
Preciso que toda a área do cliente seja invalidada. O problema é que UserControl (ou seja,ScrollableControl
) calls aScrollWindow
Função API:
protected void SetDisplayRectLocation(int x, int y)
{
...
if ((nXAmount != 0) || ((nYAmount != 0) && base.IsHandleCreated))
{
...
SafeNativeMethods.ScrollWindowEx(new HandleRef(this, base.Handle), nXAmount, nYAmount, null, ref rectClip, NativeMethods.NullHandleRef, ref prcUpdate, 7);
}
...
}
Em vez de acionar um InvalidateRect em todo o retângulo do cliente, ScrollableControl tenta "salvament "o conteúdo existente na área do cliente. Por exemplo, o usuário rolaacim, o conteúdo atual do cliente é enviadobaix deScrollWindowEx
, e somente a área descoberta recentemente é invalidada, acionando umWM_PAINT
:
No diagrama acima, a área quadriculado é o conteúdo que éinválid e terá que ser pintado durante o próximo WM_PAIN
No meu caso, isso não é bom; a parte superior do meu controle contém um "cabeçalho" (por exemplo, cabeçalhos da coluna listview). A rolagem desse conteúdo para baixo está incorreta:
e causa corrupção visual.
Quero que o ScrollableControl sejanã usarScrollWindowEx
, mas invalide toda a área do cliente.
i tentei substituirOnScroll
método protegido:
protected override void OnScroll(ScrollEventArgs se)
{
base.OnScroll(se);
this.Invalidate();
}
Mas isso causa um empate dupl
Nota Eu poderia usar o buffer duplo para mascarar o problema, mas essa não é uma solução real
buffer duplo não deve ser usado na área de trabalho remota / sessão de terminal é um desperdício de recursos da CPU não é a pergunta que estou fazendoi considerado usar umControl
ao invés deUserControl
(ou seja, antes deScrollableControl
na cadeia de herança) e adicione manualmente um controle .NET HScroll ou VScroll .NET - mas isso também não é desejável:
Como posso ver e postar o código interno paraScrollableControl
sei que não há propriedade para desativar o uso deScrollWindow
, mas existe uma propriedade para desativar o uso deScrollWindow
?
i tentei sobrescrever o método ofensivo e use o refletor para roubar todo o código:
protected override void SetDisplayRectLocation(int x, int y)
{
...
Rectangle displayRect = this.displayRect;
...
this.displayRect.X = x;
this.displayRect.Y = y;
if ((nXAmount != 0) || ((nYAmount != 0) && base.IsHandleCreated))
{
...
SafeNativeMethods.ScrollWindowEx(new HandleRef(this, base.Handle), nXAmount, nYAmount, null, ref rectClip, NativeMethods.NullHandleRef, ref prcUpdate, 7);
}
...
}
O problema é que SetDisplayRectLocation lê e grava em uma variável de membro particular displayRect
). A menos que a Microsoft altere o C # para permitir que os descendentes acessem membros privados: eu não posso fazer iss
i percebi que copiar e colar a implementação deScrollableControl
, corrigindo oquestã significa que também terei que copiar e colar toda a cadeia de herança atéUserControl
...
ScrollableControl2 : Control, IArrangedElement, IComponent, IDisposable
ContainerControl2 : ScrollableControl2, IContainerControl
UserControl2 : ContainerControl2
eu realmente prefiro trabalharcoesign orientado a objetos, e não contra el