Solved

Need Help With Flickering Problem When I Dispose User Controls From a .NET DialogBox

Posted on 2011-09-17
43
512 Views
Last Modified: 2012-05-12
Hello,

I am building a VB.NET PC application using VS 2008 and .NET Framework 3.5.

I am trying to dispose several hundred User Controls instantiated programmatically in a dialog popup by executing disposal code connected to a "Reset" button handler.  My code is shown in the code snippet.

The code in the FOR loop is the problem.  Instead of quickly disposing the User Controls, the system "flickers" for 30-60 seconds as it disposes each one individually (then the rest of the code runs quickly).

Any help would be most appreciated.

Thanks, Stu Engelman
0
Comment
Question by:stuengelman
  • 21
  • 13
  • 6
  • +1
43 Comments
 
LVL 15

Expert Comment

by:x77
Comment Utility
Try using "SuspendLayout" an "ResumeLayout" to avoid rebuild Control list on each Disposed control.
0
 

Author Comment

by:stuengelman
Comment Utility
Hi x77,

I use that technique in the form Load handler, and it works great on control instantiation.  But it does nothing to address the dispose operation flickering in the Reset button handler.  I.e., the dispose flickering remains even if I add the SuspendLayout code.

Stu
0
 
LVL 15

Expert Comment

by:x77
Comment Utility
You can use   Hide and SuspendLayout before Loop
 and ResumeLayout and Show after loop.

I Test it an is very fast disposing controls.


Private b As Boolean = True
Private l As New List(Of Button)(100)

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 If b Then
     Dim size = Button1.Size
     Dim xmax = Me.Width * 2, x = 0
     Dim ymax = Me.Height * 2, y = 0
     SuspendLayout()
     For x = 0 To xmax Step size.Width
        For y = 0 To ymax Step size.Height
           Dim btn As New Button With {.Location = New Point(x, y), .Size = size, .Text = "xx"}
           Controls.Add(btn)
           l.Add(btn)
        Next
     Next
     Me.ResumeLayout()
 Else
    Visible = False
    SuspendLayout()
    For Each btn In l
        btn.Dispose()
    Next
    ResumeLayout()
    l.Clear()
    Show()
 End If
 b = Not b
End Sub

Open in new window

0
 
LVL 15

Expert Comment

by:x77
Comment Utility
The fastest method is owner Paint Controls and place one control each time at apropiate position to edit.
Same as DataGridView does.

But it is some complex.
Image1.png
0
 

Author Comment

by:stuengelman
Comment Utility
Hi x77,

Two questions in regard to the SuspendLayout code snippet (taken from your post):

(1) Is it necessary to place the User Controls in a collection and execute the Clear command, or can I simply perform the individual Dispose operations?

(2) Should I add a "PerformLayout()" command after "ResumeLayout()"?

Thanks, Stu
Visible = False
SuspendLayout()
For Each btn In l
    btn.Dispose()
Next
ResumeLayout()
l.Clear()
Show()

Open in new window

0
 
LVL 15

Assisted Solution

by:x77
x77 earned 150 total points
Comment Utility
About clear:

I Build a List with all controls I has add to my form (l).
Note that "L" is not the Forms.Controls collection.
I clear my list to reuse it.
Button1 is also a control on my form and i do´nt dispose it.

The impact of SuspendLayout / ResoumeLayout (or PerformLayout) is small compared to impact of Hide the form.
By Sample. When I create 100 controls, Form takes about 4 to 5 seconds without hide.
Hiding the form, it takes less 1 second, but then I added SuspendLayout / ResumeLayout.
Then I do´nt apreciate the hide efect.
Note that efect of Suspend/resume Layout is minimal, but it has great efect on final result.

It is not necessary build a list with controls, but I build a sample as simple as I can do.
I do´nt put names on controls, then I need know that controls I need dispose.
Note that I can enumerate controls an dispose controls where name is nothing, but I do´nt like that.

I Tested PerformLayout and ResumeLayout and I do´nt apreciate any difference.
Note that if you put PerformLayout you do´nt need ResumeLayout.
PerformLayout forze layout to all controls, ResumeLayout only to pending layout controls.
0
 

Author Comment

by:stuengelman
Comment Utility
Thanks x77,

Will try out your technique and report.

Stu
0
 

Author Comment

by:stuengelman
Comment Utility
Hi x77,

Your method appears to help.  The Dispose time is speeded up (it now takes about about 7 seconds).  The flickering is still present.  I think I could live with the 7 second wait time for the Dispose operations, but would really like to eliminate the flickering if there was some way to do it.

Stu
0
 
LVL 15

Expert Comment

by:x77
Comment Utility
I find on Web some proyects for WindowLess Controls (Vb6 labels, lightweight controls).

There are some people that try some solutions, but there are any significant.

In future, I whant enahce QueryCtl logic to build some Editor-Panel with binding support.

By now, the PropertyGrid has a good response.
I Use it some times, also over datatables to show full information list.

There are some good articles about PropertyGrid as Data Control.
Most them are so complex.
0
 
LVL 15

Expert Comment

by:x77
Comment Utility
I take other test.

I create a Panel inside Form1.
Panel has autoscroll=false

