Developing the Primary Components for the Solution

Applies to: Duet Enterprise for Microsoft SharePoint and SAP Server 2.0 | Office 2010 | SharePoint Server 2010

In this article
Creating the Visual Studio Project
Creating the Sales Order List Instances
Customizing List Item Form Pages for the Sales Order Lists
Configuring the Sales Order Lists with Custom Schemas
Adding Feature Event Receiver Routines
Reviewing the Primary Components

After you create the necessary external content types on which the Duet Sales Order Management solution is based, you can build the basic components of the solution in Visual Studio.

Creating the Visual Studio Project

To create the primary components of the Duet Sales Order Management solution, start with an Empty SharePoint Project in Visual Studio. You add SharePoint project items to the solution in the course of this walkthrough. (For a description of the kinds of SharePoint project items available in Visual Studio 2010, see the topic Developing SharePoint Solutions in the MSDN Library.)

To create an empty SharePoint project

  1. Start Visual Studio 2010 by using the Run as Administrator option.

  2. On the File menu, point to New, and then click Project. The New Project dialog box appears.

  3. In the New Project dialog box, expand the SharePoint node under Visual C# (or the language you want to use), and then select the 2010 node. (The Duet Sales Order Management solution was developed using C# and the code samples throughout this walkthrough are in C#. Subsequent references to Visual Studio templates in this walkthrough generally refer to templates in the Visual C# language node.)

  4. In the Templates pane, select Empty SharePoint Project and specify a name for the project, such as DuetSalesOrderSolution.

  5. Click OK. The SharePoint Customization Wizard appears. This wizard enables you to select the site that you use to debug the project and the trust level of the solution.

  6. Specify the URL of the site you created for the Duet Sales Order Management solution. (See Setting Up a Development Environment for Working with Duet Enterprise.)

  7. Select Deploy as a farm solution, and then click Finish to create the project.

SharePoint projects in Visual Studio 2010 already include references to Microsoft.SharePoint.dll and Microsoft.SharePoint.Security.dll (both in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\ISAPI in a standard SharePoint installation). For the Duet Sales Order Management solution, you also need to add references to System.Web and System.Web.Extensions.

To add references to the Visual Studio project

  1. On the Project menu in Visual Studio, click Add Reference. The Add Reference dialog box appears.

  2. On the .NET tab, select System.Web (version 2.0.0.0) in the list of component names.

  3. Press Ctrl while selecting System.Web.Extensions (version 3.5.0.0) in the list of component names.

  4. Click OK to add the selected references to the solution.

In Solution Explorer for your project, you should now see the references shown in Figure 1.

Figure 1. Initial references for solution

Initial references for solution

Creating the Sales Order List Instances

The first project items to create are SharePoint list instances corresponding to the Sales Order Headers and Sales Order Items external content types.

To create a list instance of the Sales Order Headers external content type

  1. In Solution Explorer, select the project you created in the previous section (named DuetSalesOrderSolution if you are following the naming conventions of this walkthrough).

  2. On the Project menu, click Add New Item. The Add New Item dialog box appears.

  3. In the Add New Item dialog box, expand the SharePoint node under Visual C#, and then select the 2010 node.

  4. In the Templates pane, select List Instance and specify SalesOrderHeaders as the name of the item.

  5. Click Add. The SharePoint Customization Wizard appears.

  6. Specify Sales Order Headers as the display name of the list.

    The value specified as the display name of the list in the customization wizard becomes the value of the Title attribute of the ListInstance element in the Elements.xml manifest for the list instance.

  7. Select "Custom List" as the type of list to instantiate.

    A list type of "External List" is not available in the customization wizard. The properties to specify an external list will be configured in a later step.

  8. Optionally, specify a description for the list (such as "External List for Sales Order Headers").

  9. Specify "Lists/SalesOrderHeaders" for the relative URL.

    By default, Visual Studio prefixes the name of the project to the display name and also includes the project name in the relative URL for a list. If, for example, the project is named "DuetSalesOrderSolution", the value supplied automatically by the wizard for the relative URL of the list is "Lists/DuetSalesOrderSolution-SalesOrderHeaders". For the sake of clarity, these prefixes are removed in the Duet Sales Order Management solution.

  10. Click Finish. The list instance is created and added to the project, and the Elements.xml file for the list instance is opened.

  11. In the Elements.xml file, change the value of the TemplateType attribute of the ListInstance element to "600" (the template type for external lists) and change the value of the FeatureId attribute to "00bfea71-9549-43f8-b978-e47e54a10600" (the Feature identifier value for external lists).

Follow the same steps to create another list instance, this time for the Sales Order Items external content type. Use "SalesOrderItems" as the name of the list instance and "Sales Order Items" as the display name. Specify "Lists/SalesOrderItems" as the relative URL for the list.

