我似乎无法找到有效的解决方案。
我有一个基于DataGridViewTextboxColumn的自定义datagridview单元格。我正在使用VB 2005。
我正在尝试实现一个设计时属性,我可以使用该属性存储要由列中的单元格使用的SQL语句。每行的查找相同,但返回的值不同。
我有一个版本需要我在CellFormatting和RowsAdded事件期间设置语句,但是我想这样做我所要做的就是提供一个SQL语句(即从JobList中选择JobName,其中JobNo = {0})作为列类中的属性。我想绑定单元格并使用它获取的值作为语句的替换值。我无法将SQL语句属性保留(右词?)
我的部分问题是,我不确定该属性是否应该包含在自定义COLUMN或自定义CELL定义中。我一直在尝试将属性添加到列中,这似乎是合乎逻辑的,因为我希望每个实例都使用相同的值,如果单元格不必在每次触发单元格格式事件时都设置语句值。
我发现并尝试了这些属性:
<Browsable(True), _
EditorBrowsable(EditorBrowsableState.Always), _
Category("Data"), _
Description("The SQL Query to use for lookup. Make sure it will work with string.format"), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
Public Property ScalarSQLStatement() As String
End Property
它不起作用。我可以在列编辑器中输入值,但如果我退出编辑器并返回属性,则重置为默认值。
编辑----
我已经为DataGridTextboxCell创建了子类并将其放入其中:
Imports System.ComponentModel
Public Class DataGridViewScalarValue2TextboxCell
Inherits DataGridViewTextBoxCell
Private _scalarStatement As String = String.Empty
Private _ReturnValue As String = String.Empty
Private _LookupValue As Object
Public Property LookupValue() As Object
Get
Return _LookupValue
End Get
Set(ByVal value As Object)
_LookupValue = value
End Set
End Property
Public Sub New()
Me._LookupValue = Nothing
If Me.OwningColumn Is Nothing Then Return
Me.ScalarStatement = CType(Me.OwningColumn, DataGridViewScalarValue2TextboxColumn).ScalarSQLStatement
End Sub
Public Property ScalarStatement() As String
Get
Return _scalarStatement
End Get
Set(ByVal Value As String)
_scalarStatement = Value
End Set
End Property
' Override the Clone method so that the Enabled property is copied.
Public Overrides Function Clone() As Object
Dim Cell As DataGridViewScalarValue2TextboxCell = CType(MyBase.Clone(), _
DataGridViewScalarValue2TextboxCell)
Cell._scalarStatement = Me._scalarStatement
Return Cell
End Function
Protected Overrides Function GetFormattedValue(ByVal value As Object, _
ByVal rowIndex As Integer, _
ByRef cellStyle As DataGridViewCellStyle, _
ByVal valueTypeConverter As TypeConverter, _
ByVal formattedValueTypeConverter As TypeConverter, _
ByVal context As DataGridViewDataErrorContexts) As Object
If _LookupValue <> value Then
_LookupValue = value
GetReturnValueFromLookupValue()
End If
Return MyBase.GetFormattedValue(_ReturnValue, rowIndex, cellStyle, _
valueTypeConverter, formattedValueTypeConverter, context)
End Function
Protected Overrides Sub Paint(ByVal graphics As Graphics, _
ByVal clipBounds As Rectangle, _
ByVal cellBounds As Rectangle, _
ByVal rowIndex As Integer, _
ByVal cellState As DataGridViewElementStates, _
ByVal value As Object, _
ByVal formattedValue As Object, _
ByVal errorText As String, _
ByVal cellStyle As DataGridViewCellStyle, _
ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
ByVal paintParts As DataGridViewPaintParts)
If value IsNot Nothing AndAlso _
(TypeOf value Is String AndAlso Not String.IsNullOrEmpty(value)) OrElse _
(TypeOf value Is Integer AndAlso Integer.TryParse(value, Nothing)) OrElse _
(TypeOf value Is Decimal AndAlso Decimal.TryParse(value, 0)) OrElse _
(TypeOf value Is Date) AndAlso IsDate(value) Then
_LookupValue = value
GetReturnValueFromLookupValue()
Else
_ReturnValue = String.Empty
End If
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, _
_ReturnValue, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
Private Sub GetReturnValueFromLookupValue()
If _LookupValue Is Nothing _
Or OwningColumn Is Nothing _
Or String.IsNullOrEmpty(_scalarStatement) Then
_ReturnValue = Nothing
Return
End If
Using conn As New SqlClient.SqlConnection(ConnUtils.MyGCPTableConnectionString)
conn.Open()
Dim cmd As SqlClient.SqlCommand = conn.CreateCommand
With cmd
.CommandText = String.Format(_scalarStatement, _LookupValue)
.CommandType = CommandType.Text
Dim objResult = .ExecuteScalar
If objResult IsNot Nothing Then
_ReturnValue = objResult
End If
End With
conn.Close()
End Using
End Sub
Public Overloads Property Value() As Object
Get
Return _ReturnValue
End Get
Set(ByVal value)
If TypeOf value Is Integer AndAlso value > 0 Then
If _LookupValue <> value Then
_LookupValue = value
GetReturnValueFromLookupValue()
End If
End If
End Set
End Property
End Class
我为DataGridViewTextboxColumn类做了同样的事情。在我的原帖中引用它的主要属性(用于此用法)。该子类中包含以下代码:
Imports System.ComponentModel
Public Class DataGridViewScalarValue2TextboxColumn
Inherits DataGridViewTextBoxColumn
Public Sub New()
Me.CellTemplate = New DataGridViewScalarValue2TextboxCell()
End Sub
'' Fields...
Private _scalarSQLStatement As String = String.Empty
<Browsable(True), _
EditorBrowsable(EditorBrowsableState.Always), _
Category("Data"), _
Description("The SQL Query to use for lookup. Make sure it will work with string.format"), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
Public Property ScalarSQLStatement() As String
Get
Return _scalarSQLStatement
End Get
Set(ByVal Value As String)
_scalarSQLStatement = Value
End Set
End Property
在表单中,我使用如下的CellFormatting和RowsAdded事件:
Private Sub dgvCustomCellTypes_CellFormatting(ByVal sender As Object, ByVal e As .DataGridViewCellFormattingEventArgs) Handles dgvCustomCellTypes.CellFormatting
If e.ColumnIndex = colHaulID2.Index Then
Dim dgvr As DataGridViewRow = CType(sender, DataGridView).Rows(e.RowIndex)
Dim HaulCell As DataGridViewScalarValue2TextboxCell = CType(dgvr.Cells(colHaulID2.Index), DataGridViewScalarValue2TextboxCell)
HaulCell.ScalarStatement = colHaulID2.ScalarSQLStatement
End If
End Sub
Private Sub dgvCustomCellTypes_RowsAdded(ByVal sender As Object, ByVal e As DataGridViewRowsAddedEventArgs) Handles dgvCustomCellTypes.RowsAdded
For i As Integer = e.RowIndex To e.RowCount - 1
Dim dgvr As DataGridViewRow = CType(sender, DataGridView).Rows(i)
Dim HaulCell As DataGridViewScalarValue2TextboxCell = CType(dgvr.Cells(colHaulID2.Index), DataGridViewScalarValue2TextboxCell)
HaulCell.ScalarStatement = colHaulID2.ScalarSQLStatement
Next
End Sub
并将其添加到表单初始化:
colHaulID2.ScalarSQLStatement = "Select CompanyName From HaulCompany Where HaulID = {0}"
该列是数据绑定并在那里获取其查找值。它工作正常,但不是我正在寻找的解决方案。
我正在尝试重写单元格/列,以便我可以在设计时使用列编辑器将SQL语句添加到列中,并依赖于数据绑定值来提供查找键。
在我看来,唯一阻止我实现目标的是在设计时关闭列编辑器后让控件保存它的SQL语句。或者当我重新打开列编辑器时阻止它被清除。我不确定发生了什么。但我确信有一个解决方案。我在持久性方面做了一些尝试,包括我发现的类似VB6的属性包示例。我忽略了将属性保存到磁盘。似乎应该有一种让应用程序处理此任务的方法。到目前为止,没有什么对我有用
结束编辑
非常感谢任何帮助。
感谢。
马歇尔
答案 0 :(得分:1)
双击演示的第一列中的单元格。
Public Class Form1
Sub New()
' This call is required by the designer.'
InitializeComponent()
' Add any initialization after the InitializeComponent() call.'
Dim dtb As New DataTable
dtb.Columns.Add("C1")
dtb.Columns.Add("C2")
dtb.Columns.Add("C3")
dtb.Rows.Add("1", "2", "3")
dtb.Rows.Add("2", "3", "4")
dtb.Rows.Add("3", "4", "5")
dtb.Rows.Add("4", "5", "6")
DataGridView1.DataSource = dtb
DataGridView1.Columns(0).Tag = "Select JobName From JobList where JobNo = {0}"
End Sub
Private Sub DataGridView1_CellMouseDoubleClick(sender As Object, e As DataGridViewCellMouseEventArgs) Handles DataGridView1.CellMouseDoubleClick
Dim strSql As String = String.Format(DataGridView1.Columns(e.ColumnIndex).Tag.ToString, DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex).Value.ToString)
MsgBox(strSql)
End Sub
End Class
答案 1 :(得分:0)
我找到了我正在寻找的解决方案。
我需要覆盖列中的Clone方法(而不是单元格),并确保在运行时将属性传递给单元格。下面我发布我的最终解决方案。
(我在Stack Overflow上找到了我的解决方案here。)
Imports System.ComponentModel
Imports System.ComponentModel.Design
<Serializable()> _
Public Class DataGridViewScalarValueTextboxColumn
Inherits DataGridViewTextBoxColumn
Public Sub New()
Me.CellTemplate = New DataGridViewScalarValueTextboxCell()
End Sub
' Fields...'
Private _scalarSQLStatement As String = String.Empty
<Browsable(True), _
Category("Data"), _
Description("The SQL Query to use for lookup. Must work with the string.format function if lookup value is used."), _
DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)> _
Public Property ScalarSQLStatementCol() As String
Get
Return _scalarSQLStatement
End Get
Set(ByVal Value As String)
_scalarSQLStatement = Value
End Set
End Property
Public Overrides Function Clone() As Object
Dim myClone As DataGridViewScalarValueTextboxColumn = CType(MyBase.Clone, DataGridViewScalarValueTextboxColumn)
myClone.ScalarSQLStatementCol = ScalarSQLStatementCol
Return myClone
End Function
End Class
Public Class DataGridViewScalarValueTextboxCell
Inherits DataGridViewTextBoxCell
Private _ReturnValue As String = String.Empty
Private _LookupValue As Object
Public Property LookupValue() As Object
Get
Return _LookupValue
End Get
Set(ByVal value As Object)
_LookupValue = value
End Set
End Property
Public Sub New()
Me._LookupValue = Nothing
End Sub
Public Overrides Function Clone() As Object
'Method may not be needed now'
Dim Cell As DataGridViewScalarValueTextboxCell = CType(MyBase.Clone(), _
DataGridViewScalarValueTextboxCell)
Return Cell
End Function
Protected Overrides Function GetFormattedValue(ByVal value As Object, _
ByVal rowIndex As Integer, _
ByRef cellStyle As DataGridViewCellStyle, _
ByVal valueTypeConverter As TypeConverter, _
ByVal formattedValueTypeConverter As TypeConverter, _
ByVal context As DataGridViewDataErrorContexts) As Object
If _LookupValue <> value Then
_LookupValue = value
GetReturnValueFromLookupValue()
End If
Return MyBase.GetFormattedValue(_ReturnValue, rowIndex, cellStyle, _
valueTypeConverter, formattedValueTypeConverter, context)
End Function
Protected Overrides Sub Paint(ByVal graphics As Graphics, _
ByVal clipBounds As Rectangle, _
ByVal cellBounds As Rectangle, _
ByVal rowIndex As Integer, _
ByVal cellState As DataGridViewElementStates, _
ByVal value As Object, _
ByVal formattedValue As Object, _
ByVal errorText As String, _
ByVal cellStyle As DataGridViewCellStyle, _
ByVal advancedBorderStyle As DataGridViewAdvancedBorderStyle, _
ByVal paintParts As DataGridViewPaintParts)
If value IsNot Nothing AndAlso _
(TypeOf value Is String AndAlso Not String.IsNullOrEmpty(value)) OrElse _
(TypeOf value Is Integer AndAlso Integer.TryParse(value, Nothing)) OrElse _
(TypeOf value Is Decimal AndAlso Decimal.TryParse(value, 0)) OrElse _
(TypeOf value Is Date) AndAlso IsDate(value) Then
_LookupValue = value
GetReturnValueFromLookupValue()
Else
_ReturnValue = String.Empty
End If
MyBase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, _
_ReturnValue, errorText, cellStyle, advancedBorderStyle, paintParts)
End Sub
Private Sub GetReturnValueFromLookupValue()
If _LookupValue Is Nothing _
Or (OwningColumn Is Nothing _
OrElse CType(Me.OwningColumn, DataGridViewScalarValue2TextboxColumn).ScalarSQLStatementCol.Length = 0) Then
_ReturnValue = Nothing
Return
End If
Using conn As New SqlClient.SqlConnection(ConnUtils.MyGCPTableConnectionString)
conn.Open()
Dim cmd As SqlClient.SqlCommand = conn.CreateCommand
With cmd
.CommandText = String.Format(CType(Me.OwningColumn, DataGridViewScalarValue2TextboxColumn).ScalarSQLStatementCol, _LookupValue)
.CommandType = CommandType.Text
Dim objResult = .ExecuteScalar
If objResult IsNot Nothing Then
_ReturnValue = objResult
End If
End With
conn.Close()
End Using
End Sub
Public Overloads Property Value() As Object
Get
Return _ReturnValue
End Get
Set(ByVal value)
If TypeOf value Is Integer AndAlso value > 0 Then
If _LookupValue <> value Then
_LookupValue = value
GetReturnValueFromLookupValue()
End If
End If
End Set
End Property
End Class
我确信可以做更多的重构,但它确实有效。只需将列添加到网格中,为查找设置bind属性并设置SQL语句(必须只返回一个值)并运行它。只需要加载源数据。
谢谢大家。