VB Magic

2012/11/08

OData AddTo using WinRT and VB.net

I was trying to find a way to POST a new entity to an OData feed and found it hard to find examples of doing this. After a bit of searching I found some C# code that allowed me to do an update. After converting this to VB I ended up with

    Private Sub addPersonButton_Click_1(sender As Object, e As RoutedEventArgs)

        Dim p As New Person
        p.name = personNameTextBox.Text
        If p.name <> "" Then
            _context.AddToPerson(p)
            _context.BeginSaveChanges(AddressOf ContextSaveChanges, p)
        End If
    End Sub

Person is part of an OData feed I am using e.g. http://server/odata.svc/Person

So I create a new instance of a Person and add a name to it (From a TextBox in the UI)

Then I use the AddToPerson method of the context and as there is no synchronous way in WinRT to SaveChanges, I used the BeginSaveChanges method of the context and passed through the address of the routine that will handle the callback.

    Private Function ContextSaveChanges(result As IAsyncResult) As Task
        Try
            _context.EndSaveChanges(result)
        Catch ex As Exception
            _message = ex.Message
            If ex.InnerException IsNot Nothing Then
                _message = _message & " - " & ex.InnerException.Message
            End If
            Me.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, AddressOf UpdateUI)
        End Try
    End Function

    Public Sub UpdateUI()
        personNameTextBox.Text = _message
    End

Above is the function that gets called and it will try to run EndSaveChanges and trap any error that occurred and display it on the UI. I originally put the personNameTextBox.Text = ex.Message in the catch section but that caused a Treading error [RPC_E_WRONG_THREAD]. So after a lot of routing around and the help of a colleague I discovered the Me.Dispacher.RunAsync function in which I had a lambda expression in to update the UI. This didn’t fail but also didn’t update the UI so I used a subroutine and put the AddressOf in the RunAsync command and this worked as expected.

Phew made it 😉

2012/10/30

Accessing and OData Feed in WinRT App using Visual Basic.NET

Filed under: .NET, VB.NET, Windows 8, Windows Store App — Tags: , , , — vbmagic @ 5:12 pm

As I’ve been searching the internet to try and find ways of accessing OData Feeds in visual basic .net and not finding much help I thought I’d put together a small example to help others.

This will use a demo OData feed to pull customer records from an example banking application. The feed is located in an Azure Cloud Service and is accessed by the following URL

http://t24irisdemo.cloudapp.net/tbank/Wealth.svc/

(This feed may be removed in the future)

The first thing to do is create a Visual Basic Blank Windows Store XAML application.

Also add a basic page called CustomerPage.

Add a Service Reference which points to the above URL

Visual Studio Dialog

Add Service Reference

We will only use Customers from the feed.

First display all the customers. To do this we need to add a Gridview to the main page XAML with an Item Template to display customer information. (I’m not a designer so I apologies for the rough look of the details 😉 )

        <GridView x:Name="defaultGridView" Grid.Row="1" Tapped="defaultGridView_Tapped_1" Margin="10" BorderBrush="#FFF7EC05" BorderThickness="1" FontFamily="Global User Interface" >
            <GridView.ItemTemplate>
                <DataTemplate>
                    <Grid Width="250" Height="135" Background="#002">
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="*" />
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="0" Text="{Binding Path=CustomerCode}" HorizontalAlignment="Center" FontWeight="ExtraBold" ></TextBlock>
                        <Image Grid.Column="0" Grid.Row="1" Grid.RowSpan="2" Source="{Binding Path=Photo}" Stretch="Uniform" Margin="4" VerticalAlignment="Center" HorizontalAlignment="Center"/>
                        <TextBlock Grid.Column="1" Grid.Row="1"  FontStyle="Italic" VerticalAlignment="Bottom">Name:</TextBlock>
                        <TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding Path=Name}" VerticalAlignment="Top" HorizontalAlignment="Left" TextWrapping="Wrap"></TextBlock>
                    </Grid>
                </DataTemplate>
            </GridView.ItemTemplate>
        </GridView>

Next add the following code to the code behind for the Main Page.

Imports System.Data.Services.Client

' The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238