Notice that after you created the first list instance, Visual Studio automatically added a Feature to the project, scoped to the level of a specific website, for deploying the newly created list instance to SharePoint. (The capitalized word "Feature" is used in the documentation to refer specifically to the SharePoint deployment mechanism to distinguish from the word "feature" used in a generic sense.) By creating list instances in a SharePoint project, you are actually creating Feature elements. As additional list instances are created, Visual Studio includes them as components of the Feature. This Feature is used as the deployment container for any items in the project that are scoped to the website level. The Feature is called "Feature1" by default. For now, rename this Feature (in the Features node in Solution Explorer) to something more descriptive, such as "SalesOrderSiteFeature". Later, you add event receivers to the Feature for performing actions that configure the Feature on activation and deactivation.

Now these lists must be bound to the appropriate external content types.

To bind the lists to the external content types

  1. In Solution Explorer, double-click the SalesOrderHeaders list instance. The Elements.xml file for the list is opened for editing.

    An Elements.xml file for a given item is used by the Feature that deploys the item to SharePoint. The file is a "manifest" in the sense of an invoice or list of goods that identifies and describes an item and its related components to be included in a Feature.

  2. In the Elements.xml file for the SalesOrderHeaders list instance, add the following markup for the DataSource element immediately preceding the closing tag of the ListInstance element (</ListInstance>).

    <DataSource>
      <Property Name="Entity" Value="Sales Order Header" />
      <Property Name="EntityNamespace" Value="SAP.Office.DuetEnterprise.DevGuide.SalesOrder" />
      <Property Name="LobSystemInstance" Value="SCLManageSalesOrder" />
      <Property Name="SpecificFinder" Value="ReadSalesOrder" />
      <Property Name="Service" Value="Business Data Catalog" />
    </DataSource>
    
  3. Save the file and close it.

  4. Double-click the SalesOrderItems list instance. The Elements.xml file for the list is opened for editing.

  5. In the Elements.xml file for the SalesOrderItems list instance, add the following markup for the DataSource element preceding the closing tag of the ListInstance element.

    <DataSource>
      <Property Name="Entity" Value="Sales Order Item" />
      <Property Name="EntityNamespace" Value="SAP.Office.DuetEnterprise.DevGuide.SalesOrder" />
      <Property Name="LobSystemInstance" Value="SCLManageSalesOrderItem" />
      <Property Name="SpecificFinder" Value="ReadSalesOrderItem" />
      <Property Name="Service" Value="Business Data Catalog" />
    </DataSource>
    
  6. Save the file.

The properties of these DataSource elements establish associations between the lists and their appropriate external content types (referred to as "entities" in earlier releases of SharePoint Products and Technologies). The properties as specified in the ListInstance element and in the DataSource element identify these lists as "external lists" in SharePoint, because the data for the lists comes from a source other than the SharePoint content database—that is, the lists are based on external content types. The external content types specified by name in these properties must already exist (and in the specified namespace) in the Metadata Store on the server that is targeted by the solution to activate the lists on the server. (See Data Models for the Duet Sales Order Management Solution for the steps required to create the necessary external content types.) The other properties, such as the LobSystemInstance and SpecificFinder, must be configured properly for the lists to be displayed or used on the site (though they are not required, strictly speaking, for the lists simply to be deployed).

For more information about the structure of the Elements.xml file for list instances, see the Feature Schema Reference for List Instances in the MSDN Library; for information about the DataSource element in particular, see DataSource Element (List Instance).

If you were to deploy the project now to your target SharePoint site, you would see the lists in the collection of lists on the site, as shown in Figure 2.

Figure 2. Sales order lists on the SharePoint site

Sales order lists on the SharePoint site

To see the lists for a SharePoint site, click Lists in Quick Launch or click View All Site Content from the Site Actions menu on the target site.

You can click the lists to display their default views on the site. If your server has access to the web service endpoints on which the sales order external content types are based, you can able to see the data from the SAP back-end system exposed by the web services. In the next section, we configure characteristics of these lists, including what is displayed in default views, by using custom schemas.

To deploy the solution from Visual Studio

  1. Confirm that the Active Deployment Configuration property for the DuetSalesOrderSolution project is set to "Default".

  2. On the Build menu in Visual Studio, click Deploy Solution (or press F5) to deploy the solution to your target SharePoint site and activate the solution.

Note

After an initial deployment of the solution, if the value of the Deployment Conflict Resolution property for a given item is set to "Prompt" (the default), you are asked on each subsequent deployment whether you want to replace the existing item on the target SharePoint site. To facilitate the development and testing of these items in deployments to a development server, you can set the value of this property to "Automatic" to replace items without prompting.

