VB Magic

2011/04/04

Dynamically creating pivot items and populating with data

Filed under: Learning — Tags: , , , , , , , — vbmagic @ 5:01 pm

I’ve spent the weekend trying to work out how to create the pages you see on a Pivot Page dynamically through code. It took a lot of web searching and trial and errors but I seem to have managed to get the basics of this worked out. I’m posting this to help other people who are trying to do the same thing. In this case it works, but if anyone else has a better/more efficient way of doing this I would be interested in looking at it.

The database/Web server has a directory full of images which the web service will pass back to the client using XML. Each image can belong to a image type. Each of these types will be a Pivot Item in the Pivot page. The list of images for each of these types will be displayed on each of these Pivot items.

I started by creating a pivot page and deleted any pivot items that where in the XAML. I then created the following Page Load event code:

    Private _client As New adminServiceReference.AdminServiceClient

    Private Sub PhoneApplicationPage_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
        ' setup the event handlers for retrieving image types and image lists
        AddHandler _client.GetImageTypesCompleted, AddressOf client_GetImageTypesCompleted
        AddHandler _client.GetImagesCompleted, AddressOf client_GetImagesCompleted

        ' request the image types
        Dim str As New StrType
        str.TokenGUID = GetToken()
        _client.GetImageTypesAsync(str)
    End Sub

    Private Function GetToken() As Guid
        Dim result As Guid
        If _phoneAppService.State.TryGetValue("token", result) Then
            Return result
        Else
            MessageBox.Show("Failed to retrieve token")
            Return Nothing
        End If
    End Function

This will call the GetImageTypes web service on the server (I will document these in another post)
Once the request has been completed, all the image types will be sent back to the client in XML format.

    ' Routine to handle the Get Image Types completed event.
    Private Sub client_GetImageTypesCompleted(ByVal sender As Object, ByVal e As adminServiceReference.GetImageTypesCompletedEventArgs)
        If e.Error Is Nothing Then
            Dim types = e.Result
            ' did the server side report an error?
            If types.ErrorMessage = "" Then
                ' no so loop through each Image type in the xml result
                For Each ele In types.xml...<type>
                    ' We need to create a new Pivot item for each image type
                    Dim p As New PivotItem
                    ' set the header name to the lowercase version of the type name
                    ' this is to fit in with the standard way of showing pivot items
                    p.Header = ele.Value.ToLower
                    ' add the pivot item to the pivot page
                    imagePivotControl.Items.Add(p)
                    ' now request all the images under of that type
                    Dim str As New StrType
                    str.text = ele.Value
                    _client.GetImagesAsync(str)
                Next
            Else
                ' The server side got an error so display the error
                ' to aid in debugging.
                MessageBox.Show(types.ErrorMessage)
            End If
        Else
            ' the request to the webservice caused an error so
            ' display this error to try and help debug the problem.
            MessageBox.Show(e.Error.Message)
        End If
    End Sub