''' <summary>
''' An empty page that can be used on its own or navigated to within a Frame.
''' </summary>
Public NotInheritable Class MainPage
    Inherits Page

    Private Const IRISURL As String = "http://t24irisdemo.cloudapp.net/tbank/Wealth.svc"
    Private _context As New irisServiceReference.T24Wealth(New Uri(IRISURL))
    Private WithEvents _allCust As DataServiceCollection(Of irisServiceReference.Customers)

    ''' <summary>
    ''' Invoked when this page is about to be displayed in a Frame.
    ''' </summary>
    ''' <param name="e">Event data that describes how this page was reached.  The Parameter
    ''' property is typically used to configure the page.</param>
    Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)

        _allCust = New DataServiceCollection(Of irisServiceReference.Customers)
        AddHandler _allCust.LoadCompleted, AddressOf LoadAllCustComplete
		
		Dim query = _context.Customers
        _allCust.LoadAsync(query)
    End Sub

    Private Sub LoadAllCustComplete(sender As Object, e As LoadCompletedEventArgs)
        defaultGridView.ItemsSource = _allCust
    End Sub

    Private Sub defaultGridView_Tapped_1(sender As Object, e As TappedRoutedEventArgs)
        Dim gv As GridView = sender

        Dim item As irisServiceReference.Customers = gv.SelectedItem
        Dim customerNo As String = customerNo = item.CustomerCode

        Frame.Navigate(GetType(CustomerPage), customerNo)
    End Sub
End Class

The above code will pull all the customers from the feed and then bind them to the GridView. There is also a Tap event handler which will pull the customer number from the grid view item and navigate to the customer view page (I’ll leave this to you to have a go a designing the look and feel. In the following code example I assumed there is a text block called customerNameTextBlock).

If you put a debug point at the _allCust.LoadAsync(query) line. You will notice that Query is turned into a URL to the feed.

query = {http://t24irisdemo.cloudapp.net/tbank/Wealth.svc/Customers}

Next we need to put code behind the Customer info page to pull the tapped customer details back so that we can populate this page. The following code with do this.

' The Basic Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234237
Imports System.Data.Services.Client

''' <summary>
''' A basic page that provides characteristics common to most applications.
''' </summary>
Public NotInheritable Class CustomerPage
    Inherits Common.LayoutAwarePage

    Private Const IRISURL As String = "http://t24irisdemo.cloudapp.net/tbank/Wealth.svc"
    Private _context As New irisServiceReference.T24Wealth(New Uri(IRISURL))
    Private WithEvents _allCust As DataServiceCollection(Of irisServiceReference.Customers)

        ''' <summary>
        ''' Populates the page with content passed during navigation.  Any saved state is also
        ''' provided when recreating a page from a prior session.
        ''' </summary>
        ''' <param name="navigationParameter">The parameter value passed to
        ''' <see cref="Frame.Navigate"/> when this page was initially requested.
        ''' </param>
        ''' <param name="pageState">A dictionary of state preserved by this page during an earlier
        ''' session.  This will be null the first time a page is visited.</param>
    Protected Overrides Sub LoadState(navigationParameter As Object, pageState As Dictionary(Of String, Object))

    End Sub

        ''' <summary>
        ''' Preserves state associated with this page in case the application is suspended or the
        ''' page is discarded from the navigation cache.  Values must conform to the serialization
        ''' requirements of <see cref="Common.SuspensionManager.SessionState"/>.
        ''' </summary>
        ''' <param name="pageState">An empty dictionary to be populated with serializable state.</param>
    Protected Overrides Sub SaveState(pageState As Dictionary(Of String, Object))

    End Sub

    Protected Overrides Sub OnNavigatedTo(e As Navigation.NavigationEventArgs)
        Dim customerNo As String = e.Parameter

        pageTitle.Text = "Customer " + customerNo

        _allCust = New DataServiceCollection(Of irisServiceReference.Customers)
        AddHandler _allCust.LoadCompleted, AddressOf allCustomerLoadCompleted

        Dim query = From c In _context.Customers
                    Where c.CustomerCode = customerNo
                    Select c

        _allCust.LoadAsync(query)
    End Sub

    Private Sub allCustomerLoadCompleted(sender As Object, e As LoadCompletedEventArgs)
        customerNameTextBlock.Text = _allCust.Single.Name
    End Sub

End Class

You’ll notice in this piece of code that a Linq query is used to pull the customer record from the feed. If you again put a debug point at _allCust.LoadAsync(query) you will notice the query is also transformed into a OData URL.

query = {http://t24irisdemo.cloudapp.net/tbank/Wealth.svc/Customers()?$filter=CustomerCode eq '100320'}

Hopefully this very simple example will help you get kick-started in developing WinRT applications that access OData feed.

2012/09/21

Sort of found the answer to my sharing issue with WinRT & Dropbox

Filed under: Windows 8, Windows Store App — Tags: , , , — vbmagic @ 8:21 pm

It turns out, if you have the same folder location on two different machines. E.g. the default drop box location c:\users\{user}\dropbox,  this makes the project fail to run on a the machine that wasn’t the one it was created on.

If you move the dropbox folder to a new location on the other machine, E.g. c:\Dropbox then it will run with no issues. A weird one this, no one had an answer to why it happens.

Hopefully if someone else has this issue, then this post may help them.

BTW: The person at the Workshop seemed to be taken aback that the app was written using VB too 😉

Blog at WordPress.com.