Customizing List Item Form Pages for the Sales Order Lists

Lists in SharePoint are associated with a set of forms (that is, Web Parts pages) for displaying, editing, and creating individual list items. These forms can be presented to users from the list item menu (or Edit Control Block menu) of an item, from commands on the Ribbon, or from custom actions or Web Parts. The default forms for most lists are created based on the standard list item form page template (%ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\Pages\form.aspx). This page template contains a default ListFormWebPart object, and each form page (DispForm.aspx, EditForm.aspx, and NewForm.aspx) that is based on that page template uses an instance of the ListFormWebPart object to render information to display, edit, or create individual list items.

As described in the next section on configuring the sales order lists with custom schemas, for the Duet Sales Order Management solution you create schemas for the sales order lists that are configured to use custom list item forms based on the standard page template. Before you implement the custom schemas for the lists, you create custom Web Parts for the list item forms. Then, using custom schemas associated with each list, you hide the default List Form Web Parts on these list item forms and display custom Web Parts instead.

First, create the Visual Web Part for the SalesOrderHeaders list.

To create a Visual Web Part for the SalesOrderHeaders list

  1. In Solution Explorer, select the DuetSalesOrderSolution project.

  2. On the Project menu, click Add New Item. The Add New Item dialog box appears.

  3. In the Add New Item dialog box, expand the SharePoint node under Visual C#, and then select the 2010 node.

  4. In the list of templates in the Templates pane, select Visual Web Part and specify "SalesOrderHeaderVisualWebPart" as the name of the item.

  5. Click Add. The Visual Web Part is added to the project and the SalesOrderHeaderVisualWebPartUserControl.ascx user control file is opened for editing.

  6. Add the following markup to the file, after the default directives added by Visual Studio.

    <asp:Table ID="Table1" runat="server">
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel1" FieldName="SalesOrderNumber"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldSalesOrderNumber" ControlMode="Display" FieldName="SalesOrderNumber" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel2" FieldName="PurchaseOrderNumber"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldPurchaseOrderNumber" FieldName="PurchaseOrderNumber" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel3" FieldName="SoldToParty"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldSoldToParty" FieldName="SoldToParty" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel4" FieldName="SalesOrganization"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldSalesOrganization" FieldName="SalesOrganization" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel5" FieldName="DeliveryDate"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldDeliveryDate" FieldName="DeliveryDate" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel6" FieldName="OrderType"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldOrderType" FieldName="OrderType" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel7" FieldName="Currency"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldCurrency" FieldName="Currency" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel8" FieldName="NetValue"  DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldNetValue" ControlMode="Display" FieldName="NetValue" />
            </asp:TableCell>
        </asp:TableRow>
    </asp:Table>
    
  7. Save the file.

Now create a Visual Web Part for the SalesOrderItems list.

To create a Visual Web Part for the SalesOrderItems list

  1. In Solution Explorer, select the DuetSalesOrderSolution project.

  2. On the Project menu, click Add New Item. The Add New Item dialog box appears.

  3. In the Add New Item dialog box, expand the SharePoint node under Visual C#, and then select the 2010 node.

  4. In the list of templates in the Templates pane, select Visual Web Part and specify "SalesOrderItemVisualWebPart" as the name of the item.

  5. Click Add. The Visual Web Part is added to the project and the SalesOrderItemVisualWebPartUserControl.ascx user control file is opened for editing.

  6. Add the following markup to the file, after the default directives added by Visual Studio.

    <asp:Table ID="Table1" runat="server">
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel1" FieldName="ItemNumber" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldItemNumber" FieldName="ItemNumber" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel2" FieldName="Sales Order Header" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldSalesOrderSclKey" FieldName="Sales Order Header" />
            </asp:TableCell>
        </asp:TableRow>
            <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel3" FieldName="Product"  DisplaySize="5"/>
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldProduct" FieldName="Product" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel4" FieldName="MaterialShortText" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldMaterialShortText" FieldName="MaterialShortText" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel5" FieldName="Quantity" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldQuantity" FieldName="Quantity" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel6" FieldName="SalesUnit" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldSalesUnit" FieldName="SalesUnit" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel7" FieldName="NetPrice" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldNetPrice" FieldName="NetPrice" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel8" FieldName="Currency" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldCurrency" FieldName="Currency" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel9" FieldName="NetValue" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldNetValue" FieldName="NetValue" />
            </asp:TableCell>
        </asp:TableRow>
        <asp:TableRow>
            <asp:TableCell CssClass="ms-formlabel">
                <SharePoint:FieldLabel runat="server" ID="FieldLabel10" FieldName="Plant" DisplaySize="5" />
            </asp:TableCell>
            <asp:TableCell CssClass="ms-formbody">
                <SharePoint:FormField runat="server" ID="ffldPlant" FieldName="Plant" />
            </asp:TableCell>
        </asp:TableRow>
    </asp:Table>
    
  7. Save the file.

