4

我创建了一个简单的 CompositeControl 并公开了一个 Nullable DateTimeOffset 属性。我正在使用将控件绑定到 SQL Server DateTimeOffset 字段

DateTimeOffset='<%# Bind("myDateTimeOffsetField") %>'

当 DateTimeOffset 字段有值时,这很有效。但是当该字段为 NULL 时,我会收到“指定的转换无效”错误。

当字段为 NULL 时,如何停止此错误并将我的属性设置为 Nothing?

我认为这将是默认行为!

属性定义为:

Public Property DateTimeOffset As DateTimeOffset?

后来评论:

我发现如果我从使用 Bind 更改为:

DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>'

但是我没有在 FormView.ItemUpdating 事件中将“myDateTimeOffsetField”作为参数传递(是的,这是在 FormView 控件中),因为 ASP.NET 假定我没有绑定回数据库。

实际代码(按要求添加)

这是我试图绑定到的复合控件中的属性:

Public Property DateTimeOffset As DateTimeOffset?
Get
    Return CType(ViewState("DTO"), DateTimeOffset?)
End Get
Set(value As DateTimeOffset?)
    ViewState("DTO") = value
End Set
End Property

这是绑定的标记。控件位于 FormView 的 EditItemTemplate 中,它绑定到 SQL DataSource,返回一个名为 [dtoMldRejOn] 的字段,其中包含可选的 DateTimeOffset 值。

<APS:DateTimeOffsetControl runat="server" id="dtocMldRejOn" TextBoxCssClass="inputdatetime" ValidationGroup="vw1" FieldName="<%$ Resources: Resource, rxgFrom %>" DateTimeOffset='<%# Bind("dtoMldRejOn") %>' WindowsTimeZoneID="<%# me.WindowsTimeZoneID %>" IsRequired="false" />

如您所见,我的 Composite 控件用于处理 DateTimeOffset 值。除非数据库中的 DateTimeOffset 字段 [dtoMldRejOn] 为 NULL,否则一切正常,然后我得到异常。

4

5 回答 5

1

我以前从未创建过可绑定控件,但我想提出建议。如何将您的DateTimeOffset属性设置为 type Object。这样,该属性将接受任何数据类型,包括 DBNull。

进入Set代码后,检查传递的值是否为 DBNull.Value。如果是这样,创建一个新的空 DataTimeOffset?对象并将其保存在 ViewState 中。

如果非 DBNull 值,如果不能转换为日期时间,则抛出错误。

不过我没有尝试过,所以我不知道这是否可行。

############### 更新答案################

我的建议是,您创建 2 个属性,如下所示:

Public Property DateTimeOffset() As DateTimeOffset?
    Get
        Return DirectCast(ViewState("DTO"), DateTimeOffset?)
    End Get
    Set(ByVal Value As DateTimeOffset?)
        ViewState("DTO") = Value
    End Set
End Property

<Bindable(True, BindingDirection.TwoWay)>
Public Property DbDateTimeOffset As Object
    Get
        Return Me.DateTimeOffset
    End Get
    Set(value As Object)
        If IsDBNull(value) OrElse value Is Nothing Then
            Me.DateTimeOffset = New DateTimeOffset?
        Else
            Me.DateTimeOffset = DirectCast(value, DateTimeOffset?)
        End If
    End Set
End Property

因此,在您的标记中,绑定将是DbDateTimeOffset属性:

DbDateTimeOffset='<%# Bind("myDateTimeOffsetField") %>'

在后面的代码中,您可以使用其他属性来读取属性而无需强制转换。

于 2013-05-04T02:09:23.487 回答
0

基于这篇文章

我认为您只需要使用属性标记您的Bindable属性:

<System.ComponentModel.Bindable(True)> _
Public Property DateTimeOffset As DateTimeOffset?
于 2013-05-03T17:40:20.810 回答
0

问题在于它与你的代码DbNull不同Nothing,你必须在代码中的某个地方明确地写出来。我的第一个想法是使用绑定事件来添加值。因此,如果您保留这样的代码:

DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>'

您可以在绑定进行之前手动DateTimeOffset在事件中添加参数Updating(如果需要,我可以稍后更新答案,提供更多详细信息)

无论如何,在更仔细地阅读了您的代码之后,我认为可能CType没有正确转换。你试过用这样的Get东西代替你的吗?

Get
    Return If(IsDbNull(ViewState("DTO")), Nothing, CType(ViewState("DTO"), DateTimeOffset?))
End Get
于 2013-05-06T01:25:55.717 回答
0

你的代码iif ... 对我有用。
我已经创建了一个测试控件和一个带有页面代码的页面版本(我也测试了版本代码,但是这个更容易发布)。我的VS2010目标框架是4.0。首先是控件(TstNullableCtrl.ascx):

<%@ Control Language="vb" AutoEventWireup="false" %>
<script runat="server">
    Public Property DateTimeOffset As DateTimeOffset?
</script>
<div ID="Label1" runat="server" >
 <%= If(DateTimeOffset.HasValue, DateTimeOffset.ToString, "Empty")%>
</div>

和页面 - 一个两行两列绑定到数据网格(TstNullablePage.aspx)的表:

<%@ Page Language="vb" AutoEventWireup="false"  %>
<%@ Import Namespace="System.Data"%>
<%@ Register src="TstNullableCtrl.ascx" tagname="TstNullableCtrl" tagprefix="uc1" %>
<script runat="server">
    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim tbl As New DataTable
        tbl.Columns.Add(New DataColumn("id", GetType(Integer)) With {.AutoIncrement = True})
        tbl.Columns.Add(New DataColumn("myDateTimeOffsetField", GetType(DateTimeOffset)))
        Dim row As DataRow
        row = tbl.NewRow : row("myDateTimeOffsetField") = DateTimeOffset.Now
        tbl.Rows.Add(row)
        row = tbl.NewRow : row("myDateTimeOffsetField") = DBNull.Value
        tbl.Rows.Add(row)
        tstgrd.DataSource = tbl : tstgrd.DataBind()
    End Sub
</script>
<html>
<body>
    <form id="form1" runat="server">
      <asp:datagrid ID="tstgrd" runat="server">
        <Columns>
         <asp:TemplateColumn HeaderText="Offset">
           <itemtemplate>    
             <uc1:TstNullableCtrl ID="WithNullableDate1" runat="server" 
               DateTimeOffset='<%# iif(IsDbNull(Eval("myDateTimeOffsetField")), Nothing, Eval("myDateTimeOffsetField")) %>' />
            </itemtemplate>
         </asp:TemplateColumn>
         </Columns>
        </asp:datagrid>
    </form>
</body>
</html>

和预期的结果(有时为一个值,为空时为“空”)

结果

编辑

但是我认为“避免复杂化”的最佳解决方案如下:

Public _DateTimeOffset As Object
Public Property DateTimeOffset As Object
Get
    If IsDBnull(_DateTimeOffset) then Return Nothing
    Return Ctype(_DateTimeOffset, DateTimeOffset?) 
End Get
Set(value As Object)
    _DateTimeOffset = value
End Set
End Property 
于 2013-05-06T08:59:46.060 回答
0

我知道这个问题已经得到回答我只想记录我的解决方案,它位于这两个答案之间,因为我今天遇到了这个问题:

Private _AssetId As Object
<Bindable(True, BindingDirection.TwoWay)>
Public Property AssetId() As Object
    Get
        If _AssetId Is Nothing Then                
             Return Nothing                
        Else
            Return CType(_AssetId, Integer)
        End If
    End Get
    Set(ByVal value As Object)
        If value Is Nothing OrElse IsDBNull(value) OrElse CType(value, String) = "" Then
            _AssetId = Nothing                
        Else
            _AssetId = CType(value, Integer)                
        End If
    End Set
End Property
于 2015-09-10T22:46:00.403 回答