Then I create controls on Panel.
At end I resize the panel to show all controls.

Disposing controls:

Hide Panel - don´t Flicker.
To Dispose controls: I copy  to an array, clear Panel.Controls and dispose all controls.

Controls  848 , Time 0.1808827 sec
Public Class Form1
Private b As Boolean = True
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
 If b Then
     Dim size = Button1.Size
     Dim xmax = Me.Width * 4, x = 0
     Dim ymax = Me.Height * 4, y = 0
     Panel1.SuspendLayout()
     For x = 0 To xmax - size.Width Step size.Width
        For y = 0 To ymax Step size.Height
           Dim btn As New Button With {.Location = New Point(x, y), .Size = size, .Text = "xx"}
           Panel1.Controls.Add(btn)
        Next
     Next
     Panel1.Size = New Size(xmax, ymax)
     Panel1.Visible = True
     Panel1.ResumeLayout()
 Else
    'Visible = False
    Dim t = Stopwatch.StartNew
    Panel1.Visible = False
    Dim arr(Panel1.Controls.Count - 1) As Control
    Panel1.Controls.CopyTo(arr, 0)
    Panel1.Controls.Clear()
    For Each c In arr : c.Dispose() : Next
    t.Stop()
    Debug.Print(arr.Length.ToString & " " & t.Elapsed.ToString)
    'Show()
 End If
 b = Not b
End Sub
End Class

Open in new window

0
 

Author Comment

by:stuengelman
Comment Utility
x77,

I was wondering about the collection concept.  If I made the user controls members of a collection, and then issued the Clear command on the collection, would this actually prevent "collision" (runtime abend due to same named objects) when I recreate the controls, or just remove the controls from the collection?

Stu
0
 
LVL 27

Expert Comment