For both of these Web Parts, in the markup for the control, you are creating simple tables to render the data associated with a given item from either the list of sales order headers or sales order items. At the moment, these custom Web Parts don't provide anything more than the default List Form Web Parts provide. Depending on the requirements for a given solution, you can add SharePoint controls, .NET controls, HTML entities, themes, and many other customizations to custom Web Parts. You start with these Web Parts for the Duet Sales Order Management solution as a foundation for adding various enhancements later, including routines in a code-behind file to facilitate editing and to perform simple validation.

Note

To be rendered for display in Design View in the Web Editor in Visual Studio, the SharePoint controls (such as SharePoint:FormField) that have been added to these control files require a SharePoint context, which cannot be determined at design time by Visual Studio. Although you can still use Design View to manipulate standard controls and HTML entities in these files, files with SharePoint controls are generally best edited in Code View.

Configuring the Sales Order Lists with Custom Schemas

Next, you will associate custom schema files with these list instances. Lists in SharePoint are associated with default schemas (located in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\FEATURES on a computer running SharePoint Server 2010), but by using custom schemas, you have greater control over the configuration of these lists than if you were to use the default schemas associated with them in SharePoint. You can set various attributes of the lists in Visual Studio (such as which fields to include in default views and the order of those fields) and you can associate with the lists a set of custom list item form pages (which use the Visual Web Parts created in the previous section). On deployment, the lists are configured as specified in the custom schema, making it unnecessary for users to configure the lists in SharePoint to conform to the intentions of your design. Custom schema files contain Collaborative Application Markup Language (CAML) declarations for defining and rendering certain items (such as lists) in SharePoint. (For more information about the structure and purpose of schema files, see Understanding Schema.xml Files in the MSDN Library.)

First, add a custom schema to the SalesOrderHeaders list instance in the project.

To add a custom schema to SalesOrderHeaders

  1. In Solution Explorer, select the SalesOrderHeaders item (the list instance created earlier).

  2. On the Project menu, click Add New Item.

  3. In the Add New Item dialog box, under Visual C# (or Visual Basic), click Data.

  4. In the Templates pane, select XML File and specify "Schema.xml" as the name of the file to be created.

  5. Click Add. The XML file is added to the SalesOrderHeaders item in Solution Explorer and opened for editing.

  6. Add the following markup to the file, after the opening XML declaration.

    <List Title="Sales Order Headers" Direction="none" Url="Lists/SalesOrderHeaders" BaseType="0" Type="100" FolderCreation="FALSE" DisableAttachments="TRUE" DefaultItemOpen="1" xmlns:ows="Microsoft SharePoint">
      <MetaData>
        <Forms>
          <Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE">
            <WebParts>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
                <![CDATA[
                <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
                  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
                  <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
                  <PageType>PAGE_DISPLAYFORM</PageType>
                  <IsVisible>false</IsVisible>
                </WebPart>]]>
              </AllUsersWebPart>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
                <![CDATA[
                <webParts>
                  <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                    <metaData>
                      <type name="DuetSalesOrderSolution.SalesOrderHeaderVisualWebPart.SalesOrderHeaderVisualWebPart, $SharePoint.Project.AssemblyFullName$" />
                      <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                    </metaData>
                    <data>
                      <properties>
                        <property name="Title" type="string">Sales Order Header Visual Web Part</property>
                        <property name="PageType" type="string">PAGE_DISPLAYFORM</property>
                       </properties>
                    </data>
                  </webPart>
                </webParts>]]>
              </AllUsersWebPart>
            </WebParts>
          </Form>
    
          <Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE">
            <WebParts>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
                <![CDATA[
                <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
                  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>            
                  <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
                  <PageType>PAGE_EDITFORM</PageType>
                  <IsVisible>false</IsVisible>
                </WebPart>]]>
              </AllUsersWebPart>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
                <![CDATA[
                <webParts>
                  <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                    <metaData>
                      <type name="DuetSalesOrderSolution.SalesOrderHeaderVisualWebPart.SalesOrderHeaderVisualWebPart, $SharePoint.Project.AssemblyFullName$" />
                      <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                    </metaData>
                    <data>
                      <properties>
                        <property name="Title" type="string">Sales Order Header Visual Web Part</property>
                        <property name="PageType" type="string">PAGE_EDITFORM</property>                    
                       </properties>
                    </data>
                  </webPart>
                </webParts>]]>
              </AllUsersWebPart>
            </WebParts>
          </Form>
    
          <Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE">
            <WebParts>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
                <![CDATA[
                <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
                  <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>            
                  <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
                  <PageType>PAGE_NEWFORM</PageType>
                  <IsVisible>false</IsVisible>
                </WebPart>]]>
              </AllUsersWebPart>
              <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
                <![CDATA[
                <webParts>
                  <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                    <metaData>
                      <type name="DuetSalesOrderSolution.SalesOrderHeaderVisualWebPart.SalesOrderHeaderVisualWebPart, $SharePoint.Project.AssemblyFullName$" />
                      <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                    </metaData>
                    <data>
                      <properties>
                        <property name="Title" type="string">Sales Order Header Visual Web Part</property>
                        <property name="PageType" type="string">PAGE_NEWFORM</property>                    
                       </properties>
                    </data>
                  </webPart>
                </webParts>]]>
              </AllUsersWebPart>
            </WebParts>
          </Form>
        </Forms>
    
        <Views>
          <View DisplayName="Sales Order Headers Default View" DefaultView="TRUE" BaseViewID="1" Type="HTML" MobileView="TRUE" ImageUrl="/_layouts/images/generic.png" WebPartZoneID="Main" WebPartOrder="0" Url="SalesOrderHeaders.aspx" SetupPath="pages\viewpage.aspx">
            <XslLink Default="TRUE">main.xsl</XslLink>
            <!--The following method (defined in the BDC Model for the Sales Order Header ECT) is the implementation of the Finder stereotyped method.-->
            <Method Name="QuerySalesOrder" />
            <ViewFields>
              <FieldRef Name="SalesOrderSclKey" />
              <FieldRef Name="SalesOrderNumber" />
              <FieldRef Name="PurchaseOrderNumber" />
              <FieldRef Name="SoldToParty" />
              <FieldRef Name="SalesOrganization" />
            </ViewFields>
            <RowLimit Paged="TRUE">100</RowLimit>
          </View>
        </Views>
      </MetaData>
    </List>
    
  7. Save the file.

