很抱歉,这是我能提出的最好的主题,如果我更好地理解解决方案,我可能会说出更好的主题。
我正在使用一个很棒的网格控件,超级列表,位于此处:
在您阅读此问题之前,请注意您可以下载一个非常小的VB.NET 2005示例应用程序来解决问题:
http://dokmanovich.com/Documents/SuperListEvents.zip
我希望能够回答我的问题,帮助我更好地理解我想要完成的动态事件。
网格的工作方式如下:向网格添加列时,指定将在运行时返回值的事件处理程序的地址。在这种情况下,CC_ItemValueAccessor函数。后一个函数将使用输入参数调用,在这种情况下,该参数是“ToDo”对象。每个ToDo对象将在网格中呈现为一行。 CC_ItemValueAccessor函数的作用是返回网格显示的列值,该列对应于传入的ToDo对象的行。
这一切正常,直到我把它带到下一步:
我希望动态在运行时创建列。例如,我想显示由于执行用户指定的SQL而返回的数据表的输出。
使用前面描述的静态方法,我有一个columnItemValueAccessor函数负责返回传入的行对象的网格中每列的值。现在,由于列是在运行时根据SQL返回的结果确定的,我相信我需要编写一个处理所有列的通用处理程序,确定触发此事件的列的名称,然后在其中返回该列的值作为唯一参数传入的行对象。
问题是ItemValueAccessor函数有一个只包含行对象的签名,我不知道如何确定需要哪个列名,因为所有列都连接到与事件相同的ItemValueAccessor函数处理程序。
我怀疑这只是控件的一个限制,为了克服这个问题,我必须增强底层的自定义控件,但这可能超出了我目前的技能,因为它是用C#编写的高级控件而且我是一个VB人。
以下是代码:
Private Sub AddCcColumn()
Dim NewColumn As New BinaryComponents.SuperList.Column("CC", "CC", 110, AddressOf Cc_ItemValueAccessor)
_SuperList.Columns.Add(NewColumn)
End Sub
Private Function Cc_ItemValueAccessor(ByVal rowItem As Object) As Object
Dim ToDo As ToDo = CType(rowItem, SrToDoAndException).ToDo
Return ToDo.CCs.ToString
End Function
“---------------------------
以下是Column的instantiator方法的签名以及最后一个参数的定义,该参数负责指定处理的过程,以识别负责返回列值的事件处理程序。
Public Sub New(ByVal name As String,ByVal caption As String,ByVal width As Integer,ByVal columnItemValueAccessor As BinaryComponents.SuperList.ColumnItemValueAccessor) BinaryComponents.SuperList.Column
的成员Public Sub New(ByVal对象As Object,ByVal方法As System.IntPtr) BinaryComponents.SuperList.ColumnItemValueAccessor
的成员有人有任何建议或者我被卡住了吗?我真的很想利用这个控件的幻想分组功能,所以我可以显示动态输出,允许用户按照他们想要的任何列对SQL的动态输出进行分组。
我在上述网站向作者提出了这个问题,但是没有得到答复。这是一种绝望的尝试,希望找到一种方法。
谢谢你的支持。我希望这个问题不会因为我提到第三方控制而被拒绝。我希望答案在于更好地理解代表,这是一个更普遍的话题。
答案 0 :(得分:4)
我使用了lambda函数,正如Matthew建议的那样。以下是动态方法的代码:
Private Sub btnDynamic_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDynamic.Click
ListControl1.Columns.Clear()
For Each DataCol As DataColumn In _ds.dtbPerson.Columns
' Get the column name in a loop variable - it needs to be in loop scope or this won\'t work properly'
Dim colName = DataCol.ColumnName
' Create the function that will be called by the grid'
Dim colLambda As ColumnItemValueAccessor = Function(rowItem As Object) General_ItemValueAccessor(rowItem, colName)
' Setup each column in the grid'
Dim NewColumn As New BinaryComponents.SuperList.Column(DataCol.ColumnName, DataCol.ColumnName, 220, colLambda)
ListControl1.Columns.Add(NewColumn)
Next
End Sub
Private Function General_ItemValueAccessor(ByVal rowItem As Object, ByVal colName As Object) As Object
Dim rowPerson As DataRow = CType(rowItem, DataRow)
Return rowPerson.Item(colName).ToString
End Function
以下是它如何运作的快速入门:
每次循环时,lambda函数都会为每个列创建一个新的回调函数,如下所示:
Class Func1
Dim colName1 As String = "PersonId"
Private Function General_ItemValueAccessor1(ByVal rowItem As Object) As Object
Dim rowPerson As DataRow = CType(rowItem, DataRow)
Return rowPerson.Item(Me.colName1).ToString
End Function
End Class
Class Func2
Dim colName2 As String = "LastName"
Private Function General_ItemValueAccessor2(ByVal rowItem As Object) As Object
Dim rowPerson As DataRow = CType(rowItem, DataRow)
Return rowPerson.Item(Me.colName2).ToString
End Function
End Class
... for however many columns you have - 3 in this case.
您需要循环中的colName变量,而不是直接在lambda中使用DataCol.ColumnName。否则,当网格到处调用回调函数时,该DataCol变量将等于集合中的最后一个值(或Nothing),用于所有回调函数。
基本上,它会这样做,你不会得到你所期望的:
Class Func
Dim DataCol1 = DataCol
Private Function General_ItemValueAccessor1(ByVal rowItem As Object) As Object
Dim rowPerson As DataRow = CType(rowItem, DataRow)
Return rowPerson.Item(Me.DataCol1.ColumnName).ToString
End Function
Private Function General_ItemValueAccessor2(ByVal rowItem As Object) As Object
Dim rowPerson As DataRow = CType(rowItem, DataRow)
Return rowPerson.Item(Me.DataCol1.ColumnName).ToString
End Function
...
End Class
希望有所帮助。祝你好运。
答案 1 :(得分:1)
问题是ItemValueAccessor函数有一个只包含行对象的签名,我不知道如何确定需要哪个列名,因为所有列都连接到与事件相同的ItemValueAccessor函数处理程序。
好吧,我过去没有使用过这个控件,而且我真的是一个C#人。但我认为您可以通过为每列创建新的lambda function来实现此目的。类似的东西:
Private Sub AddCcColumn(ByVal sender As System.Object As System.String)
colLambda = (Function(rowItem As Object) Cc_InternalItemValueAccessor(columnName, rowItem))
Dim NewColumn As New BinaryComponents.SuperList.Column("CC", "CC", 110, colLambda)
_SuperList.Columns.Add(NewColumn)
End Sub
然后,colLambda将适合签名,而您的内部Cc_InternalItemValueAccessor将获得所需的信息。完全未经测试,但我认为基本想法有效。