DataGridView with thread vb.net? - vb.net

**I hav problem when i use DataGridView1 with thread
i get empty rows like image **
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim thread As New Thread(AddressOf grid)
thread.Start()
End Sub
Public Function grid()
For i As Int16 = 1 To 50
Invoke(Sub()
DataGridView1.Rows.Add(i)
DataGridView1.Refresh()
End Sub)
Next
End Function
https://i.stack.imgur.com/KOXRR.jpg

This is a perfect example of why you MUST read the relevant documentation, especially if something doesn't work the way you expect. If you had bothered to read the documentation for the Add method you're calling here then you'd have seen that that particular overload adds the specific number of rows to the grid and that's all. At no point does it populate those rows with any data. The code you have is going to add 1+2+3+4+...+48+49+50 empty rows to your grid. If what you actually want is to add a single row each time where i is the data displayed in that row then you need to call one of the overloads of Add that does that, or else call the overload with no arguments to add a single row, then get that row and set the Value of a cell explicitly.
EDIT: The simplest way to add a row with i as data is to call the overload of Add that takes an array of cell values. If you only have one cell, you use an array with one element:
DataGridView1.Rows.Add({i})
The braces indicate that the contents is an array. It's shorthand for this:
DataGridView1.Rows.Add(New Integer() {i})
Note that, if you pass a single Integer, the overload with a single Integer parameter will be called as it's the closest match. If you were to pass multiple discrete Integers, e.g.
DataGridView1.Rows.Add(i, i)
then you would not have the same problem because there is no overload with multiple Integer parameters. In that case, the overload that takes an array of Objects would be called. That overload's parameter is declared ParamArray, which means that you can pass either multiple individual objects or a single array. Another option would be to cast your Integer as type Object, which would also cause the overload that takes an array of Objects to be called:
DataGridView1.Rows.Add(CObj(i))
When you call an overloaded method, the closest valid match will be called, so be sure that your arguments match the parameters of the overload you want to call and make sure you understand what each overload does. ALWAYS read the documentation if you aren't 100% sure. The F1 key and the Help menu are there for a reason.

Related

Data Grid view only displaying one letter in the cell

I am trying to add rows to a datagridview and when loading the from it only displays one letter on the variable I am trying to retrieve.
Dim col As New DataGridViewTextBoxColumn 'adding the colunm player to the data grid view
col.HeaderText = "Player"
DataGridView_displayfigures.Columns.Add(col)
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
This is the structure
Structure AssignRuns
Shared batsman1A As String = PlayerSelection.player1_cmbox.Text
Shared batsman1Aruns As Integer
I don't understand this. any help would be appreciated
This is a perfect example of why you should have Option Strict On. You are use a String constructor here:
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
But that is definitely not doing what you intend. You are passing a String array as an argument but there is no String constructor that has a parameter of type String array. With Option Strict On, that would generate a syntax error and your code would fail to compile until you fixed it.
With Option Strict Off, the compiler looks for a constructor that is similar enough that it can massage your code to work. In this case, it uses the one that has a parameter of type Char array. That constructor creates a String containing all the Char values from the array.
In your case, each String in your array is converted to a Char by simply taking the first character in each String. Your array only contains one String so only one Char is passed to the constructor, so the String that gets created only contains one character.
As well as that, there's no overload of that Add method that takes a single String either. There is one that takes an Object array though, so that's what you should be passing:
DataGridView_displayfigures.Rows.Add(New Object() {AssignRuns.batsman1A})
This would also work:
DataGridView_displayfigures.Rows.Add({AssignRuns.batsman1A})
That is technically passing a String array to the Add method but that is allowed because it's a widening conversion, i.e. no data can be lost. Converting a String to a Char is a narrowing conversion because data can be lost, as it was in your original code. Option Strict On allows implicit widening conversions but not implicit narrowing conversions.
EDIT:
Actually, thinking about that last code snippet and the fact that you can pass a String array directly to Add makes me think that maybe your mistake was just to misplace a single closing parenthesis because, rather than this:
DataGridView_displayfigures.Rows.Add(New String({AssignRuns.batsman1A}))
you could have had this:
DataGridView_displayfigures.Rows.Add(New String() {AssignRuns.batsman1A})
Moving that closing parenthesis means that you are denoting a String array and then initialising it, rather than passing a literal String array as an argument to a constructor.
You can try me this way to add rows and columns in the DataGridView control.
Public Class Form1
Structure AssignRuns
Shared batsman1A As String = "player1"
Shared batsman1Aruns As Integer = 3
End Structure
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'definite columncount and then add columns of datagridview1
DataGridView1.ColumnCount = AssignRuns.batsman1Aruns
DataGridView1.Columns(0).HeaderText = "Player"
'add rows of datagridview1
Dim row As String() = {AssignRuns.batsman1A} 'You can try {AssignRuns.batsman1A,AssignRuns.batsman1A,AssignRuns.batsman1A}
DataGridView1.Rows.Add(row)
End Sub
End Class