The schema defines a default view for the list by declaring a single View element within the Views element. The Method element within the View element identifies the Finder method of the Sales Order Header external content type that returns the data for the view. In the external content type as designed for the Duet Sales Order Management solution, only one Finder method is defined, so this Method element is not strictly necessary, but if multiple Finder methods were defined, you would associate specific methods with particular views by using this Method element. The FieldRef elements within the ViewFields element specify the fields to include in the associated view and the column order of the fields. In this case, all the fields returned by the Finder method are displayed, but, depending on the data you are working with and the design of your solution, you may want to exclude certain fields from a given view.

The forms specified in this schema (in the Forms element) represent the default forms to use for displaying, editing, and creating new items in the list. These forms are instantiated using the base Web Parts page for list forms (forms.aspx in %ProgramFiles%\Common Files\Microsoft Shared\web server extensions\14\TEMPLATE\Pages). Pages instantiated from the base Web Parts page include a default List Form Web Part. In this schema, the forms are configured to be provisioned without the default List Form Web Part (that is, the UseDefaultListFormWebPart attributes of the Form elements are set to "false"), and hidden List Form Web Parts are added to the forms. Then, the custom Sales Order Header Visual Web Part (created previously in the section on customizing the list item form pages) is added to the form. (For a detailed description of the CAML declarations related to lists, see List Element (List). For more information about the markup related to Web Part controls, see Web Parts Control Description Files.)

After creating the schema file, you must associate the file with the SalesOrderHeaders list and you must set the file to be deployed along with the list. To associate the schema with SalesOrderHeaders, the declaration for the ListInstance element must be updated in the Elements.xml file for the list.

To associate the schema with the SalesOrderHeaders list

  1. In Solution Explorer, double-click the SalesOrderHeaders list instance. The Elements.xml file is opened for editing.

  2. Add a CustomSchema attribute to the ListInstance element, with a value of "SalesOrderHeaders\Schema.xml". The Elements.xml file for SalesOrderHeaders should now resemble the following.

    <?xml version="1.0" encoding="utf-8"?>
    <Elements xmlns="https://schemas.microsoft.com/sharepoint/">
      <ListInstance Title="Sales Order Headers"
                    OnQuickLaunch="TRUE"
                    TemplateType="600"
                    FeatureId="00bfea71-9549-43f8-b978-e47e54a10600"
                    Url="Lists/SalesOrderHeaders"
                    Description="External List for Sales Order Headers."
                    CustomSchema="SalesOrderHeaders\Schema.xml">
    
        <DataSource>
          <Property Name="Entity" Value="Sales Order Header" />
          <Property Name="EntityNamespace" Value="SAP.Office.DuetEnterprise.DevGuide.SalesOrder" />
          <Property Name="LobSystemInstance" Value="SCLManageSalesOrder" />
          <Property Name="SpecificFinder" Value="ReadSalesOrder" />
          <Property Name="Service" Value="Business Data Catalog" />
        </DataSource>
    
      </ListInstance>
    </Elements>
    
  3. Save the file.

  4. In Solution Explorer, select the Schema.xml file in the node for the SalesOrderHeaders list instance.

  5. Press Ctrl+W and then press P (or right-click the file and click Properties) to edit the properties of the file in the Properties window.

  6. In the Properties window, change Deployment Type from "NoDeployment" to "ElementFile" to include the file as a resource in the Feature that deploys the list instance.

