Create a View Data Form (CLR)

This task walks through steps to create a new View Data Form (CLR) Spec with the Add New Item wizard and to adjust the spec and class file for a specific table. The Table Spec that corresponds to this View Data Form (SP) Spec is shown in the steps.

  1. From an existing Blackbaud AppFx Catalog Project, right-click the project and select AddNew Item. The Add New Item screen appears.

  2. Select Blackbaud AppFx CatalogView Data Form Template Spec (CLR).

  3. From Name, enter a name such as Example.View.xml or Example.Clr.View.xml.

  4. Click Add. The new spec appears in Solution Explorer and in the XML Editor.

    In the spec that appears in the XML Editor...

  5. Leave the first three attributes of ViewDataFormTemplate as-is. The first two are namespace declarations for schema related to the spec type. The third is an ID for the feature, a GUID or uniqueidentifier generated by the Add New Item wizard. ID should be unique for every spec. The root element attributes for data forms are discussed in Root Element Attributes.

      xmlns="bb_appfx_viewdataformtemplate"
      xmlns:common="bb_appfx_commontypes"
      ID="137ed189-f88c-408e-a489-d412d23940b7"
  6. Adjust the next three attributes as necessary. The Add New Item wizard creates a Name and Description based on the filename entered in the Name field of the Add New Item screen. Author is inferred from a setting established when the Blackbaud Infinity SDK is installed.

    Note: To avoid future conflicts in the event Blackbaud adds an Example record type, add (custom) to the end of Name, RecordType, and SecurityUIFolder. If the (custom) suffix is not satisfactory for display, the NameUIOverride attribute can be used in addition to adding (custom). The Table Spec that corresponds to this View Data Form is described later in this task. The Name attribute for TableSpec is adjusted to Example (custom) in the Table Spec for the same reason.

    Change these attributes:

      Name="Example View Data Form"
      Description="A data form for viewing example records"
      Author="Technical Training"

    To:

      Name="Example View Data Form (custom)"
      Description="A data form for viewing example records"
      Author="Technical Training"
  7. DataFormInstanceID is an additional ID. DataFormInstanceID is discussed in Root Element Attributes. But remember that most features refer to data forms by DataFormInstanceID and not ID.

    DataFormInstanceID="7d382c51-7b83-4c96-b878-6c6056d51364" 
  8. The last two attributes can also be adjusted. Again, the wizard infers each based on the filename entered in the Name field of the Add New Item screen. But to avoid future conflicts in the event Blackbaud adds an Example record type, add the (custom) suffix.

    Change these attributes:

      RecordType="Example"
      common:SecurityUIFolder="Example"

    To:

      RecordType="Example (custom)"
      common:SecurityUIFolder="Example (custom)""
  9. Specify to explicitly grant permissions to the CLR code to select data from the table. Otherwise the database may deny the read. Adjust CLRDataForm as follows:

      <CLRDataForm AssemblyName="Blackbaud.CustomFx.Example.Catalog"
                   ClassName="Blackbaud.CustomFx.Example.Catalog.ExampleViewDataForm" >
        <common:GrantSelectList>
          <common:GrantSelect>USR_EXAMPLE</common:GrantSelect>
        </common:GrantSelectList>
      </CLRDataForm>
  10. Within the Visual Basic class file created by the wizard for the form, a Load() function is declared. View Data Form implementations are discussed in View Data Form Implementations.

    At this point, take some time to examine the Table Spec and table that relates to this Add Data Form. This Table Spec has few embellishments. The fields on the data form's stored procedure for the save implementation and the form fields on the Add Data Form will correspond to the fields on this Table Spec. Notice the Name attribute of TableSpec matches the RecordType for the Add Data Form.

    <TableSpec
    	xmlns="bb_appfx_table"
    	xmlns:common="bb_appfx_commontypes"
    	ID="4455ac1b-c6f0-4a56-b708-77942a823811"
    	Name="Example (custom)"
    	Description="Stores information about example records (custom)"
    	Author="Technical Training"
    	Tablename="USR_EXAMPLE"
    	IsBuiltIn="false"
    	>
    
      <Fields>
        <TextField Name="SHORTNAME" Length="10"/>
        <TextField Name="LONGNAME" Length="20"/>
        <MemoField Name="DESCRIPTION"/>
        <DecimalField Name="RATING" />
      </Fields>
    
    </TableSpec>

    The spec created by the wizard is configured for three fields: FIELD1, FIELD2, and FIELD3. The data types for these should correspond to the data types established by the platform for SHORTNAME, LONGNAME, and DESCRIPTION when the example Table Spec is loaded. Therefore, in the Add Data Form Spec, FIELD1, FIELD2, and FIELD3 can be changed to SHORTNAME, LONGNAME, and DESCRIPTION. But for now, add those in to the CLR for the save implementation.

    Note: The wizard for Add Data Form Spec (SP) creates stubbed-out Transact-SQL including mapping between the table fields, stored procedure parameters, and form fields. The wizard for Add Data Form Spec (CLR) stubs out the form fields, but leaves the mapping to you.

  11. Initially, the class looks like this:

    Imports Blackbaud.AppFx.Server
    
    Public NotInheritable Class ExampleViewDataForm
        Inherits AppCatalog.AppViewDataForm
    
        Public Overrides Function Load() As Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult
    
        End Function
    
    End Class

    Add public instances for the parameters:

    Imports Blackbaud.AppFx.Server
    
    Public NotInheritable Class ExampleViewDataForm
        Inherits AppCatalog.AppViewDataForm
    
        Public SHORTNAME As String
        Public LONGNAME As String
        Public DESCRIPTION As String
        Public RATING As Decimal
    
        Public Overrides Function Load() As Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult
    
        End Function
    
    End Class
  12. The function should return Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult.

        Public Overrides Function Load() As Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult
            Dim loadResult As Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult
            Return loadResult
        End Function
  13. In the function, use SqlClient.SqlConnection to connect to the database and execute a command. CommandText is built as a String similar to (but not the same as) the SELECT statement in the View Data Form (SP) task example. The parameter is added with the AddWithValue function. The public instances added earlier are used.

    Closing Connections

    Sometimes your code requires an unmanaged resource, such as a SQL connection. If the SqlConnection goes out of scope, it won't be closed. Therefore, you must explicitly close the connection by calling Close or Dispose. You may also consider a Using block which guarantees the disposal of one or more such resources when your code is finished with them. For more information see http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.close.aspx and http://msdn.microsoft.com/en-us/library/htd05whh.aspx.

    For example, the following code would require the explicit closing of the connection:

    Dim conn As SqlConnection = Me.RequestContext.OpenAppDBConnection
    		‘code to perform work with the sql connection
    conn.Close
    

    Whereas utilizing a Using block guarantees the disposal of the SQLConnection:

    using conn As SqlConnection = Me.RequestContext.OpenAppDBConnection
            ‘code to perform work with the sql connection
    end using
    Imports Blackbaud.AppFx.Server
    
    Public NotInheritable Class ExampleViewDataForm
        Inherits AppCatalog.AppViewDataForm
    
        Public SHORTNAME As String
        Public LONGNAME As String
        Public DESCRIPTION As String
        Public RATING As Decimal
    
        Public Overrides Function Load() As Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult
            Dim loadResult As New Blackbaud.AppFx.Server.AppCatalog.AppViewDataFormLoadResult(False)
    
            Try
                Using con As SqlClient.SqlConnection = Me.RequestContext.OpenAppDBConnection()
    
                    Using command As SqlClient.SqlCommand = con.CreateCommand()
                        command.Parameters.AddWithValue("@ID", New Guid(Me.ProcessContext.RecordID))
                        command.CommandText = _
                            "select SHORTNAME, " & _
                            "LONGNAME, " & _
                            "DESCRIPTION, " & _
                            "RATING " & _
                            "from dbo.USR_EXAMPLE " & _
                            "where ID = @ID"
    
                        Using reader As SqlClient.SqlDataReader = command.ExecuteReader()
                            reader.Read()
                            SHORTNAME = reader.GetString(reader.GetOrdinal("SHORTNAME"))
                            LONGNAME = reader.GetString(reader.GetOrdinal("LONGNAME"))
                            DESCRIPTION = reader.GetString(reader.GetOrdinal("DESCRIPTION"))
                            RATING = reader.GetDecimal(reader.GetOrdinal("RATING"))
                            loadResult.DataLoaded = True
                            reader.Close()
                        End Using
    
                    End Using
                End Using
            Catch ex As Exception
                Throw
            End Try
    
            Return loadResult
        End Function
    
    End Class
  14. Adjust FormMetaData as follows. These form fields map to the parameters in the save implementation. FormMetaData is discussed in Form Metadata.

      <common:FormMetaData>
        <common:FormFields>
    
          <common:FormField FieldID="SHORTNAME"
                            Caption="Short name"
                            DataType="String"
                            MaxLength="10" />
    
          <common:FormField FieldID="LONGNAME"
                            Caption="Long name"
                            DataType="String"
                            MaxLength="20" />
    
          <common:FormField FieldID="DESCRIPTION"
                            Caption="Description"
                            DataType="String" />
    
          <common:FormField FieldID="RATING"
                            Caption="Rating"
                            DataType="Decimal"
                            MinValue="0"
                            MaxValue="10" />
    
        </common:FormFields>
      </common:FormMetaData>
  15. Save the spec, load it, and open it. The Table Spec must also be loaded. To access the data form, you can create a task to open the form. For development, you can use LoadSpec. For CLR forms, the assembly must also be copied to vroot\bin. For deployments, you can use the Catalog Browser.

    LoadSpec

    How is the Infinity Platform Extended and Customized?

    For a Translation Function Spec and a Search List Spec to support opening this View Data Form, see Translation Function Spec and Search List Spec.