Sql server 具有特殊属性的DataGridView自定义列

Sql server 具有特殊属性的DataGridView自定义列,sql-server,vb.net,datagridview,custom-controls,Sql Server,Vb.net,Datagridview,Custom Controls,我似乎找不到有效的解决办法 我有一个基于DataGridViewTextboxColumn的自定义datagridview单元格。我用VB2005来做这个 我正在尝试实现一个设计时属性,可以用来存储列中的单元格使用的SQL语句。每行的查找相同,但返回的值不同 我有一个版本要求我在CellFormatting和RowsAdded事件期间设置语句,但我希望这样做,我所要做的就是提供一个SQL语句(即从JobList中选择JobName,其中JobNo={0})作为column类中的属性。我想绑定单元

我似乎找不到有效的解决办法

我有一个基于DataGridViewTextboxColumn的自定义datagridview单元格。我用VB2005来做这个

我正在尝试实现一个设计时属性,可以用来存储列中的单元格使用的SQL语句。每行的查找相同,但返回的值不同

我有一个版本要求我在CellFormatting和RowsAdded事件期间设置语句,但我希望这样做,我所要做的就是提供一个SQL语句(即从JobList中选择JobName,其中JobNo={0})作为column类中的属性。我想绑定单元格并使用它得到的值作为语句的替换值。我无法使SQL语句属性保持不变(对吗

我的部分问题是,我不确定该属性应该放在自定义列还是自定义单元格定义中。我一直在尝试将属性添加到列中,这似乎是合乎逻辑的,因为我希望在每次触发单元格格式事件时,如果单元格不必设置语句值,则每个实例都使用相同的值

我找到并尝试了以下属性:

<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
并将其添加到表单初始化中:

    colHaulID2.ScalarSQLStatement = "Select CompanyName From HaulCompany Where HaulID = {0}"
该列是数据绑定的,并在那里获取其查找值。它工作正常,但不是我正在寻找的解决方案

我正在尝试重写单元格/列,以便在设计时使用列编辑器将SQL语句添加到列中,并依靠数据绑定值提供查找键

在我看来,阻止我实现目标的唯一一件事是,在设计时关闭列编辑器后,让控件保存它的SQL语句。或者在我重新打开列编辑器时防止它被清除。我不确定发生了什么。但我相信有一个解决办法。我在持久化方面做了一些尝试,包括我发现的一个类似VB6的属性包示例。我忽略将属性保存到磁盘。似乎应该有一种方法让应用程序处理此任务。到目前为止,我什么都没用

结束编辑

任何帮助都将不胜感激

谢谢


Marshall

双击演示第一列中的单元格

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

我找到了我一直在寻找的解决方案

我需要重写列(而不是单元格)中的Clone方法,并确保在运行时将属性传递给单元格。下面我将发布我的最终解决方案

(我在堆栈溢出上找到了解决方案。)

导入System.ComponentModel
导入System.ComponentModel.Design
_
公共类DataGridViewScalarValueTextboxColumn
继承DataGridViewTextBoxColumn
公共分新()
Me.CellTemplate=新建DataGridViewScalarValueTextboxCell()
端接头
“字段…”
Private _scalarSQLStatement作为String=String.Empty
_
公共属性ScalarSQLStatementCol()作为字符串
得到
Return\u scalarSQLStatement
结束
设置(ByVal值作为字符串)
_scalarSQLStatement=值
端集
端属性
公共重写函数Clone()作为对象
将myClone设置为DataGridViewScalarValueTextboxColumn=CType(MyBase.Clone,DataGridViewScalarValueTextboxColumn)
myClone.ScalarSQLStatementCol=ScalarSQLStatementCol
返回myClone
端函数
末级
公共类DataGridViewScalarValueTextboxCell
继承DataGridViewTextBoxCell
Private _returnvalueas String=String.Empty
Private _LookupValue作为对象
作为对象的公共属性LookupValue()
得到
返回_LookupValue
结束
设置(ByVal值作为对象)
_LookupValue=值
端集
端属性
公共分新()
Me.\u LookupValue=无
端接头
公共重写函数Clone()作为对象
'现在可能不需要方法'
将单元格设置为DataGridViewScalarValueTextboxCell=CType(MyBase.Clone()_
DataGridViewScalarValueTextboxCell)
返回单元
端函数
受保护的覆盖函数GetFormattedValue(ByVal值作为对象_
ByVal行索引为整数_
ByRef cellStyle作为DataGridViewCellStyle_
ByVal valueTypeConverter作为类型转换器_
ByVal formattedValueTypeConverter作为类型转换器_
ByVal上下文作为DataGridViewDataErrorContexts)作为对象
如果_LookupValue值,则
_LookupValue=值
GetReturnValueFromLookupValue()
如果结束
Return MyBase.GetFormattedValue(_ReturnValue,rowIndex,cellStyle_
valueTypeConverter,格式化的valueTypeConverter,上下文)
端函数
受保护的覆盖子绘制(ByVal图形作为图形_
ByVal剪贴簿为矩形_
ByVal单元格边界为矩形_
ByVal行索引为整数_
ByVal cellState作为DataGridViewElementState_
ByVal值作为对象_
ByVal formattedValue作为对象_
ByVal errorText作为字符串_
ByVal cellStyle作为DataGridViewCellStyle_
ByVal advancedBorderStyle作为DataGridViewAdvancedBorderStyle_
ByVal paintParts作为DataGridViewPaintParts)
如果值不是空,那么_
(值的类型是String,也不是String.IsNullOrEmpty(值))或_
(TypeOf值是整数,也是整数。TryParse(value,Nothing))或_
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}"
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
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