vb.net Passing a list through a function without list value changed [duplicate]

This question already has answers here:
Argument passed ByVal to VB.NET Function and manipulated there
(2 answers)
Closed 4 years ago.
The list value changeed here when passed ByVal why
,it must be not changed.
Private Sub Button6_Click(sender As Object, e As EventArgs) Handles Button6.Click
Dim value As Integer = 1
Dim value2 As New List(Of Decimal)
value2.Add(1)
value2.Add(2)
' The integer value doesn't change here when passed ByVal.
Example1(value)
Console.WriteLine(value)
' The list value changeed here when passed ByVal.
Example3(value2)
Console.WriteLine(value)
End Sub
Sub Example1(ByVal test As Integer)
test = 10
End Sub
Sub Example3(ByVal test As List(Of Decimal))
test.Add(3)
End Sub
its solved ,the solution is making new copy:
Sub Example3(ByVal test As List(Of Decimal))
Dim testnew As New List(Of Decimal)
testnew.AddRange(test)
testnew.Add(3)
End Sub
You need to do some reading on value types and reference types and passing method arguments by value and by reference. They are related but not the same thing. When you pass a method argument by value, you create a copy of the variable being passed. If the variable is a value type, i.e. a structure, then that means creating a copy of the value. If the variable is a reference type, i.e. a class, then that means creating a copy of the reference. The thing is, the original reference and the copy still both refer to the same object.
The reason that reference types exist is that you wouldn't want to create copies of large objects every time you assigned them somewhere. In the case of passing a collection to a method, it's almost always the case that any change you make inside the method you will want to be reflected outside. In the rare case that you don't, it's up to you to create a copy of the collection first and pass that in.
When you pass a value type by value, you create a copy of the value. That means that no changes you make inside the method can affect the original variable. You can assign a new value to the parameter or you can set a property of the value and the change will not be reflected outside the method. Of course, value types should generally be immutable and so setting a property should not be possible, but there are times that that "rule" gets broken.
When you pass a reference type by value, you create a copy of the reference. That means that assigning a different object to the parameter inside the method will not affect the original variable. There is still only one object though, referred to by the original variable and the parameter. As such, if you set a property of that object via the parameter then that change will be reflected in the original variable, because it's the same object.
When you pass a value type by reference, you create a new reference to the value. That means that any changes you make inside the method will affect the original variable. You can assign a new value to the parameter or you can set a property of the value and the change will be reflected outside the method.
When you pass a reference type by reference, you create a new reference to the original reference. That means that assigning a different object to the parameter inside the method will affect the original variable. There's still just one object, so setting a property on the parameter will still affect the original variable too.
Those are the only four possibilities: value type by value, reference type by value, value type by reference and reference type by reference. In none of those scenarios is a copy of a reference type object made so in none of those scenarios can you set a property of a reference type object via a method parameter and have that change not be reflected in the original variable.
If you want a copy of the original object then it's up to you to create one explicitly. Whether you do that inside the method or outside really depends on the specific circumstances. That means that you need to change your code to this:
Sub Example3(ByVal test As List(Of Decimal))
Dim copy = test.ToList()
copy.Add(3)
End Sub
or this:
Dim copy = value2.ToList()
Example3(copy)
Let me just repeat the important point here: there is NO WAY to pass a reference type object to a method, modify the object via the parameter inside the method and have that not affect the original variable (assigning a different object to the parameter is NOT modifying the object). If you want a modification inside the method to not affect the original variable then you need a copy of the object and the ONLY way that will happen is if YOU do it explicitly.

VBA Assign value (only) to variable

I've hit a snag, and my searching hasn't helped so far.
I have a variant being passed into a function which I then intend to copy, perform some calculations, take another copy, perform some other calculations then compare the results of the two copies...
However, when I perform the calculations on one copy, the original variant is also manipulated... so after two copies, and two calculations I end up with 3 variants that are equal to each other and different to the original... Not what I intended.
I expect this is happening because when I use NewVar = OldVar I'm actually taking a reference to the original object. What I actually want, is to make an independent duplicate of the original object - i.e. copy the value of the variable similar to byval in a function delcaration.
My code is linked here: https://1drv.ms/x/s!AiPgb0BH-YZ_ga956eMmJbSdihGjyg.
If you put a break on line 67 of modMain, then watch CutList(1).QTY (the original variable), and CutTrial.RemainingCuts(1).QTY you'll see that both the QTY values decrement when you step through line 67... I want CutList(1).QTY to remain unchanged, and CutTrial.RemainingCuts(1).QTY to decement only.
Any suggestions?
Make sure the functions definition is as follows
Public function DoMagic(ByVal variable as something)
Don't use ByRef or as you found it will modify the reference.
If you are using an object, array or collection you will need to first copy it before using it.
Eg something like the following:
Public Function Clone() As Class1
Set Clone = New Class1
Clone.prop1 = prop1
Clone.PrivateThing = PrivateThing
End Function