by:planocz
Comment Utility
I have used this on some apps.

 Public Declare Auto Function SendMessage Lib "User32" Alias "SendMessageA" (ByVal hWnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Boolean

         '// This code will kept the Maximized Child Forms from
        '//  flickering when opening
        '//  Sample:
        '//  Dim objForm As Form = New frmMyForm
        '//  With objForm
        '//       .Dock = DockStyle.Fill
        '//       SendMessage(Me.Handle, WM_SETREDRAW, 0, 0)
        '//       .Text = "MyForm Header"
        '//        .MdiParent = Me
        '//        .Show()
        '//  End With
        '//  SendMessage(Me.Handle, WM_SETREDRAW, 1, 0)
        '//  Me.Invalidate(True)   <----- the MDI Parent Form
        '//  Cursor = Cursors.Default
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello, based in the x77 idea, what if you call Application.DoEvents() after set Visible = False, example:
Visible = False
Application.DoEvents()
SuspendLayout()
For Each btn In l
    btn.Dispose()
Next
ResumeLayout()
l.Clear()
Show()

Open in new window

Still flicking?
0
 

Author Comment

by:stuengelman
Comment Utility
Hi Planocz and Yv989c,

Will try both of your methods and report back.

Thanks, Stu
0
 

Author Comment

by:stuengelman
Comment Utility
yv989c,

Application.DoEvents() did not solve the problem.

Stu
0
 

Author Comment

by:stuengelman
Comment Utility
planocz,

I'm not sure whether or not your code is applicable to my situation.  My issue is not flickering as the UserControls are instantiated and rendered.  The issue is flickering on their disposal.  I have a Reset button that disposes of the 200 or so UserControls (and two buttons), and then calls the dialog popup's Load handler to rebuild the popup from the database.  Please see the code snippet for the current state of the Reset button's handler logic.

The flickering is occuring in the FOR loop that disposes the UserControls.  Would you be able to revise the code in the code snippet to reflect what you think is the best way to handle the problem?

Thanks, Stu
Me.Visible = False
Application.DoEvents()
Me.SuspendLayout()
For i = 1 To ctlcounter
    Me.Controls("mxrow" & CStr(i)).Dispose()
Next
Me.Controls("btnMXReset").Dispose()
Me.Controls("btnMXClose").Dispose()
Me.ResumeLayout()
Me.PerformLayout()
Me.Show()
mdgExpListMgr_Load(Nothing, Nothing)
Me.ScrollControlIntoView(pbExpListBackground)

Open in new window

0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello, can you try this?
' Make a list of your controls...
Dim myControls As New List(Of Control)
For i As Integer = 1 To ctlcounter
    Dim myControl As Control = Me.Controls("mxrow" & i)
    myControls.Add(myControl)
Next
myControls.Add(Me.Controls("btnMXReset"))
myControls.Add(Me.Controls("btnMXClose"))

' Remove controls
Me.SuspendLayout()
For Each ctrl As Control In myControls
    Me.Controls.Remove(ctrl)
Next
Me.ResumeLayout(True)
Application.DoEvents()

' Dispose controls
For Each ctrl As Control In myControls
    ctrl.Dispose()
Next

mdgExpListMgr_Load(Nothing, Nothing)
Me.ScrollControlIntoView(pbExpListBackground)

Open in new window

0
 

Author Comment

by:stuengelman
Comment Utility
yv989c,

You're code functions properly, but the flickering is still present.

Stu
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Please try this, now I just want to know how much time requires your controls to dispose:
' Make a list of your controls...
Dim myControls As New List(Of Control)
For i As Integer = 1 To ctlcounter
    Dim myControl As Control = Me.Controls("mxrow" & i)
    myControls.Add(myControl)
Next
myControls.Add(Me.Controls("btnMXReset"))
myControls.Add(Me.Controls("btnMXClose"))

' Remove controls
Me.SuspendLayout()
For Each ctrl As Control In myControls
    Me.Controls.Remove(ctrl)
Next
Me.ResumeLayout(True)
Application.DoEvents()

Dim myStopwatch As New System.Diagnostics.Stopwatch
myStopwatch.Start()
' Dispose controls
For Each ctrl As Control In myControls
    ctrl.Dispose()
Next
myStopwatch.Stop()
MessageBox.Show(myStopwatch.Elapsed.ToString())

Open in new window


How much time show the message box?
0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

A great idea.  The answer came out 00:00:00:303.  That means the dispose is running really fast.  The flickering must be occuring on the reinstantiation of the controls when the Reset handler runs the command mdgExpListMgr_Load(Nothing, Nothing).  But here's what's confusing: I don't get this issue when the dialog popup is first popped and the Load handler runs at that time.  The Load handler uses SuspendLayout/.../ResumeLayout/DoEvents, which makes the initial load run nice and quickly.

Stu
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
How much time requires mdgExpListMgr_Load(Nothing, Nothing) to execute?

Try this to see that:
' Make a list of your controls...
Dim myControls As New List(Of Control)
For i As Integer = 1 To ctlcounter
    Dim myControl As Control = Me.Controls("mxrow" & i)
    myControls.Add(myControl)
Next
myControls.Add(Me.Controls("btnMXReset"))
myControls.Add(Me.Controls("btnMXClose"))

' Remove controls
Me.SuspendLayout()
For Each ctrl As Control In myControls
    Me.Controls.Remove(ctrl)
Next
Me.ResumeLayout(True)
Application.DoEvents()

' Dispose controls
For Each ctrl As Control In myControls
    ctrl.Dispose()
Next


Dim myStopwatch As New System.Diagnostics.Stopwatch
myStopwatch.Start()
mdgExpListMgr_Load(Nothing, Nothing)
myStopwatch.Stop()
MessageBox.Show(myStopwatch.Elapsed.ToString())


Me.ScrollControlIntoView(pbExpListBackground)

Open in new window

0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
If you can post a code snippet of mdgExpListMgr_Load that will be useful
0
 

Author Comment

by:stuengelman
Comment Utility
yv989c,

Took 7 seconds, compared with three for the initial popup.

The Load Handler is in the code snippet.

Thanks, Stu
Private Sub mdgExpListMgr_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Me.SuspendLayout()
        Me.BackgroundImage = Nothing
        pbExpListBackground.SendToBack()
        Dim CN As New SqlConnection
        Dim CMD As New SqlCommand
        Dim RDR As SqlDataReader
        CN.ConnectionString = glbLocalCnxnString
        CN.Open()
        CMD.Connection = CN
        Dim SQL As String
        SQL = "select * from ExpenseList order by Supercategory,Category,ExpenseName"
        CMD.CommandText = SQL
        RDR = CMD.ExecuteReader()
        Dim ii As Integer = 0
        Dim resettop As Integer = 0
        If RDR.HasRows Then
            Do While RDR.Read
                Dim dmxrow As New MXrow
                ii = ii + 1
                If ii = 1 Then
                    dmxrow.Name = "mxrow1"
                    Me.Controls.Add(dmxrow)
                    dmxrow.Left = 40
                    dmxrow.Top = Me.lblExpenseList.Top + 30
                Else
                    dmxrow.Name = "mxrow" & CStr(ii)
                    Me.Controls.Add(dmxrow)
                    dmxrow.HideHeaders()
                    dmxrow.Update()
                    dmxrow.SendToBack()
                    dmxrow.Left = 40
                    dmxrow.Top = Me.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                End If
                If RDR("SuperCategory") = "Fixed" Then
                    dmxrow.cboMXSuperCategory.SelectedIndex = 0
                Else
                    dmxrow.cboMXSuperCategory.SelectedIndex = 1
                End If
                dmxrow.txtMXCategory.Text = RDR("Category")
                dmxrow.txtMXExpenseName.Text = RDR("ExpenseName")
                dmxrow.cbMXStatus.Checked = RDR("Status")
                dmxrow.btnMXAdd.Tag = CStr(ii)
                dmxrow.btnMXAlter.Tag = CStr(RDR("ExpListID"))
                dmxrow.btnMXDelete.Tag = CStr(RDR("ExpListID"))
                resettop = dmxrow.Bottom
                ctlcounter = ii
                If CStr(ii) = glbMiscString Then
                    ii = ii + 1
                    dmxrow.Name = "mxrow" & CStr(ii)
                    Me.Controls.Add(dmxrow)
                    dmxrow.HideHeaders()
                    dmxrow.Update()
                    dmxrow.SendToBack()
                    dmxrow.Left = 40
                    dmxrow.Top = Me.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                    dmxrow.cboMXSuperCategory.SelectedIndex = -1
                    dmxrow.txtMXCategory.Text = ""
                    dmxrow.txtMXExpenseName.Text = ""
                    dmxrow.btnMXAdd.Tag = "0"
                    dmxrow.btnMXAdd.Text = "Enter"
                    dmxrow.btnMXAlter.Enabled = False
                    dmxrow.btnMXDelete.Enabled = False
                    dmxrow.cbMXStatus.Checked = False
                    resettop = dmxrow.Bottom
                    ctlcounter = ii
                    glbMiscString = ""
                End If
            Loop
        Else
            Dim dmxrow As New MXrow
            dmxrow.Name = "mxrow1"
            Me.Controls.Add(dmxrow)
            dmxrow.Left = 40
            dmxrow.Top = Me.lblExpenseList.Top + 30
            dmxrow.cboMXSuperCategory.SelectedIndex = -1
            dmxrow.txtMXCategory.Text = ""
            dmxrow.txtMXExpenseName.Text = ""
            dmxrow.btnMXAdd.Tag = "0"
            dmxrow.btnMXAdd.Text = "Enter"
            dmxrow.btnMXAlter.Enabled = False
            dmxrow.btnMXDelete.Enabled = False
            dmxrow.cbMXStatus.Checked = False
            resettop = dmxrow.Bottom
            ctlcounter = 1
        End If
        Dim btnMXReset As New Button
        btnMXReset.Name = "btnMXReset"
        Me.Controls.Add(btnMXReset)
        btnMXReset.Text = "Reset"
        btnMXReset.BackColor = Color.White
        btnMXReset.Left = (Me.Width / 2) - (btnMXReset.Width / 2)
        btnMXReset.Top = resettop + 15
        AddHandler btnMXReset.Click, AddressOf btnMXReset_Clicked
        resettop = btnMXReset.Bottom + 15
        Dim btnMXClose As New Button
        btnMXClose.Name = "btnMXClose"
        Me.Controls.Add(btnMXClose)
        btnMXClose.Text = "Close"
        btnMXClose.BackColor = Color.White
        btnMXClose.Left = (Me.Width / 2) - (btnMXClose.Width / 2)
        btnMXClose.Top = resettop
        AddHandler btnMXClose.Click, AddressOf btnMXClose_Clicked
        resettop = btnMXClose.Bottom + 15
        Dim lblspacer As New Label
        Me.Controls.Add(lblspacer)
        lblspacer.Text = ""
        lblspacer.Left = (Me.Width / 2) - (lblspacer.Width / 2)
        lblspacer.Top = resettop
        RDR.Close()
        RDR = Nothing
        CN.Close()
        CMD = Nothing
        CN = Nothing
        For i As Integer = 1 To ctlcounter
            Dim myControl As Control = Me.Controls("mxrow" & i)
            myControls.Add(myControl)
        Next
        myControls.Add(Me.Controls("btnMXReset"))
        myControls.Add(Me.Controls("btnMXClose"))
        Me.ResumeLayout(True)
        Application.DoEvents()
    End Sub

Open in new window

0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello, just a question, the MXrow class, when you create an instance of it, it does a DB query to fill a ComboBox/DropDownList?

Example, when I do this, it does a DB query to fill cboMXSuperCategory?
Dim dmxrow As New MXrow

Open in new window

0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

Correct.  A DB query is performed to populate the controls (one combobox, two textboxes, and one checkbox) in each MXrow instance.  I copy pasted the applicable logic contained in the previous code snippet to a new code snippet here.

Stu
If RDR("SuperCategory") = "Fixed" Then
    dmxrow.cboMXSuperCategory.SelectedIndex = 0
Else
    dmxrow.cboMXSuperCategory.SelectedIndex = 1
End If
dmxrow.txtMXCategory.Text = RDR("Category")
dmxrow.txtMXExpenseName.Text = RDR("ExpenseName")
dmxrow.cbMXStatus.Checked = RDR("Status")

Open in new window

0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello, well, that is not what I want to know, I saw that in your previous code... I think that I did not explain very well.. I'm going to make some changes to your method that I think can eliminate the flickering effect and reduce the load time.
0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

Thank you so much.  I really appreciate all your help.

Best regards, Stu
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Two questions, how many rows contains the table [ExpenseList]? also, this table is updated very often?
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello, try this new code:
Function GetExpenseListData() As DataTable
    Dim dtt As New DataTable

    Using cn As New SqlConnection(glbLocalCnxnString)
        Dim cmd As New SqlCommand("SELECT SuperCategory, Category, ExpenseName, Status, ExpListID FROM ExpenseList ORDER BY Supercategory, Category, ExpenseName", cn)
        cn.Open()
        Using dr As SqlDataReader = cmd.ExecuteReader
            dtt.Load(dr)
        End Using
    End Using

    Return dtt
End Function

Private Sub mdgExpListMgr_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        Me.SuspendLayout()
        Me.BackgroundImage = Nothing
        pbExpListBackground.SendToBack()

        Dim myData As DataTable = GetExpenseListData()

        Dim ii As Integer = 0
        Dim resettop As Integer = 0
        If myData.Rows.Count > 0 Then
            Dim myMXrows As New List(Of MXrow)
            For Each row As DataRow In myData.Rows
                Dim dmxrow As New MXrow
                ii = ii + 1
                If ii = 1 Then
                    dmxrow.Name = "mxrow1"
                    myMXrows.Add(dmxrow)
                Else
                    dmxrow.Name = "mxrow" & CStr(ii)
                    myMXrows.Add(dmxrow)
                    dmxrow.HideHeaders()
                End If

                If row("SuperCategory") = "Fixed" Then
                    dmxrow.cboMXSuperCategory.SelectedIndex = 0
                Else
                    dmxrow.cboMXSuperCategory.SelectedIndex = 1
                End If

                dmxrow.txtMXCategory.Text = row("Category")
                dmxrow.txtMXExpenseName.Text = row("ExpenseName")
                dmxrow.cbMXStatus.Checked = row("Status")
                dmxrow.btnMXAdd.Tag = CStr(ii)
                dmxrow.btnMXAlter.Tag = CStr(row("ExpListID"))
                dmxrow.btnMXDelete.Tag = CStr(row("ExpListID"))

                resettop = dmxrow.Bottom
                ctlcounter = ii

                If CStr(ii) = glbMiscString Then
                    ii = ii + 1
                    dmxrow.Name = "mxrow" & CStr(ii)
                    myMXrows.Add(dmxrow)
                    dmxrow.HideHeaders()
                    dmxrow.cboMXSuperCategory.SelectedIndex = -1
                    dmxrow.txtMXCategory.Text = ""
                    dmxrow.txtMXExpenseName.Text = ""
                    dmxrow.btnMXAdd.Tag = "0"
                    dmxrow.btnMXAdd.Text = "Enter"
                    dmxrow.btnMXAlter.Enabled = False
                    dmxrow.btnMXDelete.Enabled = False
                    dmxrow.cbMXStatus.Checked = False
                    resettop = dmxrow.Bottom
                    ctlcounter = ii
                    glbMiscString = ""
                End If
            Next

            ii = 0
            For Each dmxrow As MXrow In myMXrows
                Me.Controls.Add(dmxrow)
                ii = ii + 1
                If ii = 1 Then
                    dmxrow.Left = 40
                    dmxrow.Top = Me.lblExpenseList.Top + 30
                Else
                    dmxrow.Update()
                    dmxrow.SendToBack()
                    dmxrow.Left = 40
                    dmxrow.Top = Me.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                End If

                resettop = dmxrow.Bottom
                ctlcounter = ii

                If CStr(ii) = glbMiscString Then
                    ii = ii + 1
                    Me.Controls.Add(dmxrow)
                    dmxrow.Update()
                    dmxrow.SendToBack()
                    dmxrow.Left = 40
                    dmxrow.Top = Me.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                    resettop = dmxrow.Bottom
                    ctlcounter = ii
                    glbMiscString = ""
                End If
            Next
        Else
            Dim dmxrow As New MXrow
            dmxrow.Name = "mxrow1"
            Me.Controls.Add(dmxrow)
            dmxrow.Left = 40
            dmxrow.Top = Me.lblExpenseList.Top + 30
            dmxrow.cboMXSuperCategory.SelectedIndex = -1
            dmxrow.txtMXCategory.Text = ""
            dmxrow.txtMXExpenseName.Text = ""
            dmxrow.btnMXAdd.Tag = "0"
            dmxrow.btnMXAdd.Text = "Enter"
            dmxrow.btnMXAlter.Enabled = False
            dmxrow.btnMXDelete.Enabled = False
            dmxrow.cbMXStatus.Checked = False
            resettop = dmxrow.Bottom
            ctlcounter = 1
        End If

        Dim btnMXReset As New Button
        btnMXReset.Name = "btnMXReset"
        Me.Controls.Add(btnMXReset)
        btnMXReset.Text = "Reset"
        btnMXReset.BackColor = Color.White
        btnMXReset.Left = (Me.Width / 2) - (btnMXReset.Width / 2)
        btnMXReset.Top = resettop + 15
        AddHandler btnMXReset.Click, AddressOf btnMXReset_Clicked
        resettop = btnMXReset.Bottom + 15

        Dim btnMXClose As New Button
        btnMXClose.Name = "btnMXClose"
        Me.Controls.Add(btnMXClose)
        btnMXClose.Text = "Close"
        btnMXClose.BackColor = Color.White
        btnMXClose.Left = (Me.Width / 2) - (btnMXClose.Width / 2)
        btnMXClose.Top = resettop
        AddHandler btnMXClose.Click, AddressOf btnMXClose_Clicked
        resettop = btnMXClose.Bottom + 15

        Dim lblspacer As New Label
        Me.Controls.Add(lblspacer)
        lblspacer.Text = ""
        lblspacer.Left = (Me.Width / 2) - (lblspacer.Width / 2)
        lblspacer.Top = resettop

        For i As Integer = 1 To ctlcounter
            Dim myControl As Control = Me.Controls("mxrow" & i)
            myControls.Add(myControl)
        Next

        myControls.Add(btnMXReset)
        myControls.Add(btnMXClose)
    Finally
        Me.ResumeLayout(True)
        Application.DoEvents()
    End Try
End Sub

Open in new window


There is a new function named GetExpenseListData and the updated sub mdgExpListMgr_Load.
Please test this and check if I have not broken anything ;)
0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

