Need an inner loop to keep going while an outer loop loops

dlvonde

Active member
Joined
Oct 26, 2007
Messages
26
Programming Experience
1-3
OK I don't know how to describe the problem in one sentence.

I have an application I've been working on that monitors hardware stats on multiple pc's..things like hard drive free space, memory usage, cpu utitilization, etc.

I am using custom user controls to show all these stats so that each computer's information is represented in a tabControl. I created a loop that loops through each computername in an array and grabs the info about that computer then adds it to a flowlayoutpanel.

The Problem:
each new userControl that is created represents a different server, and I need for the information inside that userControl to be polled for the server it represents every few seconds.

So if I make my usercontrol run on a loop to poll for information every few seconds then it never breaks out of itself so my "outer loop" can create the next userControl.

so I'm guessing I'm needing to know if I can create a new userControl, let it start doing it's thing, but allow the computer to keep on creating more userControls?

thanks
 
here is my code to hopefully demonstrate my dilemma

VB.NET:
Expand Collapse Copy
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim i As Integer

        Dim serverArray(4) As String
        serverArray(0) = "Serv2K3"
        serverArray(1) = "SCHOOL"
        serverArray(2) = "Vista64"
        serverArray(3) = "Oldschool"


        For i = 0 To 3
            Dim u As New ServerResultsControl
            u.GetHWInfo(serverArray(i))
            u.Name = "Server" & i.ToString
            FlowLayoutPanel1.Controls.Add(u)
        Next

    End Sub
End Class

as you can see, the names of each userControl is dynamically created, so I can't just make a loop afterwards that calls the GetHWInfo function of each object because I don't know the names of the objects...and even if I did know what they would be the program wouldn't compile because those names haven't been created yet. Is there a way I can do some sort of for each loop to crawl through every one of my usercontrols and execute the GetHWInfo function periodically?

if I loop beforehand the form never shows up as it's endlessly looping through one of the userControls..
 
thanks for your replies. I used a loop because the idea is to be able to feed in as many server names as is on the network then create a control for each one. so I needed something that would allow me to dynamically create as many as I needed (the array of server names is just a temporary solution. it will eventually read from a file).

I also needed to be able to call on the objects again to re-run their functions to get updated info. Here's what I did so far:

VB.NET:
Expand Collapse Copy
Imports System.Management

Public Class Form1
    Dim serverArray(4) As String
    Dim serverResultsArray(serverArray.Length - 2) As ServerResultsControl

    Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim i As Integer

        serverArray(0) = "Serv2K3"
        serverArray(1) = "SCHOOL"
        serverArray(2) = "Vista64"
        serverArray(3) = "Oldschool"

        For i = 0 To (serverArray.Length - 2)
            serverResultsArray(i) = New ServerResultsControl
            serverResultsArray(i).GetPCName(serverArray(i))
            ' add the rest of the functions here.
            FlowLayoutPanel1.Controls.Add(serverResultsArray(i))
        Next

        Me.Timer1.Start()
    End Sub

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
        Dim i As Integer

        For i = 0 To serverArray.Length - 2
            serverResultsArray(i).GetHDInfo(serverArray(i))
        Next
    End Sub
End Class

I created a timer but I will create a few different timers to get different bits of information at say 10 sec, 30 sec, 1 min...etc. to hopefully gain some performance.

If this multi-threading will help the performance I'm open to suggestions.

thanks!
 
I was talking to someone else who mentioned if I could make the timer run in a seperate thread then it wouldn't hang my main form while the fields were being updated in it...is this true? and if so how would I go about doing it?

As of right now the forms seem to only be getting half updated and they are hanging really bad...
 
You don't run a Timer in any thread. You Start the Timer and it runs. When the Timer raises an event, THEN you have choices. If you've used a Timers.Timer then it can raise its Elapsed event in either the UI thread or on a background thread, depending on whether you set the SynchronizingObject property. If you used a Windows.Forms.Timer then it raises its Tick event in the UI thread, but you can spawn a new thread from there if you want.
 
ok please forgive my ignorance as coding with threads is completely new to me.
I guess I need to explain better what outcome I hope to achieve..then you or someone else can tell me if it's doable and point me in the right direction. I certainly don't expect anyone to do the work for me, just give me a nudge :)

as you can see in my code..the form loads and it creates several instances of a custom user control I created ServerResultsControl. This control goes through a series of WMI queries to get information from different computers. The results of the query are pumped directly into progress bars & labels on the control. so each time a query is performed the control hangs while it waits to get the results fed to it.

I believe what i need is for all of the WMI queries to occur in a background thread and have the results of those queries stored in string/int variables, then interact with the UI just long enough to update the labels/progress bars. This way the impact to the responsiveness of the UI is greatly minimized.

Does that make sense? and if so how do I made a function/etc. run in a background thread?

If I could have all those queries that usually hang the form/controls up run in the background and just update the controls with the string variables that contain the results I should be good to go.

I hope this all makes sense. I had 2 root canals yesterday and took an extra strength vicoden an hour ago so I don't have all my wits about me.

thanks again for everyone's help with this. I've got 2 weeks left on this project and thanks to your help it's going to be great.
 
Here are a couple of possibilities:

1. Add a Windows.Forms.Timer to your UserControl. When it Ticks you initiate a BackgroundWorker. You handle the ProgressChanged or RunWorkerCompleted events to update the control's UI.

