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