The ExpenseList table has about 200 rows.

I'll try out your code and report.

Thanks, Stu
0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

An incremental improvement.  I still have the three second refresh time, which is fine, as that's about as long as it takes the popup to initially load.  Also, the flickering is reduced to the two textboxes, whereas ealier most of the whole user control flickered (combobox, two textboxes, checkbox, and three buttons) as the refresh spun through the DB and rerendered the user controls.  What's so nice as mentioned earlier is that the popup simply "waits until done" on initial load before showing.

I'm wondering whether some kind of popup hide/show strategy would make sense for the refresh to get the final extra bit of performance I need?

My latest code is in the snippet.

Thanks, Stu
Imports System.Windows.Forms
Imports System.Data.SqlClient

Public Class mdgExpListMgr

    Private myUserControls As New List(Of MXrow)

    Private Sub mdgExpListMgr_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Try
            Me.SuspendLayout()
            Me.BackgroundImage = Nothing
            pbExpListBackground.SendToBack()
            Dim myData As DataTable = GetExpenseListData()
            Dim ii As Integer = 0
            If myData.Rows.Count > 0 Then
                For Each row As DataRow In myData.Rows
                    Dim dmxrow As New MXrow
                    ii = ii + 1
                    If ii = 1 Then
                        dmxrow.Name = "mxrow1"
                        myUserControls.Add(dmxrow)
                    Else
                        dmxrow.Name = "mxrow" & CStr(ii)
                        myUserControls.Add(dmxrow)
                        dmxrow.HideHeaders()
                    End If
                    If row("SuperCategory") = "Fixed" Then
                        dmxrow.cboMXSuperCategory.SelectedIndex = 0
                    Else
                        dmxrow.cboMXSuperCategory.SelectedIndex = 1
                    End If
                    dmxrow.txtMXCategory.Text = row("Category")
                    dmxrow.txtMXExpenseName.Text = row("ExpenseName")
                    dmxrow.cbMXStatus.Checked = row("Status")
                    dmxrow.btnMXAdd.Tag = CStr(ii)
                    dmxrow.btnMXAlter.Tag = CStr(row("ExpListID"))
                    dmxrow.btnMXDelete.Tag = CStr(row("ExpListID"))
                    If CStr(ii) = glbMiscString Then
                        Dim dnmxrow As New MXrow
                        ii = ii + 1
                        dnmxrow.Name = "mxrow" & CStr(ii)
                        myUserControls.Add(dnmxrow)
                        dnmxrow.HideHeaders()
                        dnmxrow.cboMXSuperCategory.SelectedIndex = -1
                        dnmxrow.txtMXCategory.Text = ""
                        dnmxrow.txtMXExpenseName.Text = ""
                        dnmxrow.btnMXAdd.Tag = "0"
                        dnmxrow.btnMXAdd.Text = "Enter"
                        dnmxrow.btnMXAlter.Enabled = False
                        dnmxrow.btnMXDelete.Enabled = False
                        dnmxrow.cbMXStatus.Checked = False
                        glbMiscString = ""
                    End If
                Next
                ii = 0
                For Each dmxrow As MXrow In myUserControls
                    Me.Controls.Add(dmxrow)
                    ii = ii + 1
                    If ii = 1 Then
                        dmxrow.Left = 40
                        dmxrow.Top = Me.lblExpenseList.Top + 30
                        dmxrow.Update()
                    Else
                        dmxrow.SendToBack()
                        dmxrow.Left = 40
                        dmxrow.Top = Me.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                        dmxrow.Update()
                    End If
                Next
            Else
                Dim dmxrow As New MXrow
                dmxrow.Name = "mxrow1"
                Me.Controls.Add(dmxrow)
                dmxrow.Left = 40
                dmxrow.Top = Me.lblExpenseList.Top + 30
                dmxrow.cboMXSuperCategory.SelectedIndex = -1
                dmxrow.txtMXCategory.Text = ""
                dmxrow.txtMXExpenseName.Text = ""
                dmxrow.btnMXAdd.Tag = "0"
                dmxrow.btnMXAdd.Text = "Enter"
                dmxrow.btnMXAlter.Enabled = False
                dmxrow.btnMXDelete.Enabled = False
                dmxrow.cbMXStatus.Checked = False
            End If
            Dim resettop = Me.Controls("mxrow" & CStr(ii)).Bottom
            Dim btnMXReset As New Button
            btnMXReset.Name = "btnMXReset"
            Me.Controls.Add(btnMXReset)
            btnMXReset.Text = "Reset"
            btnMXReset.BackColor = Color.White
            btnMXReset.Left = (Me.Width / 2) - (btnMXReset.Width / 2)
            btnMXReset.Top = resettop + 15
            AddHandler btnMXReset.Click, AddressOf btnMXReset_Clicked
            resettop = btnMXReset.Bottom + 15
            Dim btnMXClose As New Button
            btnMXClose.Name = "btnMXClose"
            Me.Controls.Add(btnMXClose)
            btnMXClose.Text = "Close"
            btnMXClose.BackColor = Color.White
            btnMXClose.Left = (Me.Width / 2) - (btnMXClose.Width / 2)
            btnMXClose.Top = resettop
            AddHandler btnMXClose.Click, AddressOf btnMXClose_Clicked
            resettop = btnMXClose.Bottom + 15
            Dim lblspacer As New Label
            Me.Controls.Add(lblspacer)
            lblspacer.Text = ""
            lblspacer.Left = (Me.Width / 2) - (lblspacer.Width / 2)
            lblspacer.Top = resettop
        Finally
            Me.ResumeLayout(True)
            Application.DoEvents()
        End Try
    End Sub

    Function GetExpenseListData() As DataTable
        Dim dtt As New DataTable
        Using cn As New SqlConnection(glbLocalCnxnString)
            Dim cmd As New SqlCommand("SELECT SuperCategory, Category, ExpenseName, Status, ExpListID FROM ExpenseList ORDER BY Supercategory, Category, ExpenseName", cn)
            cn.Open()
            Using dr As SqlDataReader = cmd.ExecuteReader
                dtt.Load(dr)
            End Using
        End Using
        Return dtt
    End Function

    Public Sub btnMXReset_Clicked()
        Me.SuspendLayout()
        For Each ctrl As Control In myUserControls
            Me.Controls.Remove(ctrl)
        Next
        Me.ResumeLayout(True)
        Application.DoEvents()
        For Each ctrl As Control In myUserControls
            ctrl.Dispose()
        Next
        myUserControls.Clear()
        If glbMiscString = "" Then
            Me.Controls("btnMXReset").Dispose()
            Me.Controls("btnMXClose").Dispose()
        End If
        mdgExpListMgr_Load(Nothing, Nothing)
        Me.ScrollControlIntoView(pbExpListBackground)
    End Sub

    Private Sub btnMXClose_Clicked()
        Me.Close()
    End Sub