To add a custom schema file to the SalesOrderItems list instance, follow the same steps as you did for the SalesOrderHeaders list instance, except for the contents of the Schema.xml file that you create for SalesOrderItems, add the following markup (after the XML declaration).

<List Title="Sales Order Items" Url="Lists/SalesOrderItems" BaseType="0" Type="100" FolderCreation="FALSE" DisableAttachments="TRUE" DefaultItemOpen="1" xmlns:ows="Microsoft SharePoint">
  <MetaData>
    <Forms>
      <Form Type="DisplayForm" Url="DispForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE">
        <WebParts>
          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
            <![CDATA[
            <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
              <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>
              <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
              <PageType>PAGE_DISPLAYFORM</PageType>
              <IsVisible>false</IsVisible>
            </WebPart>]]>
          </AllUsersWebPart>

          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
            <![CDATA[
            <webParts>
              <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                <metaData>
                  <type name="DuetSalesOrderSolution.SalesOrderItemVisualWebPart.SalesOrderItemVisualWebPart, $SharePoint.Project.AssemblyFullName$"/>
                  <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                </metaData>
                <data>
                  <properties>
                    <property name="Title" type="string">Sales Order Item Visual Web Part</property>
                    <property name="PageType" type="string">PAGE_DISPLAYFORM</property>
                   </properties>
                </data>
              </webPart>
            </webParts>]]>
          </AllUsersWebPart>
        </WebParts>
      </Form>

      <Form Type="EditForm" Url="EditForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE" >
        <WebParts>
          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
            <![CDATA[
            <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
              <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>            
              <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
              <PageType>PAGE_EDITFORM</PageType>
              <IsVisible>false</IsVisible>
            </WebPart>]]>
          </AllUsersWebPart>

          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
            <![CDATA[
            <webParts>
              <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                <metaData>
                  <type name="DuetSalesOrderSolution.SalesOrderItemVisualWebPart.SalesOrderItemVisualWebPart, $SharePoint.Project.AssemblyFullName$"/>
                  <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                </metaData>
                <data>
                  <properties>
                    <property name="Title" type="string">Sales Order Item Visual Web Part</property>
                    <property name="PageType" type="string">PAGE_EDITFORM</property>
                   </properties>
                </data>
              </webPart>
            </webParts>]]>
          </AllUsersWebPart>
        </WebParts>
      </Form>

      <Form Type="NewForm" Url="NewForm.aspx" SetupPath="pages\form.aspx" WebPartZoneID="Main" UseDefaultListFormWebPart="False" Default="TRUE" >
        <WebParts>
          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="3">
            <![CDATA[
            <WebPart xmlns="https://schemas.microsoft.com/WebPart/v2">
              <Assembly>Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c</Assembly>            
              <TypeName>Microsoft.SharePoint.WebPartPages.ListFormWebPart</TypeName>
              <PageType>PAGE_NEWFORM</PageType>
              <IsVisible>false</IsVisible>
            </WebPart>]]>
          </AllUsersWebPart>

          <AllUsersWebPart WebPartZoneID="Main" WebPartOrder="2">
            <![CDATA[
            <webParts>
              <webPart xmlns="https://schemas.microsoft.com/WebPart/v3">
                <metaData>
                  <type name="DuetSalesOrderSolution.SalesOrderItemVisualWebPart.SalesOrderItemVisualWebPart, $SharePoint.Project.AssemblyFullName$"/>
                  <importErrorMessage>$Resources:core,ImportErrorMessage;</importErrorMessage>
                </metaData>
                <data>
                  <properties>
                    <property name="Title" type="string">Sales Order Item Visual Web Part</property>
                    <property name="PageType" type="string">PAGE_NEWFORM</property>
                   </properties>
                </data>
              </webPart>
            </webParts>]]>
          </AllUsersWebPart>
        </WebParts>
      </Form>
    </Forms>

    <Views>
      <View DisplayName="Sales Order Items Default View" DefaultView="TRUE" BaseViewID="1" Type="HTML" MobileView="TRUE" ImageUrl="/_layouts/images/generic.png" WebPartZoneID="Main" WebPartOrder="0" Url="SalesOrderItems.aspx" SetupPath="pages\viewpage.aspx">
        <XslLink Default="TRUE">main.xsl</XslLink>
        <Method Name="QuerySalesOrderItem" />
        <ViewFields>
          <FieldRef Name="ItemSclKey" />
          <FieldRef Name="ItemNumber" />
          <FieldRef Name="SalesOrderSclKey" />
          <FieldRef Name="MaterialSclKey" />
          <FieldRef Name="MaterialShortText" />
          <FieldRef Name="Quantity" />
          <FieldRef Name="SalesUnit" />
          <FieldRef Name="NetPrice" />
          <FieldRef Name="Currency" />
          <FieldRef Name="NetValue" />
          <FieldRef Name="Plant" />
        </ViewFields>
        <RowLimit Paged="TRUE">100</RowLimit>
      </View>
    </Views>
  </MetaData>
