Alessandro Del Sole's Blog

/* A programming space about Microsoft® .NET® */
posts - 159, comments - 0, trackbacks - 0

My Links

News

Your host

This is me! This space is about Microsoft® .NET® and Microsoft® Visual Basic development. Enjoy! :-)

These postings are provided 'AS IS' for entertainment purposes only with absolutely no warranty expressed or implied and confer no rights.

Microsoft MVP

My MVP Profile

I'm a VB!

Watch my interview in Seattle

My new book on VB 2015!

Pre-order VB 2015 Unleashed Pre-order my new book "Visual Basic 2015 Unleashed". Click for more info!

My new book on LightSwitch!

Visual Studio LightSwitch Unleashed My book "Visual Studio LightSwitch Unleashed" is available. Click the cover!

Your visits

Follow me on Twitter!

CodePlex download Download my open-source projects from CodePlex!

Article Categories

Archives

Post Categories

.NET Framework

Blogroll

Help Authoring

Microsoft & MSDN

Setup & Deployment

Visual Basic 2005/2008/2010

WPF: The drag'n'drop data-binding in Visual Basic 2010 Beta 1 - part four (Entity Framework)

This is the last post of the introductory small series about the drag'n'drop data-binding for WPF in Visual Studio 2010 Beta 1. We're going to discuss the same topic I presented in my previous blog post, this time focusing the usage of the ADO.NET Entity Framework as the data-source in Visual Basic applications. Basically we're going to create the same kind of application shown in the previous post using DataSets; this means that we'll create a master-details representation, with the ability of choosing customers from a ListBox and viewing related orders implementing controls for navigating the orders themselves.

 

So you can create a new WPF project for Visual Basic 2010 and repeat all the steps we saw in the second post of this series until you complete the generation of the Entity Data Model. Once done this, ensure that in the Data Sources window are listed the EntitySets generated by the Entity Framework, particularly Customers and Orders. At this point, from the toolbox drag a ListBox control onto the Window's surface and then edit the Grid position as follows:

 

    <Grid>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="200" />

            <ColumnDefinition/>

        </Grid.ColumnDefinitions>

        <Grid.RowDefinitions>

            <RowDefinition/>

            <RowDefinition Height="40"/>

        </Grid.RowDefinitions>

       

        <ListBox Grid.Column="0" Grid.Row="0"/>

    </Grid>

 

Now, from the Data Sources window, select the CompanyName item exposed by the Customers object and drag it onto the ListBox as shown in the following figure:

The result of this task is that Visual Studio generated some lines of XAML code. First of all, the IDE generated a new resource pointing to the list of customers and each of them is represented by a Customer object; for Customers a new list is generated:

 

    <Window.Resources>

        <CollectionViewSource x:Key="CustomersViewSource__NorthwindEntities" d:DesignSource="{d:DesignInstance my:Customer,

                              CreateList=True}" />

    </Window.Resources>

 

The code also assigns the main Grid's DataContext property, so that controls nested inside the Grid itself can be automatically populated:

 

    <Grid DataContext="{StaticResource CustomersViewSource__NorthwindEntities}">

 

The ListBox is also edited as follows:

 

        <ListBox Grid.Column="0" Grid.Row="0"

                 DisplayMemberPath="CompanyName" IsSynchronizedWithCurrentItem="True"

                 ItemsSource="{Binding}" SelectedIndex="0" />

 

You can notice how the control is data-bound, via the assignment of the ItemsSource property. The data-binding source is constitued by the Grid's DataContext property. The next step is establishing the orders data-binding. Let's go back to the Data Sources window and select the Orders object (the one nested inside Customers), ensuring that the Details view is selected:

 

Let's drag Orders onto the right side of the window; when released, we should get a result similar to the following figure:

As we can see, the IDE generated for us a collection of controls, basically a series of Label and TextBox (except for DateTime objects represented by DatePicker) enclosed inside a new Grid declared via the following XAML:

 

        <Grid DataContext="{StaticResource CustomersOrdersViewSource}" Grid.Column="1" Name="Grid1">

            <Grid.ColumnDefinitions>

                <ColumnDefinition Width="Auto" />

                <ColumnDefinition Width="Auto" />

            </Grid.ColumnDefinitions>

            <Grid.RowDefinitions>

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

                <RowDefinition Height="Auto" />

            </Grid.RowDefinitions>

            <Label Content="Order ID:" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="0" Height="23" HorizontalAlignment="Left" Margin="3" Name="OrderIDTextBox" Text="{Binding Path=OrderID}" VerticalAlignment="Center" Width="120" />

            <Label Content="Employee ID:" Grid.Column="0" Grid.Row="1" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="1" Height="23" HorizontalAlignment="Left" Margin="3" Name="EmployeeIDTextBox" Text="{Binding Path=EmployeeID}" VerticalAlignment="Center" Width="120" />

            <Label Content="Order Date:" Grid.Column="0" Grid.Row="2" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <DatePicker Grid.Column="1" Grid.Row="2" HorizontalAlignment="Left" Margin="3" Name="OrderDateDatePicker" SelectedDate="{Binding Path=OrderDate}" VerticalAlignment="Center" />

            <Label Content="Required Date:" Grid.Column="0" Grid.Row="3" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <DatePicker Grid.Column="1" Grid.Row="3" HorizontalAlignment="Left" Margin="3" Name="RequiredDateDatePicker" SelectedDate="{Binding Path=RequiredDate}" VerticalAlignment="Center" />

            <Label Content="Shipped Date:" Grid.Column="0" Grid.Row="4" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <DatePicker Grid.Column="1" Grid.Row="4" HorizontalAlignment="Left" Margin="3" Name="ShippedDateDatePicker" SelectedDate="{Binding Path=ShippedDate}" VerticalAlignment="Center" />

            <Label Content="Ship Via:" Grid.Column="0" Grid.Row="5" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="5" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipViaTextBox" Text="{Binding Path=ShipVia}" VerticalAlignment="Center" Width="120" />

            <Label Content="Freight:" Grid.Column="0" Grid.Row="6" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="6" Height="23" HorizontalAlignment="Left" Margin="3" Name="FreightTextBox" Text="{Binding Path=Freight}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship Name:" Grid.Column="0" Grid.Row="7" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="7" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipNameTextBox" Text="{Binding Path=ShipName}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship Address:" Grid.Column="0" Grid.Row="8" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="8" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipAddressTextBox" Text="{Binding Path=ShipAddress}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship City:" Grid.Column="0" Grid.Row="9" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="9" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipCityTextBox" Text="{Binding Path=ShipCity}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship Region:" Grid.Column="0" Grid.Row="10" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="10" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipRegionTextBox" Text="{Binding Path=ShipRegion}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship Postal Code:" Grid.Column="0" Grid.Row="11" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="11" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipPostalCodeTextBox" Text="{Binding Path=ShipPostalCode}" VerticalAlignment="Center" Width="120" />

            <Label Content="Ship Country:" Grid.Column="0" Grid.Row="12" HorizontalAlignment="Left" Margin="3" VerticalAlignment="Center" />

            <TextBox Grid.Column="1" Grid.Row="12" Height="23" HorizontalAlignment="Left" Margin="3" Name="ShipCountryTextBox" Text="{Binding Path=ShipCountry}" VerticalAlignment="Center" Width="120" />

        </Grid>

 

This code is of course long but it's also simple. Controls (TextBoxes and DatePickers) are now data-bound. The collection of objects that acts as the data source (and that is the value of the new Grid's DataContext property) is represented by a new CollectionViewSource called CustomersOrdersViewSource that is also defined as a new resource:

 

        <CollectionViewSource x:Key="CustomersOrdersViewSource" Source="{Binding Path=Orders, Source={StaticResource CustomersViewSource__NorthwindEntities}}" />

    </Window.Resources>

 

We can then complete the UI adding some buttons for navigating between orders and for saving changes, writing the following code before the closing tag of the main Grid: 

 

        <StackPanel Orientation="Horizontal" Grid.Column="1" Grid.Row="1">

            <Button Margin="5" Content="&lt;Previous" Name="PrevButton" Width="100" Height="30"/>

            <Button Margin="5" Content="Next>" Name="NextButton" Width="100" Height="30"/>

            <Button Margin="5" Content="Save changes" Name="SaveButton" Width="100" Height="30"/>

        </StackPanel>

 

Let's now switch to the Visual Basic code so that we can observe what the IDE did for us. In the code-behind file we'll first find a method called GetCustomersQuery that queries the list of customers returning the result as an ObjectQuery(Of T):

 

    Private Function GetCustomersQuery(ByVal NorthwindEntities As ItemsBrowsingWithEntityFramework.NorthwindEntities) As

                     System.Data.Objects.ObjectQuery(Of ItemsBrowsingWithEntityFramework.Customer)

 

        Dim CustomersQuery As System.Data.Objects.ObjectQuery(Of ItemsBrowsingWithEntityFramework.Customer) =

                              NorthwindEntities.Customers

        'Update the query to include Orders data in Customers. You can modify this code as needed.

        CustomersQuery = CustomersQuery.Include("Orders")

        'Do not modify the following code.

        Return CustomersQuery

    End Function

 