End Class

Open in new window

0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
I will try something and let you know...
0
 

Author Comment

by:stuengelman
Comment Utility
OK, thanks yv989c, Stu
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hello Stu, based on your last code I did this, it will show a dialog (Please wait...) while your controls are created:

1. Add this sub to your form
Sub LoadMyFormControls(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim myForm As mdgExpListMgr = sender

    Dim myData As DataTable = GetExpenseListData()
    Dim ii As Integer = 0
    If myData.Rows.Count > 0 Then
        For Each row As DataRow In myData.Rows
            Dim dmxrow As New MXrow
            ii = ii + 1
            If ii = 1 Then
                dmxrow.Name = "mxrow1"
                myUserControls.Add(dmxrow)
            Else
                dmxrow.Name = "mxrow" & CStr(ii)
                myUserControls.Add(dmxrow)
                dmxrow.HideHeaders()
            End If
            If row("SuperCategory") = "Fixed" Then
                dmxrow.cboMXSuperCategory.SelectedIndex = 0
            Else
                dmxrow.cboMXSuperCategory.SelectedIndex = 1
            End If
            dmxrow.txtMXCategory.Text = row("Category")
            dmxrow.txtMXExpenseName.Text = row("ExpenseName")
            dmxrow.cbMXStatus.Checked = row("Status")
            dmxrow.btnMXAdd.Tag = CStr(ii)
            dmxrow.btnMXAlter.Tag = CStr(row("ExpListID"))
            dmxrow.btnMXDelete.Tag = CStr(row("ExpListID"))
            If CStr(ii) = glbMiscString Then
                Dim dnmxrow As New MXrow
                ii = ii + 1
                dnmxrow.Name = "mxrow" & CStr(ii)
                myUserControls.Add(dnmxrow)
                dnmxrow.HideHeaders()
                dnmxrow.cboMXSuperCategory.SelectedIndex = -1
                dnmxrow.txtMXCategory.Text = ""
                dnmxrow.txtMXExpenseName.Text = ""
                dnmxrow.btnMXAdd.Tag = "0"
                dnmxrow.btnMXAdd.Text = "Enter"
                dnmxrow.btnMXAlter.Enabled = False
                dnmxrow.btnMXDelete.Enabled = False
                dnmxrow.cbMXStatus.Checked = False
                glbMiscString = ""
            End If
        Next
        ii = 0
        For Each dmxrow As MXrow In myUserControls
            myForm.Controls.Add(dmxrow)
            ii = ii + 1
            If ii = 1 Then
                dmxrow.Left = 40
                dmxrow.Top = myForm.lblExpenseList.Top + 30
                dmxrow.Update()
            Else
                dmxrow.SendToBack()
                dmxrow.Left = 40
                dmxrow.Top = myForm.Controls("mxrow" & CStr(ii - 1)).Bottom - 30
                dmxrow.Update()
            End If
        Next
    Else
        Dim dmxrow As New MXrow
        dmxrow.Name = "mxrow1"
        myForm.Controls.Add(dmxrow)
        dmxrow.Left = 40
        dmxrow.Top = myForm.lblExpenseList.Top + 30
        dmxrow.cboMXSuperCategory.SelectedIndex = -1
        dmxrow.txtMXCategory.Text = ""
        dmxrow.txtMXExpenseName.Text = ""
        dmxrow.btnMXAdd.Tag = "0"
        dmxrow.btnMXAdd.Text = "Enter"
        dmxrow.btnMXAlter.Enabled = False
        dmxrow.btnMXDelete.Enabled = False
        dmxrow.cbMXStatus.Checked = False
    End If
    Dim resettop = myForm.Controls("mxrow" & CStr(ii)).Bottom
    Dim btnMXReset As New Button
    btnMXReset.Name = "btnMXReset"
    myForm.Controls.Add(btnMXReset)
    btnMXReset.Text = "Reset"
    btnMXReset.BackColor = Color.White
    btnMXReset.Left = (myForm.Width / 2) - (btnMXReset.Width / 2)
    btnMXReset.Top = resettop + 15
    AddHandler btnMXReset.Click, AddressOf btnMXReset_Clicked
    resettop = btnMXReset.Bottom + 15
    Dim btnMXClose As New Button
    btnMXClose.Name = "btnMXClose"
    myForm.Controls.Add(btnMXClose)
    btnMXClose.Text = "Close"
    btnMXClose.BackColor = Color.White
    btnMXClose.Left = (myForm.Width / 2) - (btnMXClose.Width / 2)
    btnMXClose.Top = resettop
    AddHandler btnMXClose.Click, AddressOf btnMXClose_Clicked
    resettop = btnMXClose.Bottom + 15
    Dim lblspacer As New Label
    myForm.Controls.Add(lblspacer)
    lblspacer.Text = ""
    lblspacer.Left = (myForm.Width / 2) - (lblspacer.Width / 2)
    lblspacer.Top = resettop
End Sub

Open in new window



2. Add this form (inside the zip file) to your project:
LoadingForm.zip
First extract the zip file to a folder and be sure to add both files (LoadingForm.vb and LoadingForm.Designer.vb) to your project.


3. Update your mdgExpListMgr_Load method with this:
Private Sub mdgExpListMgr_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        Me.SuspendLayout()
        Me.BackgroundImage = Nothing
        pbExpListBackground.SendToBack()
        Me.Hide()
        Application.DoEvents()

        Using myLoadingForm As New LoadingForm(AddressOf LoadMyFormControls)
            myLoadingForm.ShowDialog(Me)
        End Using

        Me.Show()
    Finally
        Me.ResumeLayout(True)
        Application.DoEvents()
    End Try
End Sub

Open in new window


Try it, I hope it works :)
0
 

