Office Test - Tutorial 4

The 4th page of the OfficeTest General Tests tutorial applies to more that just Firebird. In this tutorial we'll look at making a normal GridView work more like a spreadsheet or an editable grid. If you want to review the other tutorials, the central page can be found here Firebird and .NET 2.0 development Example. Information covered in previous tutorial pages will not be covered however this topic differs considerably from the previous pages. The 3rd tutorial (Employee: Simple) covers templated fields and manual binding which will be used here as well.

4. Editable GridView - acts more like a spreadsheet.

    This web page brings us back to working with the BillingType table. This time however we will not be using SqlDataSource for handling selects, inserts, updates or deletes. Also for the first time the GridView control will perform all actions (Display and ALL editing).

    BillingType: EditGrid - run time view

    Looking at this runtime image of the web page we can discuss how it should work:

    There is 1 visable row in the grid for each row of data and a new row is added when the "Add New Row" button is pressed. Every field in the grid is editable at all times allowing you to quickly jump from field to field or row to row and just type any changes. There is a delete button for each row to make it more obvious and easier to delete a particular row. Changes made in the grid are not really made until the "Apply Changes" button is clicked. When changes are applied the deleted rows are actually deleted, edits are updated and new rows are inserted. In fact we could easily add a "Cancel Changes" button which would require almost no code.

    The TAB key allows you to move quickly to the next edit field. Tabbing beyond the last edit field moves to the "Delete" button and then down to the next row. I didn't add any key event handling so you can't cursor up or down rows like in a real spreadsheet.

    Below the grid is a label I use for showing a change log. The changes listed are the ones actually done when the "Apply Changes" button is pressed.

    BillingType: EditGrid - design time view

    The design time view looks almost exactly the same as the run time view. This is because the page is not using any nonvisual controls such as SqlDataSource. The web page itself is a very simple design. Essentially the web page has a GridView, 2 buttons and a label. The GridView has 5 templated columns containing 3 textboxes, a button and a label.

    Markup Tags/Code

    The tags related to the GridView gvBillingType and the templated fields is really what we want to concentrate on from the HTML first before we look at the real code.

    <asp:GridView ID="gvBillingType" runat="server" AutoGenerateColumns="False" Caption="BillingType Editable Grid" OnRowCommand="gvBillingType_RowCommand" CellPadding="4" ForeColor="#333333" GridLines="None">
      <Columns>
        <asp:TemplateField HeaderText="ID">
          <ItemTemplate>
            <asp:TextBox ID="txtBillingTypeID" runat="server" Text='<%# Bind("BillingTypeID") %>' OnTextChanged="TextChanged" Width="47px"></asp:TextBox>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="BillingTitle">
          <ItemTemplate>
            <asp:TextBox ID="txtBillingTitle" runat="server" Text='<%# Bind("BillingTitle") %>' OnTextChanged="TextChanged" Width="180px"></asp:TextBox>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="BillingDesc">
          <ItemTemplate>
            <asp:TextBox ID="txtBillingDesc" runat="server" Text='<%# Bind("BillingDesc") %>' OnTextChanged="TextChanged" Width="250px"></asp:TextBox>
          </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Operations">
          <ItemTemplate>
            <asp:Button ID="cmdDelete" runat="server" CommandArgument='<%# Eval("BillingTypeID") %>' CommandName="DeleteRow" Text="Delete" OnClick="cmdDelete_Click" />
          </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Status">
          <ItemTemplate>
            <asp:Label ID="Label2" runat="server" Text='<%# Bind("Status") %>'></asp:Label>
          </ItemTemplate>
        </asp:TemplateField>
      </Columns>
    </asp:GridView>
       

    gvBillingType primary properties:

    <asp:GridView ID="gvBillingType" runat="server" AutoGenerateColumns="False" Caption="BillingType Editable Grid" OnRowCommand="gvBillingType_RowCommand" CellPadding="4" ForeColor="#333333" GridLines="None">
    </asp:GridView>
       

    Breaking out the tags just related to the GridView itself and not the templated fields the only property we really care about is OnRowCommand="gvBillingType_RowCommand". Although I commented out the code related to this event in the BillingTypeEditGrid.aspx.cs file it can be very usefull. It can provide a more powerfull way of handling row commands and CommandArguments. I will discuss this in more detail later in the coding section.

    ID field template:

    <asp:TemplateField HeaderText="ID">
      <ItemTemplate>
        <asp:TextBox ID="txtBillingTypeID" runat="server" Text='<%# Bind("BillingTypeID") %>' OnTextChanged="TextChanged" Width="47px"></asp:TextBox>
      </ItemTemplate>
    </asp:TemplateField>
       

    Right away you should notice we only have one template for the field - the ItemTemplate. This is because we are not going to be switch between edit modes. This grid is always in the default mode and we will use it for both display and editing. The default mode uses the ItemTemplate so that is the one we will work with. A single simple TextBox was added to the template with 3 important property settings.

    • ID="txtBillingTypeID": This ID does not really need to be set to anything meaningfull normally, but in our case I parse the name to reduce code in the OnTextChanged event handler.
    • Text='<%# Bind("BillingTypeID") %>': I use the two-way binding call in the Text property to allow us to get and set the internal BillingTypeID field value on the GridView.
    • OnTextChanged="TextChanged": This event handler will be used to let us know the value in this field was modified. This event does not cause any postbacks so there is no hit to performance. In the code section further on I will discuss how this event is processed.

    BillingTitle and BillingDesc work exactly the same so I won't go over them in detail. Just make sure to note that the OnTextChanged event handler is bound to the same TextChanged procedure for all 3 fields.

    Operations field template:

    <asp:TemplateField HeaderText="Operations">
      <ItemTemplate>
        <asp:Button ID="cmdDelete" runat="server" CommandArgument='<%# Eval("BillingTypeID") %>' CommandName="DeleteRow" Text="Delete" OnClick="cmdDelete_Click" />
      </ItemTemplate>
    </asp:TemplateField>
       

    The "Operations" field was added to hold the delete button. The important properties on the delete button are the CommandArgument, CommandName and OnClick.

    • CommandName="DeleteRow": This value is meant to be used with gvBillingType_RowCommand event I mentioned above. The GridViewCommandEventArgs parameter contains a CommandName property which will be equal to this value ("DeleteRow"). This feature is very usefull when you have multiple commands all processed through the global RowCommand event handler on the grid. The code related to this is currently commented out so this feature is not necessary when your using the OnClick event handler.
    • CommandArgument='<%# Eval("BillingTypeID") %>': This value is also meant to be used with gvBillingType_RowCommand event. The GridViewCommandEventArgs parameter contains a CommandArgument property which will be equal to this value (Eval("BillingTypeID") which will equal the BillingTypeID for the current row). This feature is very usefull for passing row specific information through the global RowCommand event handler on the grid. The code related to this is currently commented out so this feature is not necessary when your using the OnClick event handler.
    • OnClick="cmdDelete_Click": If the previous 2 properties were actually being used it would not be necessary to add an OnClick event handler but I wanted to show another method of handling the deletes. See cmdDelete_Click function in the related code comments below.

    Status field template:

    <asp:TemplateField HeaderText="Status">
      <ItemTemplate>
        <asp:Label ID="Label2" runat="server" Text='<%# Bind("Status") %>'></asp:Label>
      </ItemTemplate>
    </asp:TemplateField>
       

    The "Status" field was added to hold text information related to the state of a row. The text is updated from within the code which is why a label is used. The binding should have been a one-way binding to make it more efficient but the two-way binding will work just as well.

Page 2 of this tutorial (BillingTypeEditGrid.aspx.cs, C# Code)