Obviously we could change the query according to our needs but in this scenario we want to retrieve the list of all the customers. The eager-loading technique (see method Include) retrieves also the orders related to each customer. The last code loads and binds data when the Window is loaded:

 

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

 

        Dim NorthwindEntities As ItemsBrowsingWithEntityFramework.NorthwindEntities = New

                                 ItemsBrowsingWithEntityFramework.NorthwindEntities()

        'Load data into Customers. You can modify this code as needed.

        Dim CustomersViewSource__NorthwindEntities As System.Windows.Data.CollectionViewSource = CType(Me.FindResource

            ("CustomersViewSource__NorthwindEntities"), System.Windows.Data.CollectionViewSource)

        Dim CustomersQuery As System.Data.Objects.ObjectQuery(Of ItemsBrowsingWithEntityFramework.Customer) = Me.GetCustomersQuery

            (NorthwindEntities)

        CustomersViewSource__NorthwindEntities.Source = CustomersQuery.Execute(System.Data.Objects.MergeOption.AppendOnly)

        CustomersViewSource__NorthwindEntities.View.MoveCurrentToFirst()

    End Sub

 

The code gets the instance of the customers' CollectionViewSource that receives the result of the above described query. The last line of code moves the focus to the first item of the collection.

This is a basic code generation and you'll probably need some manual edits in a real world application. We'll now make some edits but our work will also be very simple, this is because we want to understand where and what we have to edit to improve the code.

Let's start by making one consideration: we want to be able to implement custom actions versus the data source; to accomplish this we must move to class level the ObjectContext instance declaration and the declaration of the CollectionViewSource for Customers, moreover we need an additional declaration shown in the following code:

 

Class Window1

 

    Private NorthwindEntities As ItemsBrowsingWithEntityFramework.NorthwindEntities

    Private CustomersViewSource__NorthwindEntities As System.Windows.Data.CollectionViewSource

    Private CustomersOrdersViewSource As CollectionViewSource

 

We have declared also the CollectionViewSource related to orders. Next, let's change the Window_Loaded event handler as follows:

 

    Private Sub Window_Loaded(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded

 

        NorthwindEntities = New ItemsBrowsingWithEntityFramework.NorthwindEntities()

 

        'Load data into Customers. You can modify this code as needed.

        CustomersViewSource__NorthwindEntities = CType(Me.FindResource("CustomersViewSource__NorthwindEntities"),

        System.Windows.Data.CollectionViewSource)

        'Otteniamo anche l’istanza dell’altra CollectionViewSource.

        CustomersOrdersViewSource = CType(Me.FindResource("CustomersOrdersViewSource"), System.Windows.Data.CollectionViewSource)

 

        Dim CustomersQuery As System.Data.Objects.ObjectQuery(Of ItemsBrowsingWithEntityFramework.Customer) = Me.GetCustomersQuery

           (NorthwindEntities)

        CustomersViewSource__NorthwindEntities.Source = CustomersQuery.Execute(System.Data.Objects.MergeOption.AppendOnly)

        CustomersViewSource__NorthwindEntities.View.MoveCurrentToFirst()

    End Sub

 

As I already mentioned in different circumstances, a better programming technique would be separating the UI from the business logic and the DAL. So this example is good for our goal of introducing the new features in Dev10 but some additional work should be done. 

 

We can now add an event handler for the Click event of the Save Changes button:

 

    Private Sub SaveButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles SaveButton.Click

        Try

            Me.NorthwindEntities.SaveChanges()

        Catch ex As Exception

 

        End Try

    End Sub

 

Again we can take advantage of the Views that I introduced in my previous post and we can handle the other two buttons to provide the ability of switching between items:

 

    Private Sub NextButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles NextButton.Click

        If Me.CustomersOrdersViewSource.View.CurrentPosition < CType(Me.CustomersOrdersViewSource.View, CollectionView).Count - 1 Then

            Me.CustomersOrdersViewSource.View.MoveCurrentToNext()

        End If

 

    End Sub

 

    Private Sub PrevButton_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles PrevButton.Click

        If Me.CustomersOrdersViewSource.View.CurrentPosition > 0 Then

            Me.CustomersOrdersViewSource.View.MoveCurrentToPrevious()

        End If

    End Sub

 

Now we can try and run the application. We should get a result similar to what we can see in the following figure:

You'll notice how the new buttons will allow you to navigate orders and how changes are correctly saved to the original data source. We'll discuss in future post other interesting features about the WPF 4.0 data-binding that can be also used in Visual Studio 2010 Beta 1.

 

The source code for the complete blog post series is available from the MSDN Code Gallery and you can download it by clicking here.

 

Alessandro

Print | posted on sabato 20 giugno 2009 20:23 | Filed Under [ Visual Studio 2010 Visual Basic Windows Presentation Foundation ]

Feedback

No comments posted yet.

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 2 and 8 and type the answer here:

Powered by:
Powered By Subtext Powered By ASP.NET