Author Comment

by:stuengelman
Comment Utility
Hi yv989c,

It appears the class LoadingForm does not exist in VS 2008.

Stu
0
 
LVL 17

Expert Comment

by:Carlos Villegas
Comment Utility
Hi Stu, LoadingForm class is the form in step 2, you must add these files to your project, do you need help with this step?
0
 

Author Comment

by:stuengelman
Comment Utility
Oops, missed that.  Let me try again.

Stu
0
 

Author Comment

by:stuengelman
Comment Utility
yv989c,

An excellent job, but one small problem.  Unless all other apps are minimized, the main app window of the system as well as the dialog popup disappear under the other apps.  Is there any way to bring the main app and dialogbox back to being the active windows (the dialogbox should sit on top of the main app window)?

Thanks, Stu
0
 

Author Comment

by:stuengelman
Comment Utility
yv989c,

A clarification to my last post.  The app I'm working on does not lose focus when I press the button on the main app form to pop the dialog box.  The issue only arises when I press the Reset button on the dialog box itself; in this latter case, the VB app main screen and dialog box end up in back of all non-minimized windows from other open applications.

Stu
0
 
LVL 17

Accepted Solution

by:
Carlos Villegas earned 350 total points
Comment Utility
Hello, I'm not sure, try this:
Private Sub mdgExpListMgr_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Try
        Me.SuspendLayout()
        Me.BackgroundImage = Nothing
        pbExpListBackground.SendToBack()
        Me.Hide()
        Application.DoEvents()

        Using myLoadingForm As New LoadingForm(AddressOf LoadMyFormControls)
            myLoadingForm.ShowDialog(Me)
        End Using

        Me.Show()
        Me.Activate()
    Finally
        Me.ResumeLayout(True)
        Application.DoEvents()
    End Try
End Sub

Open in new window

I'm using the Activate method (line #14), it will activate your form and gives it focus.
0
 

Author Closing Comment

by:stuengelman
Comment Utility
Thanks for all the help.  Awarded points to both x77 and yv989c as both made contributions to the final solution.  Congrats to yv989c for solving the final issue about getting the app form to reactivate after refresh.  Very complex problems were solved in this thread, and both of you did a great job.
0

Featured Post

What Should I Do With This Threat Intelligence?

Are you wondering if you actually need threat intelligence? The answer is yes. We explain the basics for creating useful threat intelligence.

Join & Write a Comment

Preface This is the third article about the EE Collaborative Login Project. A Better Website Login System (http://www.experts-exchange.com/A_2902.html) introduces the Login System and shows how to implement a login page. The EE Collaborative Logi…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…
HTML5 has deprecated a few of the older ways of showing media as well as offering up a new way to create games and animations. Audio, video, and canvas are just a few of the adjustments made between XHTML and HTML5. As we learned in our last micr…

763 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now