The comments in the above code should lead you through the creation and titling of the PivotItem and used XML Literals a very handy feature in VB to make code more readable when interacting with XML. (This should be implemented in C#)

For each image type pivot item created it will also request all the images for that image type which the following code will handle.

    ' a routine to handle the Get Images completed event.
    Private Sub client_GetImagesCompleted(ByVal sender As Object, ByVal e As adminServiceReference.GetImagesCompletedEventArgs)
        ' Did the request cause an error
        If e.Error Is Nothing Then
            Dim imgs = e.Result
            ' Did the web server get an error while processing the request.
            If imgs.ErrorMessage = "" Then
                ' no error so start searching the PivotItems to find the one matching
                ' the type that we requested the images for.
                For Each pg As PivotItem In imagePivotControl.Items
                    If pg.Header.ToString = imgs.type.ToLower Then
                        ' We have a match so create a listbox item to hold the details
                        Dim lb As New ListBox
                        ' we need a counter to display next to the image
                        ' this is only temorary until we have an image there
                        Dim cnt As Integer = 0
                        ' Loop through all the image elements in the returned XML
                        For Each ele In imgs.xml...<image>
                            ' We need to create a grid to store the information in the
                            ' list box item this is the equivilent to the following XAML
                            '
                            '   <grid>
                            '       <Grid.RowDefinitions>
                            '           <RowDefinition Height="Auto"/>
                            '       </Grid.RowDefinitions>
                            '       <Grid.ColDefinitions>
                            '           <ColDefinition Width="100"/>
                            '           <ColDefinition Width="Auto"/>
                            '       </Grid.RowDefinitions>
                            '    </grid>

                            ' Create the grid object
                            Dim grd As New Grid
                            ' Create the row definition objec
                            Dim rowdef As New RowDefinition
                            ' the row definition object uses a object called gridlength
                            ' we create one of these and set it to Auto
                            Dim glen As New GridLength
                            glen = GridLength.Auto
                            ' we add the height information to the row definition
                            rowdef.Height = glen
                            ' now we add the row definition to the list of row definitions
                            ' in the grid object
                            grd.RowDefinitions.Add(rowdef)
                            ' Now we need to create a column definition
                            Dim coldef As New ColumnDefinition
                            ' the first column has a width of 100 pixels for now, it will
                            ' contain an image eventually and we can leave it set to auto.
                            coldef.Width = New GridLength(100)
                            ' add the column definition to the list of column definitions in
                            ' the grid object.
                            grd.ColumnDefinitions.Add(coldef)
                            ' we now create the second column definition to auto which is the
                            ' same as we used with the row definiton so lets just re-use
                            ' this object.
                            coldef = New ColumnDefinition
                            coldef.Width = glen
                            ' add the final column definition to the collection of column
                            ' definitions in the grid object.
                            grd.ColumnDefinitions.Add(coldef)

                            ' Now we start to add the data, first we create a textblock that
                            ' will be used to hold the count.
                            ' This is the equivilent to the following XAML.
                            '
                            '   <TextBox Grid.Column="0" Grid.Row="0" Text="{cnt.string}"/>
                            '
                            Dim tb = New TextBlock
                            ' we set the row and column of the textblock to make it appear in
                            ' the correct loctation
                            Grid.SetColumn(tb, 0)
                            Grid.SetRow(tb, 0)
                            ' set the text property of the text block to the current count
                            tb.Text = cnt.ToString
                            ' add the textblock to the children objects of the grid.
                            grd.Children.Add(tb)
                            ' Now we add a new text block which will display the name of the
                            ' image file on the server.
                            ' This is the equivilent to the following XAML
                            '
                            '   <TextBox Grid.Column="1" Grid.Row="0" Text="{ele.value}"/>
                            '
                            tb = New TextBlock
                            ' set the row and column information of the text block.
                            Grid.SetColumn(tb, 1)
                            Grid.SetRow(tb, 0)
                            ' pull the content of the image item ( <image>value</image> ) and
                            ' put this into the text property of the text block
                            tb.Text = ele.Value
                            ' add the text block to the child objects of the grid.
                            grd.Children.Add(tb)

                            ' Now we create the list box item to add to the list box in
                            ' the pivot item.
                            Dim lbi As New ListBoxItem
                            ' add the grid to the listbox item
                            lbi.Content = grd
                            ' and add the list box item to the list box
                            lb.Items.Add(lbi)
                            ' increment the counter
                            cnt += 1
                        Next
                        ' add the list box to the pivot item.
                        pg.Content = lb
                    End If
                Next
            Else
                ' the server produced and error so display to aid in debugging
                MessageBox.Show(imgs.ErrorMessage)
            End If
        Else
            ' the request caused and error so display this to aid in debugging
            MessageBox.Show(e.Error.Message)
        End If
    End Sub

Again I have commented the code to lead you through how the listbox and listbox items are created from the XML results and used to populate the pivot item for each image type.

Jas

Blog at WordPress.com.