-
Sep 28th, 2015, 04:11 PM
#1
Thread Starter
Junior Member
I'm adding objects to a list linked to a dgv. When I click the dgv I get an error.
Hello guys. I have this problem. I have a single form with two datagridview components (dgv1 and dgv2).
Both are linked to two list of Tobjeto. I have code in dgv1 that when I double click, I add an object to the list2.
All looks fine, but when I click on dgv2, I get a an error:
An unhandled exception of type 'System.IndexOutOfRangeException' occurred in System.Windows.Forms.dll
Additional information: Index -1 does not have a value.
Any ideas? Here is the code. You just need to have 1 form with two dgv (1 and 2).
Code:
Public Class TestForm
Dim list1 As New List(Of TObjecto)
Dim list2 As New List(Of TObjecto)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = 0 To 2
Dim producto As New TObjecto
producto.IDproducto = 0
producto.Nombre = "NOMBRE" & i.ToString
list1.Add(producto)
Next
dgv1.DataSource = list1
dgv2.DataSource = list2
End Sub
Private Sub RefrescarGrillas()
dgv2.DataSource = Nothing
dgv2.DataSource = list2
End Sub
Private Sub dgv1_CellDoubleClick(sender As Object, e As DataGridViewCellEventArgs) Handles dgv1.CellDoubleClick
Dim tmpPedido As New TObjecto
tmpPedido.IDproducto = 0
tmpPedido.Nombre = list1(e.RowIndex).Nombre
list2.Add(tmpPedido)
Me.RefrescarGrillas()
End Sub
End Class
Public Class TObjecto
Private _IDproducto As Integer
Public Property IDproducto() As Integer
Get
Return _IDproducto
End Get
Set(ByVal value As Integer)
_IDproducto = value
End Set
End Property
Private _Nombre As String
Public Property Nombre() As String
Get
Return _Nombre
End Get
Set(ByVal value As String)
_Nombre = value
End Set
End Property
End Class
THANKS!
-
Sep 28th, 2015, 06:46 PM
#2
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
This fixes it for me.
Code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = 0 To 2
Dim producto As New TObjecto
producto.IDproducto = 0
producto.Nombre = "NOMBRE" & i.ToString
list1.Add(producto)
Next
dgv1.DataSource = list1
' dgv2.DataSource = list2
End Sub
-
Sep 28th, 2015, 08:14 PM
#3
Thread Starter
Junior Member
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by passel
This fixes it for me.
Code:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = 0 To 2
Dim producto As New TObjecto
producto.IDproducto = 0
producto.Nombre = "NOMBRE" & i.ToString
list1.Add(producto)
Next
dgv1.DataSource = list1
' dgv2.DataSource = list2
End Sub
Thanks, I would try it back at home.
-
Sep 29th, 2015, 10:58 AM
#4
Thread Starter
Junior Member
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by passel
This fixes it for me.
In fact it does, so the question is why is this happening, the error I mean.
-
Sep 29th, 2015, 12:45 PM
#5
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by kwanbis
In fact it does, so the question is why is this happening, the error I mean.
This issue took a while to track down as the error did not present a stack trace. However, if you modify 'Sub RefrescarGrillas' like this:
Code:
Private Sub RefrescarGrillas()
dgv2.DataSource = Nothing
dgv2.DataSource = list2
dgv2.CurrentCell = dgv2.Item(0, dgv2.Rows.Count - 1)
End Sub
The added line will throw the same error, but this time you get a stacktrace and it reveals that the problem is in the CurrencyManager for List2. A CurrencyManager object is part of the behind the scenes databinding mechanism. You can retrieve a reference to it like this:
Code:
Dim cmList2 As CurrencyManager = CType(Me.BindingContext(list2), CurrencyManager)
I believe the problem arises due to the limited binding support for a simple IList object like List(Of T) and this is probably a bug in the .Net binding code that does not refresh the data bound list when it is bound to a object that does not support notification of changes.
However, the fact that you forced DGV2 to reflect changes with code like 'Sub RefrescarGrillas' is a clue that you should probably be doing things differently.
The simplest would be to declare the lists as 'System.ComponentModel.BindingList(Of TObjecto)' and eliminate 'Sub RefrescarGrillas'.
An alternative would be to redefine 'RefrescarGrillas' like this:
Code:
Private Sub RefrescarGrillas()
Dim cmList2 As CurrencyManager = CType(Me.BindingContext(list2), CurrencyManager)
cmList2.Refresh()
End Sub
This forces data binding to repopulate itself from the data source and the datagridview will then reflect those changes as well.
-
Sep 29th, 2015, 02:36 PM
#6
Thread Starter
Junior Member
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by TnTinMN
The simplest would be to declare the lists as 'System.ComponentModel.BindingList(Of TObjecto)' and eliminate 'Sub RefrescarGrillas'.
Thanks, that worked perfectly.
Originally Posted by TnTinMN
An alternative would be to redefine 'RefrescarGrillas' like this:
Code:
Private Sub RefrescarGrillas()
Dim cmList2 As CurrencyManager = CType(Me.BindingContext(list2), CurrencyManager)
cmList2.Refresh()
End Sub
This forces data binding to repopulate itself from the data source and the datagridview will then reflect those changes as well.
This also works perfectly. Can you explain a little bit more what the code does? THANKS!
-
Sep 29th, 2015, 04:34 PM
#7
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by kwanbis
...This also works perfectly. Can you explain a little bit more what the code does?
I can try, but no guaranty that it will make any sense.
When you set the DataSource property on the DatagridView control, you are creating a data binding for which there are three parts:- The data source. (in your case a List)
- A manager object. (CurrencyManager or PropertyManager Class)
- The data consuming control. (a DatagridView in your case)
A data source can represent a single item such as the Text property of a Control and in this case, the manager object will be an instance of (you guessed it!) the Property Manager class. When the data source is collection of items such as a List, the manager object will be a CurrencyManager instance.
The manager object handles the communication of data from the data source to the consuming control and also the reverse direction from the consuming control to the data source.
The CurrencyManager maintains an internal List of references to the items in the data source. If the underlying data source object is capable of providing notifications (an Event) that its contents have changed (an item was added or removed), then the CurrencyManager can automatically update its internal List to reflect these changes. However, not all data sources provide this notification. The System.Collections.Generic.List(Of T) is an example of a data source that does not provide any such notifications were-as the System.ComponentModel.BindingList(Of T) provides two events (AddingNew and ListChanged) that the CurrencyManager can subscribe to to keep its internal list current.
Since the CurrencyManager has no way of ascertaining of the List(Of T)'s current state, it is somewhat running blind when it tries to access the data source using references from its internal list. The only way to solve this issue, is for your code to tell it to update its internal list and hence the call to the CurrencyManager.Refreshmethod.
Code:
Dim cmList2 As CurrencyManager = CType(Me.BindingContext(list2), CurrencyManager)
cmList2.Refresh()
Hopefully that gives you a bit of the understanding about what is going on.
P.S.: I should have previously mentioned that you could also use a BindingSource as the data source for the Datagridview. The BindingSource Class implements ICurrencyManagerProvider, so it acts as its own CurrencyManager. However, you would still need to tell it of changes to the List(Of T) class by calling its ResetBindings method similar to the CurrencyManager.Refresh method.
-
Sep 29th, 2015, 10:18 PM
#8
Thread Starter
Junior Member
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by TnTinMN
Code:
Dim cmList2 As CurrencyManager = CType(Me.BindingContext(list2), CurrencyManager)
cmList2.Refresh()
Thanks for the explanation.
About the code, what I understand is
1) you define cmList2 As CurrencyManager
2) then you convert the list2 to a concurrencymanager type in CType(Me.BindingContext(list2), CurrencyManager)
3) you then call refresh cmList2.Refresh()
What I don't understand is this "Me.BindingContext(list2)". Why do you have to do that? Why can't you do CType(list2, CurrencyManager)?
THANKS ONCE MORE!
-
Sep 30th, 2015, 01:23 AM
#9
Registered User
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
I can try, but no guaranty that it will make any sense.
บาคาร่าออนไลน์ 1688
-
Sep 30th, 2015, 10:31 AM
#10
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by kwanbis
...
What I don't understand is this "Me.BindingContext(list2)". Why do you have to do that? Why can't you do CType(list2, CurrencyManager)?
The technical answer is because 'list2' is a instance of List(Of T) and as such it is not an instance of CurrencyManger nor does it derive from CurrencyManager.
The form's BindingContext property returns either a CurrencyManager or a PropertyManager for the specified data source (list2) as a BindingManagerBase Class type.
CurrencyManager derives from BindingManagerBase, so cast (CType) to CurrencyManager is valid. The BindingManagerBase Class does not implement the Refresh method. This method is implemented in the CurrencyManager Class.
P.S: I do hope that you understand that the items appearing in light blue in the text such as:
are links that you should click on for more information.
-
Oct 4th, 2015, 11:19 AM
#11
Thread Starter
Junior Member
Re: I'm adding objects to a list linked to a dgv. When I click the dgv I get an error
Originally Posted by TnTinMN
P.S: I do hope that you understand that the items appearing in light blue in the text such as:
are links that you should click on for more information.
Thanks for all your help. It's been great.
But somehow it is not working.
RefrescarGrillas is now:
Dim cmListaPedidos As CurrencyManager = CType(Me.BindingContext(listaPedidos), CurrencyManager)
cmListaPedidos.Refresh()
This works perfectly the first time the form is shown.
But if I close the form and reopen, it does not works any more.
EDIT: So I just finished changing all lists to BindingList. Now I'm seeing how can I raise a BindingList event.
Apparently I need to create INotifyPropertyChanged.
EDIT2: So I was able to do everything I wanted. Thanks so much for your help! (probably would have more questions latter )
Last edited by kwanbis; Oct 4th, 2015 at 06:52 PM.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|