Integer in VB.net turns into String in VBA

I have a list of objects that are "keys" into a table - the keys are simply the items in the first column. They can be Integers or Strings, depending on what DB table we read it from. Since we use them a lot, we cache that column in an ArrayList called "Keys".
We wrote cover methods to return Row, one that uses strings and the other integers. If you call the integer version it simply returns that row by index. If you call the string, it looks down Keys for a match, and uses that index to pull out the row.
Ok, so now I pass Keys to Excel, pull out one of them in a loop, and ask it what it is...
TypeName(DB.Keys(i))
And the object returns...
Long
Great, the keys must have been integers! So now I'll try to get the row for that key, by calling the accessor method, Row...
DB.Row(DB.Keys(i))
And it calls into the version that takes a String.
Whoa!
Can anyone think of a reason that VBA calling back into our VB.net DLL ends up calling the wrong accessor?
ADDED CODE: I can't figure out how to put the code in as a reply, so I'm editing this. Here is the code in the VB.net class:
Public Function Row(ByVal K As String) As DataRow
Dim R As DtaRow = DB.Tables(0).Rows(K)
Return New DataRow(R)
End Function
Public Function Accounts(ByVal K As Integer) As DataRow
Dim R As DtaRow = DB.Tables(0).Rows(K)
Return New DataRow(R)
End Function
If you're wondering, there's two versions of Rows, which take strings or ints.
This code works perfectly from VB.net. You can ask for a row by key string or by the row number, that invokes the proper Row, which calls the proper Rows, and out comes the proper answer.
But in VBA, it always calls the method with the string input. If I rename it to RowIHATEYOUALL then I can call the Integer version just fine. But when there are two of them, differing only in signature, no such luck.
And the A and i (see comments) was my typo.
The interop layer does not support overloaded methods. Whenever you call Row, the first declared method with that name is used. The .NET overload resolution algorithm does not apply here.
Other overloads are exposed to VBA as Row_2, Row_3, etc. Thus, the following code should do what you expect:
DB.Row_2(DB.Keys(i))
This implicit dependency on the order of declaration has a high potential for error. Thus, I would suggest to either
give the methods unique names if they are called from VBA,
or, if you want to retain the "nice" overloaded version for .NET, add compatibility methods for VBA:
<Obsolete("Compatibility method for VBA, use Row instead.")>
Public Function RowByKeyVBA(ByVal K As String) As DataRow
Return Row(K)
End Function
<Obsolete("Compatibility method for VBA, use Row instead.")>
Public Function RowByNumberVBA(ByVal K As Integer) As DataRow
Return Row(K)
End Function
Further information can be found in the following question:
COM->.NET - can't access overloaded method
Following Heinzi's notes (above) I fixed this by making three method signatures for each call, one takes an Object and then attempts to figure out what it is, the others take the String and Integers. Within VB/C#/etc the proper String or Integer methods get called as expected, from VBA the Object version is called, as Heinzi noted
This causes the very minor issue that a user may have a "number like value" that is actually a String. For instance, the array keys might be "User3232" or "3232", both of which are String objects in the table. So you have to be careful, simply asking if the Object can be converted to an Int32 is not enough. This is unlikely to be something that effects most users.

ByVal DataTable Manipulation

I think I'm missing something fundamental about how DataTables work. The following procedure starts with GetData, bringing in what as a filled DataTable. All the following code does is pass through copies of the datatable, manipulate it, then return it:
Sub GetData(ByVal what As DataTable)
Dim Part As DataTable = Generate(what)
End Sub
Function Generate(ByVal brown As DataTable)
Dim lameface As DataTable = DoStuff(brown)
Return lameface
End Function
Function DoStuff(ByVal cow As DataTable)
Dim result As DataTable = cow
result.Rows.RemoveAt(0)
Return result
End Function
The way this is written above, function DoStuff will remove the top row from result and cow. Similarly, brown and what will also have that first row removed, even though they are sent as ByVal.
If I change the first line in DoStuff from
Dim result As DataTable = cow
to
Dim result As DataTable = cow.copy
then cow, brown and what are left alone. Why is this? Marking a parameter as ByVal is supposed to send a copy of the object instead of the original, so why do I have tell it to use a copy when instantiating result? If I do a similar procedure using integers instead of datatables, it works as I would expect. What am I missing about datatables?
I poked around on MSDN's articles for datatables and didn't see anything that spoke to this. Thanks for your help!
The ByVal keyword doesn't necessarily indicate that a copy of the value is passed to the method. If the parameter is a reference type, like a DataTable, then a copy of the pointer is passed to the method - it still references the same object, so any changes made to the object in the method will be maintained once the method completes execution.
The ByRef keyword would permit the method to change the object the variable is pointing to, or the actual value if the parameter is a simple type (like int).
In your situation above, if you want to remove a row inside DoStuff, but not affect the source DataTable, then you need to make a copy of the DataTable before doing the remove operation.