|
OK, it doesn't work the way you think because you are essentially blocking the UI thread You are having it do thousands of updates to the UI and those updates are competing with the message pump to get the window and controls repainted.
In this example, you may as well not even use threading. The end result is the same. You're not really removing "work" from the UI thread. The only "work" you have on the background threads is incrementing a couple of counters and if statements. The bulk of the "work" is still upating the UI and only the UI thread can do that.
Oh, and you don't need to Invoke consecutive statements and the Refreshes are unnecessary. By putting the Refreshes in, you're actually doubling the number of WM_PAINT messages Windows is sending your application.
Your code should look more like this:
Imports System.Threading
Public Class Form1
Private Const MAXCOUNT As Integer = 10000
Private i1 As Integer
Private i2 As Integer
Private Sub count1()
Do While i1 < MAXCOUNT
i1 += 1
UpdateLabel(i1.ToString, Label1)
Loop
End Sub
Private Sub count2()
Do While i2 < MAXCOUNT
i2 += 1
UpdateLabel(i2.ToString, Label2)
Loop
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
i1 = 0
Dim t As New Thread(AddressOf count1)
t.Start()
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
i2 = 0
Dim t2 As New Thread(AddressOf count2)
t2.Start()
End Sub
Private Sub UpdateLabel(message As String, c As Label)
If Me.InvokeRequired Then
Me.Invoke(Sub()
c.Text = message
End Sub)
Else
c.Text = message
End If
Thread.Sleep(1)
End Sub
End Class
But, wait a minute. What's with the Thread.Sleep() ? By sleeping the background threads for a tiny bit, you're preventing them from hogging the CPU and giving the UI thread a chance to process the messages in the message pump. These messages are various UI things like WM_PAINT, WM_MOVE and WM_MOUSEMOVE messages that Windows sends to tell your application to paint various windows and controls, that the window is moving, and the mouse is moving and over a control.
Like I said, if you flood the UI thread with Invokes like you did, the UI will not be able to process these messages and update the window.
|
|
|
|
|
Thank you Dave, most helpful...
Yeah I can see its overkill for the work its doing, it was more a simple exercise to try and learn something about multithreading & invoke than a need for more processing.
I guess I should be putting some effort into passing variables when calling subs so as to cut down on the coding too!
Thanks again
Tony 
|
|
|
|
|
That's good. All of the concepts apply to normal applications. We normally put the work on background threads and shove all UI update work to the UI thread.
Normally, you're not updating the UI that often for what you're seeing to be a problem. The Thread.Sleep() is in there just to get the background threads in your example to back off a bit. Normally, you don't need it.
|
|
|
|
|
Thanks for the help and tips for future work...
Tony 
|
|
|
|
|
Hi again Dave..
where you say - ' you don't need to Invoke consecutive statements ' how would you script an invoke in the case of needing to perform 2 separate UI updates?
Cheers
Tony
|
|
|
|
|
Private Sub UpdateLabel(message As String, c As Label)
If Me.InvokeRequired Then
Me.Invoke(Sub()
c.Text = message
otherControl.Text = something
someOtherControl.Property = soemthingElse
End Sub)
Else
c.Text = message
otherControl.Text = something
someOtherControl.Property = soemthingElse
End If
Thread.Sleep(1)
End Sub
|
|
|
|
|
A gent and a scholar!
Thanks Dave 
|
|
|
|
|
Hai,
Am developing vb.net2008 windows application. I have two datagridview table datagridview1 column one has combobox. It stored 4 string. below see the code.
Dim gridComboBox As New DataGridViewComboBoxCell
With datagridFunction
If .Rows.Count = 0 Then Return 0
gridComboBox.Items.Add("LTrim")
gridComboBox.Items.Add("RTrim")
gridComboBox.Items.Add("Insert")
gridComboBox.Items.Add("Replace")
.Item(0, datagridFunction.CurrentRow.Index) = gridComboBox
.Visible = True
End With
am using following code
datagridview1.rows(0).cells(0).value = "LTrim"
datagridview1.rows(1).cells(0).value = "RTrim" but combobox value not showed in the datagridview. I don't know how to show combobox value here. plz help me very urgent
|
|
|
|
|
Not enough information to help you. Please, elaborate.
|
|
|
|
|
Hello,
I have my own mail template in vb6.0.
when i click on send button it creates a new outlook 2007 window. all information passes to it except subject message. on my local machine it is working but on client side not.
Thanks,
krunal
|
|
|
|
|
Without seeing your code it's impossible to tell you what you did wrong.
You REALLY should NOT be doing any new development work in VB6.
|
|
|
|
|
Here is the question:
12-player are in a 6-day competition. The competition have 6 different games. the rule is:
1. Every player must participate all 6 games.
2. Each player can only play the same game ONCE.
3, Each player can only play with the same opponent ONCE.
The problem is my algorithm cannot scheduling all the players into the games.
Here is my code:
Public Class clsGame
Public teams As ArrayList
Public Sub New(ByVal intTeamNumber As Integer)
teams = New ArrayList
teams.Capacity = intTeamNumber
End Sub
Public Sub add(ByVal intTeam As Integer)
If Not isFull() And Not contains(intTeam) Then teams.Add(intTeam)
End Sub
Public Function isEmpty() As Boolean
If teams.Count = 0 Then Return True
Return False
End Function
Public Function isFull() As Boolean
If teams.Count = teams.Capacity Then Return True
Return False
End Function
Public Function contains(ByVal intTeam As Integer) As Boolean
If teams.Contains(intTeam) Then Return True
Return False
End Function
End Class
Public Class clsSummerCamp
Public intDays As Integer
Public teams As New Queue
Public swimming() As clsGame
Public games(,) As clsGame
Public Sub New(ByVal intNewDays As Integer, ByVal intTeams As Integer)
intDays = intNewDays
ReDim swimming(intDays)
ReDim games(intDays, 6)
For intCount As Integer = 0 To intTeams - 1
teams.Enqueue(intCount)
Next
End Sub
Public Sub schedule(ByVal t As Queue)
Dim temp As Queue = t.Clone
initiateGames()
While Not temp.Count = 0
Dim intTeamNumber As Integer = temp.Dequeue
For intDay As Integer = 0 To intDays - 1
setGames(intDay, intTeamNumber)
Next
End While
End Sub
Public Sub initiateGames()
For intGameDay As Integer = 0 To games.GetUpperBound(0) - 1
For intCount As Integer = 0 To games.GetUpperBound(1) - 1
games(intGameDay, intCount) = New clsGame(2)
Next
Next
End Sub
Public Sub setGames(ByVal intDay As Integer, ByVal intTeam As Integer)
For intCount As Integer = 0 To games.GetUpperBound(1) - 1
If games(intDay, intCount).isEmpty Then
If Not isPlayed(intCount, intTeam) Then
games(intDay, intCount).add(intTeam)
Exit For
End If
ElseIf Not games(intDay, intCount).isFull Then
If Not games(intDay, intCount).contains(intTeam) And Not isPlayed(intCount, intTeam) Then
If Not isPlayedWith(games(intDay, intCount).teams.Item(0), intTeam) Then
games(intDay, intCount).add(intTeam)
Exit For
End If
End If
End If
Next
End Sub
Public Function isPlayed(ByVal intGame As Integer, ByVal intTeam As Integer) As Boolean
For intDay As Integer = 0 To games.GetUpperBound(0) - 1
If games(intDay, intGame).contains(intTeam) Then Return True
Next
Return False
End Function
Public Function isPlayedWith(ByVal intTeam1 As Integer, ByVal intTeam2 As Integer) As Boolean
For intDay As Integer = 0 To games.GetUpperBound(0) - 1
For intCount As Integer = 0 To games.GetUpperBound(1) - 1
If games(intDay, intCount).contains(intTeam1) And games(intDay, intCount).contains(intTeam2) Then Return True
Next
Next
Return False
End Function
Public Sub printSchedule()
schedule(teams)
For int1 As Integer = 0 To games.GetUpperBound(0) - 1
Console.Write("Games: ")
For int2 As Integer = 0 To games.GetUpperBound(1) - 1
Console.Write("{0,-10}", games(int1, int2).teams.Item(0) & " vs " & games(int1, int2).teams.Item(1) & " ")
Next
Console.WriteLine()
Next
End Sub
End Class
Module modTest
Sub Main()
Dim summerCamp As New clsSummerCamp(6, 12)
summerCamp.printSchedule()
Console.Read()
End Sub
End Module
|
|
|
|
|
Hi All,
i have a project that uses a Dll file that the owners are no longer maintaining but have released the source code. i have edited all the URLS to comply with the new twitter api v1.1. my problem is, is that the responses from the server are now sent back via JSON format and no longer XML but all the parse code is parsed via XML. i have no experience in XML or JSON so i was wondering how to go by fixing this so many people who like me are needing this .dll updated would really appreciated if someone can help convert it or some guidance on how to convert it. Bellow are some of the code that needs to be converted but there is a lot more.
Private Function ParseRelationships(ByVal Xml As String) As List(Of TwitterRelationship)
Dim XmlDoc As New XmlDocument
XmlDoc.LoadXml(Xml)
Dim Relationships As New List(Of TwitterRelationship)
For Each RelationshipNode As XmlNode In XmlDoc.SelectNodes("//relationship")
Relationships.Add(New TwitterRelationship(RelationshipNode))
Next
Return Relationships
End Function
Private Function ParseLists(ByVal Xml As String, ByRef NextCursor As Int64) As List(Of TwitterList)
Dim XmlDoc As New XmlDocument
XmlDoc.LoadXml(Xml)
Dim Lists As New List(Of TwitterList)
For Each ListNode As XmlNode In XmlDoc.SelectNodes("//list")
Lists.Add(New TwitterList(ListNode))
Next
NextCursor = Convert.ToInt64(XmlDoc.SelectSingleNode("//next_cursor").InnerText)
Return Lists
End Function
|
|
|
|
|
If you're working with JSON, then JSON.NET[^] is probably the best place to start.
However, you might do better to start with a library which supports v1.1 of the API. A quick look on the Twitter libraries page[^] provides several open-source options which look like they should fit your requirements:
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Thank you i shall look into it 
|
|
|
|
|
Hi Pete, what is it that you want to do with Twitter? I have used Linqtotwitter in Visual Basic successfully. Regards henry Hugo
|
|
|
|
|
Hi there,
This is a bit of a complicated question.
I'm building a Windows Form Application. In the database, there are paths to certain external resources. All of these resources are in a pool. In the past, just the absolute paths to the resources were saved, but now, I want to implement the app.config file to define a path to a "resource pool" and save the data as absolute paths from this pool.
All of the resources are on the same server, so I would like to get UNC paths. Problem is: the current paths are stored as normal Windows paths using a mapped network drive.
For example: the resource pool is located at \\fileserver\resx\resources . There's a mappad drive, X: , referring to \\fileserver\resx . In the current database, paths are stored as \\fileserver\resx\resources\img\img1.jpg or as X:\resources\img\img1.jpg (both notations are used randomly across the records).
What I want to achieve is the following. Let's say I've got the following URLs:
Dim strBase as String = "\\fileserver\resx\resources"
Dim strUrlA as String = "X:\resources\img\img1.jpg"
Dim strUrlB as String = "\\fileserver\resx\resources\img\img1.jpg"
Dim strUrlC as String = "Y:\tracks\track1.mp3"
Dim strUrlD as String = "\\fileserver\audio\tracks\track1.mp3"
Is there a method to convert those files as being relative to the pool? In this case, both strUrlA and strUrlB would be converted to img\img1.jpg and both strUrlC and strUrlD would be converted to ..\..\audio\tracks\track1.mp3 .
What would be a good way to handle this?
Thanks in advance!
Cheers!
|
|
|
|
|
You'll need to start by converting the mapped drive paths to UNC paths. If you have a fixed mapping scheme, you could do that manually. Otherwise, you'll need to P/Invoke WNetGetUniversalName[^] to convert the local paths to UNC paths.
Once you have consistent paths, you can use the Uri class[^] to parse the paths, and the MakeRelativeUri method[^] to get the relative paths.
Dim basePath As New Uri("\\fileserver\resx\resources\")
Dim pathA As New Uri("\\fileserver\resx\resources\img\img1.jpg")
Dim pathARelative As String = basePath.MakeRelativeUri(pathA).ToString()
Dim pathB As New Uri("\\fileserver\audio\tracks\track1.mp3")
Dim pathBRelative As String = basePath.MakeRelativeUri(pathB).ToString()
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
Hi Richard,
First of all, thanks for your advice. Just two more questions though:
- Do I manually need to replace the forward slashes by back slashes in a Windows environment or does Windows do this for me (Win7/Win8)
- Is WNetGetUniversalName a plug-in I need or just a class I can create (by using the code on the page and just copying and pastng it into a new class?
Cheers!
|
|
|
|
|
Windows should be able to handle paths with forward-slashes. You can also use the Uri class to get back to the absolute path to the file:
Dim basePath As New Uri("\\fileserver\resx\resources\")
Dim pathBAbsolute As String = New Uri(basePath, "../../audio/tracks/track1.mp3").LocalPath
WNetGetUniversalName is a Windows API which isn't exposed through a .NET class. To access it, you have to use a technique called P/Invoke (short for "Platform Invoke"). The code samples on pinvoke.net are usually good enough to get you started.
"These people looked deep within my soul and assigned me a number based on the order in which I joined."
- Homer
|
|
|
|
|
|
hi, i can't view the attached photo because of security of my computer. But here's the codes that i'm using for combining the 3 cell into 1 cell.
]
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.ConnectionString = "Data Source=192.168.xx.xx;Initial Catalog=information;Persist Security Info=True;User ID=me;Password=cute"
cmd.Connection = con
con.Open()
Dim qr As String = "SELECT (Firstname + MI + Lastname) as Full_Name FROM directory1"
Dim ds As New DataSet
Dim da As New SqlDataAdapter(qr, con)
da.Fill(ds, "directory1")
DataGridView1.DataSource = ds
DataGridView1.DataMember = "directory1"
con.Close()
|
|
|
|
|
|
Hello !
I have groupbox with several controls inside.
When a condition is true , I want to prevent users clicking on the controls inside groupbox , but without disabling groupbox or controls.
How can I do that ?
|
|
|
|
|
This is counter-intuitive in the Windows interface application. If a control, like a button, is not greyed out people expect it to be clickable. This is referred to as a "consistent user experience" across all applications running in Windows.
If by "clickable" you mean that the use clicks a button and nothing happens, you have to "unwire" the Click event handler using the RemoveHandler[^] statement. This also means you have to rewire up the handler when you need it to work again, using AddHandler[^].
|
|
|
|