</List>

And in the Elements.xml file for SalesOrderItems list instance, again add a CustomSchema attribute to the ListInstance element, this time with a value of "SalesOrderItems\Schema.xml".

If you were to deploy the solution now, the lists and their custom schemas would be deployed to the SharePoint site specified for your solution. But you may notice that links to the lists no longer show up in Quick Launch, even though the OnQuickLaunch attribute of the ListInstance elements in the Elements.xml files for these lists is set to "TRUE". This is because we are now using custom schemas to define and render the lists. Later, you add a routine to the Feature activation code to add the links to these lists back to Quick Launch.

Adding Feature Event Receiver Routines

After you created the Sales Order Header Visual Web Part, Visual Studio added another Feature to the project, as it did after you created the first list instance. The Sales Order Headers Visual Web Part was not simply added to the existing Feature, because that Feature is scoped to the level of a website. Web Parts in SharePoint are deployed at the level of a site collection rather than to an individual website, because they are also deployed to the Web Part Gallery, which exists only at the level of a site collection (that is, in the root website of a site collection). If you set a Feature that includes Web Parts to be deployed at the level of a website, you receive an error in Visual Studio when you deploy the Feature. A single Feature cannot be scoped to multiple levels. It must be scoped to only one of the available levels (and all the elements of that Feature are deployed to the same level). Visual Studio therefore creates a second Feature, scoped to the level of the site collection, to accommodate the Web Parts in your project. Rename this Feature to something like "SalesOrderWebParts". (You could also use a single Feature for the project if that Feature is scoped to the level of a site collection, because list instances can be deployed in a Feature scoped either to the level of a website or a site collection. The Duet Sales Order Management solution was designed to use one Feature for components deployed to the level of a website, such as the sales order list instances, and another Feature for the Visual Web Parts, which are deployed to the level of a site collection.)

For the Duet Sales Order Management solution, you create a class to contain list configuration and customization code. Then you instantiate an object of that class and call its methods from an event receiver that you add to the SalesOrderSiteFeature Feature.