2. Add a Timers.Timer to your UserControl with nothing assigned to its SynchronizingObject property. When it Elapses you do the work and then use delegation to update the UI.
 
ok, Since I'm using a Windows.Forms.Timer I believe I'll go the Background Worker route..I was doing some reading and it seems like I should do the following:
1) Within the timer create a new Background Worker Event.
2) set the background worker Do Work event/function to perform all the queries/etc. then store the values in int's and strings
3) Then use the ProgrressChanged event/function to somehow pass those int's/strings back to the UI

does that sound right? Every example I see says something different and they are passing objects back and not actual variables.

thanks again.
 
Last edited:
You would just create one BackgroundWorker, probably adding it to the form in the designer. You'd create a DoWork event handler and a ProgressChanged and/or RunWorkerCompleted event handler. When your Timer Ticks you would test the IsBusy property of the BGW and, if it's False, you call RunWorkerAsync. When you need to update the UI you can either call ReportProgress and pass the data via the UserState parameter if you need to update as you go. Alternatively, if you just want to wait until all the work is done to update the UI you can assign the data to the e.Result property and get it back in the RunWorkerCompleted from the same property.
 
OK

- I created a windows.forms.timer on the control (it was on the mainform before)

- I created a backgroundworker.

- when the timer tick event occurs it checks the background workers isBusy property. If not I run the backgroundworkers runWorkerAsync function.

- It seems as though this triggers the background workers DoWork function. in the DoWork functions I put all the methods of my usercontrol class I want to be run. I am setting the usercontrol up so all the queries it does goes into string and int variables.

- Now my forms come up quickly and I can navigate while the methods of all the usercontrols are run in the background. the final hurdle is getting the strings and integers into the controls.

so since I want all the methods to run, then have the strings/int's loaded into the userform I suppose this means I need to go the e.Results route.

so my final question (hopefully) is how do i "assign the data to the e.Result property and get it back in the RunWorkerCompleted from the same property. "????

do I do this inside the DoWork method at the end?
 
here's my code so far

VB.NET:
Expand Collapse Copy
Imports System.Management
Imports System.ComponentModel


Public Class ServerResultsControl
    Dim computerName As String

    Dim cpuName As String
    Dim loadPercentage As Integer
    Dim mainCPULabelString As String

    Dim hddName As String                          ' THESE ARE ALL THE VALUES
    Dim hardDriveSize As Double                   ' I NEED TO GET BACK TO THE 
    Dim hddFreeSpace As Double                  ' UI!!!
    Dim hddPercentFree As Double
    Dim hddSizeString As String
    Dim hddprogress As Integer
    Dim hddPercentFreeString As String

    Dim memoryCapacity As Double
    Dim freeMemory As Double
    Dim percentFreeMemory As Double
    Dim percentFreeMemoryString As String
    Dim percentFreeMemoryProgress As Integer

    Dim servicesList As String
    Dim processes As String


    Public Sub GetStaticNames(ByVal machineName As String)
        ' Gets the PC Name and HDD Name..code omitted
    End Sub

    Public Sub GetCPUStats(ByVal machineName As String)
        ' GETS CPU Speed, Utilization, and Name
    End Sub

    Public Sub GetHDInfo(ByVal machineName As String)
        ' GET HARD DRIVE SIZE & Free Space
    End Sub

    Public Sub GetMemoryInfo(ByVal machineName As String)
        ' GET MEMORY TOTAL SIZE AND FREE 
    End Sub


    ' GET NETWORK UTILIZATION


    Public Sub GetServicesProcesses(ByVal machineName As String)
        ' GET SERVICES & PROCESSES

    End Sub


    Private Sub serverControlTimer_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles serverControlTimer.Tick
        If serverControlBW.IsBusy = False Then
            serverControlBW.RunWorkerAsync()
        End If
    End Sub

    Private Sub serverControlBW_DoWork(ByVal sender As System.Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles serverControlBW.DoWork
        GetCPUStats(computerName)
        GetHDInfo(computerName)
        GetMemoryInfo(computerName)
        GetServicesProcesses(computerName)
    End Sub
End Class
 
ok i finally f igured it out...if I stuff a variable from my usercontrol class into e.result and then pull it out of e.result in the runworkercompleted method I can stick it into my userform.

so I guess i have one final questions...i've got a lot of strings and ints I need to send over to my form..can I somehow stuff all my variables in e.result and pull them all out at the same time?
 
Last edited:
can I somehow stuff all my variables in e.result and pull them all out at the same time?
Excellent progress so far. The answer to your question is "yes". The e.Result property in both the DoWork and RunWorkerCompleted event handlers are type Object, because the idea is that you can pass any object you like.

You should declare a class that has a property for each of the values you want to pass. You then create an instance of this class in the DoWork event handler, assign the appropriate values to each property and assign it to the e.Result property. In the RunWorkerCompleted event handler you cast the e.Result property as this type and get all the values back from the properties, updating the UI accordingly.

I should also point out that you terminology, and therefore your understanding of what's happening, is not quite right. DoWork is an event, not a method. You call the BackgroundWorker's RunWorkerAsync method and it raises its DoWork event in response. This will invoke all methods registered as handlers for that event, which will include the method you generated by double-clicking it in the design window. That event handler is a method, but it's a member of the form, not the BackgroundWorker.
 
Back
Top