Francesco Geri

Il blog di Francesco Geri
posts - 94, comments - 165, trackbacks - 2

Eliminazione dello sfarfallio (flickering) delle Finestre figlie di una MDI all’activate

Quando una Form MDI contiene delle form figlie aperte in modalità Maximized si uno sfarfallio al cambio delle finestra attiva.

Ciò succede quando si attiva la finestra da codice. Per evitare questo fastidioso comportamento si può come al solito ricorrere alle API Windows.

A tal proposito ho preparato un modulo MDIUtil che crea un Extension method per aggiungere alla form MDIParent il metodo MyActivateMdiChild con cui si può richiedere di attivare una form child evitando il flickering.

Il codice del modulo è il seguente:

Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports System.Runtime.InteropServices
 
Public Module MDIUtil
 
#Region " MDI Activate Child "
 
    <System.Security.SuppressUnmanagedCodeSecurity>
    <System.Runtime.InteropServices.DllImport("user32.dll", CharSet:=System.Runtime.InteropServices.CharSet.Auto)>
    Public Function SendMessage(hWnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr) As IntPtr
    End Function
 
    Public Const WM_MDINEXT As Integer = &H224
 
    ''' <summary>
    ''' Attiva la form MDI child specificata eviatando i problemi di flicker/flashing
    ''' che si avrebbero usando semplicemente il metodo <see cref="Form.Activate">Activate</see>.
    ''' Vedi post http://www.codeproject.com/Articles/19524/Workaround-for-flicker-flashing-when-programmatica
    ''' </summary>
    ''' <param name="form">Form MDI partent</param>
    ''' <param name="childToActivate">Form MDI child da attivre</param>
    <System.Runtime.CompilerServices.Extension>
 Public Sub MyActivateMdiChild(form As Form, childToActivate As Form)
        If Not childToActivate Is form.ActiveMdiChild Then
            Dim mdiClient As MdiClient = GetMDIClient(form)
            If mdiClient Is Nothing Then Return
            Dim count As Integer = form.MdiChildren.Length
            Dim childForm As Control = Nothing
            ' next or previous MDIChild form
            Dim pos As Integer = mdiClient.Controls.IndexOf(childToActivate)
            If pos < 0 Then Return 'Throw New InvalidOperationException("MDIChild form not found")
            If mdiClient.Controls.Count <= 1 Then
                ' C'è un solo child, quindi attiva quello in modo classico
                childToActivate.Focus()
                Return
            End If
            If pos = 0 Then
                childForm = mdiClient.Controls(1)
            Else
                ' get next and activate previous
                childForm = mdiClient.Controls(pos - 1)
            End If
            ' get previous and activate next
 
            ' flag indicating whether to activate previous or next MDIChild
            Dim direction As New IntPtr(If(pos = 0, 1, 0))
 
            ' bada bing, bada boom
            SendMessage(mdiClient.Handle, WM_MDINEXT, childForm.Handle, direction)
        End If
    End Sub
 
    Public Function GetMDIClient(form As Form) As MdiClient
        For Each c As Control In form.Controls
            If TypeOf c Is MdiClient Then
                Return DirectCast(c, MdiClient)
            End If
        Next
        Return Nothing 'Throw New InvalidOperationException("No MDIClient")
    End Function
 
#End Region
 
End Module

 

A questo punto nella form parent MDI si deve importare il modulo e usare il metodo MyActivateMdiChild al posto di child.Activate() (o Focus()):

Imports itConsult.josh.joshDesigner.MDIUtil
 
 
...
 
Dim child As Form = getTheFormToActivate()
' La seguente istruzione sostisuice l'istruzione: child.Activate()
Me.MyActivateMdiChild(child)

 

Nei commenti del codice del modulo è indicata anche la fonte da cui ho liberamente preso quel codice, ovvero questo post.

Print | posted on venerdì 1 marzo 2013 19:13 | Filed Under [ Tips .Net MDI ]

Powered by:
Powered By Subtext Powered By ASP.NET