To create a class for list configuration

  1. In Solution Explorer, select the DuetSalesOrderSolution project.

  2. On the Project menu, click New Folder. A folder is added under the node for the DuetSalesOrderSolution project. Specify "Customizations" as the name of the folder.

    The class modules in the Duet Sales Order Management solution are contained in a separate folder (and namespace) simply for the sake of convenience and clear organization. Creating a folder for class modules in your project is recommended, but optional.

  3. Select the Customizations folder in the project (or the DuetSalesOrderSolution project itself if you didn't create a folder in Step 2). On the Project menu, click Add Class. The Add New Item dialog box appears with the class template selected.

  4. Specify "ListCustomizations.cs" as the name of the class file.

  5. Click Add. The file is added to the project and opened for editing.

  6. Replace the contents of the file with the following code.

    using System;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Utilities;
    using Microsoft.SharePoint.WebPartPages;
    using System.Web.UI.WebControls.WebParts;
    
    namespace DuetSalesOrderSolution.Customizations
    {
        class ListCustomizations
        {
            private string[] externalListTitles = null;
    
            public ListCustomizations(string[] listTitles)
            {
                externalListTitles = listTitles;
            }
    
            public void Activate(SPWeb spWeb)
            {
                if (externalListTitles != null)
                {
                    MakeExternalListsVisibleOnQuickLaunch(spWeb);
                }
            }
    
            public void Deactivate(SPWeb spWeb)
            {
                if (externalListTitles != null)
                {
                    // Remove the lists that were created.
                    for (int i = 0; i < externalListTitles.Length; i++)
                    {
                        SPList externalList = spWeb.Lists.TryGetList(externalListTitles[i]);
                        if (externalList != null)
                        {
                            spWeb.Lists.Delete(externalList.ID);
                        }
                    }
                }
            }
    
            /// <summary>
            /// Programmatically sets the specified lists to show on Quick Launch.
            /// </summary>
            /// <remarks>
            /// List Instances, when they are defined declaratively (that is, using an Elements.xml file)
            /// and associated with a custom schema may not be visible on Quick Launch even when
            /// the OnQuickLaunch property for them is set to TRUE in the Elements.xml file.
            /// </remarks>
            /// <param name="spWeb">The target SharePoint Web site.</param>
            private void MakeExternalListsVisibleOnQuickLaunch(SPWeb spWeb)
            {
                for (int i = 0; i < externalListTitles.Length; i++)
                {
                    SPList externalList = spWeb.Lists.TryGetList(externalListTitles[i]);
                    if (externalList != null)
                    {
                        externalList.OnQuickLaunch = true;
                        externalList.Update();
                    }
                }
            }
        }
    }
    
  7. Save the file.

The Activate and Deactivate methods of this class are called from the appropriate events of the SalesOrderSiteFeature Feature. (You add handlers for Feature events in the following set of steps.) For now, the Activate method simply calls the MakeExternalListsVisibleOnQuickLaunch method, which programmatically configures the lists to appear on Quick Launch. You add other methods to this ListCustomizations class as you continue to develop the Duet Sales Order Management solution.

Now you need to add an event receiver class to SalesOrderSiteFeature, the Feature in the solution that is scoped to the level of a Web site.

To add an event receiver class to SalesOrderSiteFeature

  1. In Solution Explorer, right-click the SalesOrderSiteFeature Feature in the Features folder.

  2. Click Add Event Receiver. An event receiver class file (SalesOrderSiteFeature.EventReceiver.cs) is added to the Feature and opened for editing.

  3. Near the top of the file, after the using directives added by Visual Studio, add the following additional directive.

    using DuetSalesOrderSolution.Customizations;
    
  4. The event receiver class file is created with four methods for handling Feature events. The methods in the file are initially commented out. After the class declaration and before the first method declaration, add the following code.

    private string[] externalListTitles = { "Sales Order Headers", "Sales Order Items" };
    

    The values specified here for the list titles must match the value of the Title attribute (e.g., "Sales Order Headers") of the ListInstance element in Elements.xml for a given list instance.

  5. Replace the FeatureActivated method in the file with the following code.

    public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
        base.FeatureActivated(properties);
    
        SPWeb spWeb = (SPWeb)properties.Feature.Parent;
    
        // Enable list customizations.
        ListCustomizations listCustomizations = new ListCustomizations(externalListTitles);
        listCustomizations.Activate(spWeb);
    }
    
  6. Replace the FeatureDeactivating method in the file with the following code.

    public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
    {
        SPWeb spWeb = (SPWeb)properties.Feature.Parent;
    
        ListCustomizations listCustomizations = new ListCustomizations(externalListTitles);
        listCustomizations.Deactivate(spWeb);
    
        base.FeatureDeactivating(properties);
    }
    
  7. Save the file.

Reviewing the Primary Components

The fundamental components of the Duet Sales Order Management solution are now in place. If you were to deploy this solution to your target SharePoint site, you would again see links to the sales order lists on Quick Launch. If you click the link to the Sales Order Headers List, you should see something similar to Figure 3.

Figure 3. Default list view of sales order headers

Default list view of sales order headers

The modal dialogs (that is, the list item form pages) displayed from the list item menu of a given item or from the Edit Item command on the Ribbon would reflect the customizations specified earlier in the Visual Web Parts added to the form pages in the custom schemas for each sales order list. The View Item form (DispForm.aspx) for the Sales Order Headers List, for example, should resemble Figure 4.

Figure 4. View Item form for sales order headers

View Item Form for sales order headers

Note

The data displayed in Figure 4 is provisional data used simply for demonstration and testing purposes in this walkthrough. The information displayed in your solution will differ.

You can edit the data associated with the Sales Order Headers and Sales Order Items external content types, and you can delete or create new headers and items (if your development system has access to the Web Service endpoints on which the external content types are based).

In the next topic, Adding User Interface Enhancements, you continue to develop the Duet Sales Order Management solution by adding custom actions, simple data-entry validation, mechanisms to facilitate editing list items, and other enhancements.

See Also

Other Resources

Walkthrough: Add Feature Event Receivers

Developing SharePoint Solutions

SharePoint Project and Project Item Templates

Web Parts Control Description Files