• Beth Massi - Sharing the goodness

    How We Do It: Building the Visual Studio Product Line

    • 1 Comments

    Ever wonder how we build Visual Studio and the .NET Framework? I mean literally. You know, the build process that spits out a product at the other end?  Well I sure did and it's not just hitting F5 people ;-).

    In this interview I sit down with Matt Gertz, frequent VB blogger and also the guy in charge of the builds in Developer Division (he has a long title, but I forget what it is :-)). He explains how the build and test processes work on a team of two thousand people all on Team Foundation Server. I must say it's pretty darn impressive. Many thanks to Matt for taking time out of his busy schedule to do this interview!

    How We Do It: Building the Visual Studio Product Line

    Enjoy!

  • Beth Massi - Sharing the goodness

    Visual Studio 2010 Beta 1 – Everyone can download and play today!

    • 11 Comments

    Here it is folks, Visual Studio 2010 Beta 1 has been released to the public today. Check out the Visual Studio 2010 and .NET Framework 4 Beta 1 site to download the Beta, submit product feedback on the Beta 1 Forums, report bugs on Connect, and find additional information. Also visit the Beta 1 walkthroughs page for information on how to use the new features and download the Visual Studio 2010 Samples. There’s also some good language-focused resources on the Visual Basic 2010 and C# 2010 that are hanging off the Developer Centers.

    Some of my favorite features include those around the WPF Designer and the Data Sources Window which now supports the same drag-drop RAD experience of Winforms in WPF applications:

    For Office solutions, check out the Advanced Office Solution Deployment topic in the library and the VSTO Team blog for some cool new Office client features:

    Take a look through the Visual Studio 2010 Product Highlights and What's New in Visual Studio 2010 for more info on other new features including multi-monitor – YUMMY! :-)

    New Team Bloggers

    I’d also like to introduce the “come-back” of the Visual Studio Data team blog. We’ve got a lot of new faces on the team that are building some amazing tools in Visual Studio to help you build business applications. They’ll be posting a lot of great VS 2010 content here

    Visual Studio 2010 Beta 1 resources:

    My recommended blogs on VS 2010:

    Enjoy!

  • Beth Massi - Sharing the goodness

    I’ll be Speaking at DevTeach Vancouver – Be There!

    • 3 Comments

    I’m headed up to Vancouver June 8-12 for DevTeach. I love DevTeach because of it’s close, friendly atmosphere that you don’t get with the larger conferences. The caliber of speakers is excellent and they easily accessible and always floating around the session hallways, ballrooms and of course the bars ;-). Plus, the deal is great – buy 2 passes, get one free.

    Here’s some more reasons to go:

    Keynote: Visual Studio 2010 — Your Development Happy Place : Tim Huckaby is putting together a great Keynote that will show off a lot of the awesome features in Visual Studio 2008 as well as new features in Visual Studio 2010. I’ll be on hand for a short demo myself that shows off some of our new WPF data-binding tools.

    User Group Night Monday June 8th : This one is Free for everyone just before the kickoff party on Monday night. I’ll be presenting Future Directions for Microsoft Visual Basic and C# from 6pm to 8pm. Register for the user group here.

    DevTeach has a jam packed conference schedule. 136 sessions will be presented with many advanced sessions as well. They are including a Silverlight track and an application live-cycle track this time. Also check out the three Pre-Conference workshops on June 8th. I’d highly recommend Building Business Applications with Silverlight 2.0. There’s also three Post-Conference workshops on June 12th, one with Julie Lerman on ADO.NET Entity Framework that I know will be awesome.

    Register for DevTeach here.

    Hope to see you there!

  • Beth Massi - Sharing the goodness

    TechEd Sessions Online – My Favorites

    • 4 Comments

    Now that TechEd is over, you can head on over to TechEd Online and watch some interesting sessions and tech talks. Not all of them are available to non-attendees but here are my favorites that have public access:

    If you did register for TechEd but missed these I’d highly recommend them (only attendees can view these):

    Enjoy!

  • Beth Massi - Sharing the goodness

    Using TableAdapters to Insert Related Data into an MS Access Database

    • 59 Comments

    I’ve posted before about how to use TableAdapters to update parent-child (master-detail) relationships against SQL server. It’s pretty straightforward and Visual Studio generates all the code for you to properly insert, update and delete your data. However if you’re using MS Access then there’s one thing that Visual Studio doesn’t do because it’s not supported when using Access.

    How Parent-Child Inserts Work

    When Visual Studio generates the insert commands on a SQL-Server TableAdapter it looks to see if the table’s primary keys are auto-generated (identity columns) and if so, Visual Studio will write an additional statement to retrieve the key using the SCOPE_IDENTITY functionality of SQL Server. When in the DataSet designer, if you look at the insert statement in the properties window for the SQLTableAdapter you will see two statements separated by a semi-colon:

    image

    INSERT INTO [dbo].[Products] ([ProductName], [SupplierID], [CategoryID], [QuantityPerUnit], [UnitPrice], [UnitsInStock], [UnitsOnOrder], [ReorderLevel], [Discontinued]) VALUES (@ProductName, @SupplierID, @CategoryID, @QuantityPerUnit, @UnitPrice, @UnitsInStock, @UnitsOnOrder, @ReorderLevel, @Discontinued);
    SELECT ProductID, ProductName, SupplierID, CategoryID, QuantityPerUnit, UnitPrice, UnitsInStock, UnitsOnOrder, ReorderLevel, Discontinued FROM Products WHERE (ProductID = SCOPE_IDENTITY())

    SQL Server supports batch statements through ADO.NET commands so this will populate the primary key back in the DataRow inside the DataSet as each row is inserted into the database. If you are enforcing foreign key constraints with a parent-child relation set up on two DataTables and you set the Update Rule to Cascade then any foreign key references will also be updated in the children. Because the TableAdapterManager will save the children after their parent records, when the child saves to the database it will contain the correct parent key which must already exist in the database before a child can be inserted in order to maintain referential integrity in the database.

    Unfortunately Access doesn’t support batch statements. If you look at what is generated for Access you will only see one statement (also the OLEDB provider does not support named parameters hence the question mark placeholders):

    INSERT INTO `Products` (`ProductName`, `SupplierID`, `CategoryID`, `QuantityPerUnit`, `UnitPrice`, `UnitsInStock`, `UnitsOnOrder`, `ReorderLevel`, `Discontinued`) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)

    So if you are doing inserts, especially for related parent-child data, you need a way to intercept the DataRow and set the primary key right after the row is inserted into the database and before any children are inserted. There’s an excellent article by Bill Vaughn (VB MVP) that explains this issue as well as a KB Article that shows how to solve it using the DataAdapter. These were written before Visual Studio had the concept of TableAdapters (which were added in VS 2008) so let’s see how we could use this technique to enhance our TableAdapters via partial classes.

    Setting up the Parent-Child DataSet

    The first step is to make sure you set up the tables in your Access database to use the AutoNumber feature for the primary keys on the rows. Here I’m using Access 2007 against the Northwind Access database. AutoNumber is used for both the primary keys on the Products and Categories tables:

    image

    Next you need to make sure you set up the relationship on the DataSet properly so that the primary key on the parent will cascade to the foreign key on the child. Set the relation in the DataSet designer to "Both Relation and Foreign Key Constraint" and then set the Update and Delete rules to Cascade. Just right-click on the relation and select "Edit Relation" in the DataSet designer:

    image image

    Loading and Editing the Parent-Child DataSet

    You now are telling the DataSet to enforce the foreign key relationship which means that you must have a parent for every child. This means you have to load the data in parent then child order. You also have to be careful with your queries. You have to make sure that every row in the child DataTable will have a corresponding parent row in the parent DataTable. This also means that you have to make sure to call EndEdit on any new parent BindingSource before any children can be added.

    For example, from the Data Sources window drag the Categories parent table as details and the related child Products table as a DataGridView on the form and Visual Studio will generate the code to load and save our data.

    image

    Head over to the code behind and make sure that the parent is filled first before the child. Also make sure that EndEdit is called on the CategoriesBindingSource before a new product can be inserted into the DataGridView. EndEdit will flush the data row being edited by the controls into the DataTable. In this example I just am calling EndEdit on the CategoriesBindingSource when the user selects the grid.

    Public Class Form1
    
        Private Sub CategoriesBindingNavigatorSaveItem_Click() _
                Handles CategoriesBindingNavigatorSaveItem.Click
            Me.Validate()
            'Call EndEdit on all BindingSources! 
            Me.CategoriesBindingSource.EndEdit()
            Me.ProductsBindingSource.EndEdit()
            Me.TableAdapterManager.UpdateAll(Me.ProductsDataSet)
        End Sub
    
        Private Sub Form1_Load() Handles MyBase.Load
            'Load parent before child!
            Me.CategoriesTableAdapter.Fill(Me.ProductsDataSet.Categories)
            Me.ProductsTableAdapter.Fill(Me.ProductsDataSet.Products)
        End Sub
    
        Private Sub ProductsDataGridView_Enter() Handles ProductsDataGridView.Enter
            'You must commit the parent row to the DataTable before adding child rows 
            Me.CategoriesBindingSource.EndEdit()
        End Sub
    
    End Class

    Note that anytime you call EndEdit and flush the data to the DataTable, the row must not fail any constraints either (i.e. if NULLs aren’t being allowed then you have to set those values). One way to handle this is to add code to set default values in the TableNewRow handler on the DataTable.

    Enhancing the TableAdapter Partial Classes

     

     

     

    Now for the good stuff. Like I mentioned in the beginning, you need a way to set the primary key on the parent right after the row is inserted into the database and before any children are inserted. Now that we have keys cascading we just need to write code to handle the RowUpdated event on the DataAdapter inside the TableAdapter partial class. TableAdapters are generated classes that Visual Studio creates for us from the DataSet designer. These classes are declared as Partial Classes so that means we can add code to the same class even if it’s in a separate file. Right-click on the TableAdapter class in the DataSet Designer and select View Code and the partial class file that you can edit will be created for you.

    Namespace ProductsDataSetTableAdapters
    
        Partial Public Class CategoriesTableAdapter
    
        End Class
    
        Partial Public Class ProductsTableAdapter
    
        End Class
    End Namespace

    In these classes we can handle the RowUpdated event on the private variable _adapter which gives us access to the ADO.NET DataAdapter that is executing the updates to our rows. The way we retrieve the primary key is by executing the statement  SELECT @@IDENTITY which tells Access to send back the last primary key it used on the connection. Because you have to add this handler to all your TableAdapters that are working against MS Access, to make things more manageable you can create a class with a Shared (static) method to handle setting the key and then call that from the handlers.

    Imports System.Data.OleDb
    
    Public Class AccessIDHelper
        ''' <summary>
        ''' Retrieves the primary key autonumber values from Access
        ''' </summary>
        ''' <remarks></remarks>
        Public Shared Sub SetPrimaryKey(ByVal trans As OleDbTransaction, _
                                        ByVal e As OleDbRowUpdatedEventArgs)
            If e.Status = UpdateStatus.Continue AndAlso _
               e.StatementType = StatementType.Insert Then
                ' If this is an INSERT operation...
                Dim pk = e.Row.Table.PrimaryKey
                ' and a primary key column exists...
                If pk IsNot Nothing AndAlso pk.Count = 1 Then
                    Dim cmdGetIdentity As New OleDbCommand("SELECT @@IDENTITY", trans.Connection, trans)
                    ' Execute the post-update query to fetch new @@Identity
                    e.Row(pk(0)) = CInt(cmdGetIdentity.ExecuteScalar)
                    e.Row.AcceptChanges()
                End If
            End If
        End Sub
    End Class
    
    Namespace ProductsDataSetTableAdapters
    
        Partial Public Class CategoriesTableAdapter
    
            Private Sub _adapter_RowUpdated(ByVal sender As Object, _
                                            ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs) _
                                            Handles _adapter.RowUpdated
    
                AccessIDHelper.SetPrimaryKey(Me.Transaction, e)
            End Sub
        End Class
    
        Partial Public Class ProductsTableAdapter
    
            Private Sub _adapter_RowUpdated(ByVal sender As Object, _
                                            ByVal e As System.Data.OleDb.OleDbRowUpdatedEventArgs) _
                                            Handles _adapter.RowUpdated
    
                AccessIDHelper.SetPrimaryKey(Me.Transaction, e)
            End Sub
        End Class
    End Namespace

    So that’s how you can get the primary keys into the data rows and have them properly cascaded to the child rows. So now when the children are updated they will have the correct foreign key and the parent will exist in the database. I hope this helps clear up how to work with Access and Visual Studio. 

    I’ve posted this example on CodeGallery so have a look.

    Enjoy!

  • Beth Massi - Sharing the goodness

    Special Guest at EastBay.NET User’s Group Tomorrow Night

    • 2 Comments

    This month we have a good friend of mine and Microsoft Visual Basic MVP, Rob Windsor, coming all the way from Toronto! Thanks Rob, for coming out to the Bay Area and speaking to our group on your birthday! We’re excited to have you and many thanks to INETA for bringing you out. 

    ASP.NET AJAX Tips and Tricks
    Wednesday, 5/13/2009
    Main presentation starts at 6:45 PM, FUNdamentals starts at 6:00pm

    [Please note, the location has changed for this month only!]
    Robert Half, 1999 Harrison Street, Suite 1100, Oakland, CA 94612 MAP

    This is on the corner of Harrison and 20th. You can take BART to 19th St Oakland for easy access.

    Click here for more information and to register.

    Rob’s staying at my place and since he’s a big baseball fan we caught my team playing his team (A’s vs. Jay’s) on Sunday. It was a good game if you’re a Jay’s fan. :-/

    RobAndBeth

    Hope to see all you East Bay folks there! FREE PIZZA! Take BART! Go A’s!

  • Beth Massi - Sharing the goodness

    TechEd is Online

    • 1 Comments

    If you’re like me and couldn’t make it down to L.A. this year for TechEd, you can still check out some of the sessions and Keynotes at TechEd Online. If you want to really geek out, you can also watch the twitter feed, blog feed and more.

    Don’t forget to check out some of the recommended sessions from Lisa and Christin:

    Enjoy!

  • Beth Massi - Sharing the goodness

    Using the WPF ObservableCollection with EF Entities

    • 15 Comments

    The ObservableCollection is a special WPF collection that provides proper notifications to the UI when items are added, removed, or the list is refreshed because it implements INotifyCollectionChanged. It’s common to use this collection (or inherit from it) to contain your business objects you want to bind to in WPF. 

    Class Window1
    Private CustomerData As ObservableCollection(Of Customer)

    You can then set up a CollectionViewSource and use it’s View property to get a reference to the ListCollectionView in order to add and remove items instead of working with the source collection directly. This decouples your data source (and therefore any collection logic) from the form itself making it much easier to change sources later. I’ve showed how to use CollectionViewSources before but basically you just declare them in the Window.Resources section and bind to them in XAML:

    <Window x:Class="Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="282" Width="440" Name="Window1">
        <Window.Resources>
            <CollectionViewSource x:Key="CustomerSource" />
        </Window.Resources>
        <Grid DataContext="{Binding Source={StaticResource CustomerSource}}">

    And then you can set the Source property in code to your collection and obtain the ListCollectionView.

    Dim customerSource = CType(Me.Resources("CustomerSource"), CollectionViewSource)
    customerSource.Source = Me.CustomerData
    
    Me.View = CType(customerSource.View, ListCollectionView)

    Then you use the View to add and remove items from the collection and the UI will update properly:

    Private Sub btnDelete_Click() Handles btnDelete.Click
           If Me.View.CurrentPosition > -1 Then
               'removes the currently selected customer from the underlying collection 
               Me.View.RemoveAt(Me.View.CurrentPosition)
           End If
       End Sub
    
       Private Sub btnAdd_Click() Handles btnAdd.Click
           'adds a new customer to the underlying collection 
           Dim customer = CType(Me.View.AddNew, Customer)
           'do something with customer if needed...
           Me.View.CommitNew()
       End Sub

    Calling these methods on the ListCollectionView will execute the InsertItem and RemoveItem methods on the ObservableCollection.

    Now if you are using an Entity Data Model (EDM) the designer in Visual Studio 2008 SP1 will generate entity classes for you that you can also bind to in your UI. Access to these entities is done through the ObjectContext and the designer also creates a class for you that inherits from this when you create the EDM. It is named something like xxxEntites. (For instance, in Visual Studio 2008 SP1 “Add New Item” and select ADO.NET Entity Data Model and name it Northwind.edmx. Generate from Database and select Northwind. Select all the tables and then the designer will generate an ObjectContext called NorthwindEntities and entity classes based on the tables in the database.)

    Because the ObjectContext is what tracks changes on entities you can place entities inside an ObservableCollection but in order for the ObjectContext to be notified that adds and deletes need to be tracked you need to write a bit of code. The easiest thing to do is to create your own class that inherits from ObservableCollection and override the InsertItem and RemoveItem methods so that you can tell the ObjectContext to either add or delete the entity which will ultimately execute against the database. In the constructor pass a reference to the ObjectContext. You can also pass in any collection of entities, say from a LINQ query, and then add them to the ObservableCollection. For example:

    Imports NorthwindDAL
    Imports System.Collections.ObjectModel
    
    Public Class CustomerCollection
        Inherits ObservableCollection(Of Customer)
    
        Private _context As NorthwindEntities
        Public ReadOnly Property Context() As NorthwindEntities
            Get
                Return _context
            End Get
        End Property
    
        Sub New(ByVal customers As IEnumerable(Of Customer), ByVal context As NorthwindEntities)
            MyBase.New(customers)
    _context = context End Sub Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As Customer) Me.Context.AddToCustomers(item) MyBase.InsertItem(index, item) End Sub Protected Overrides Sub RemoveItem(ByVal index As Integer) Me.Context.DeleteObject(Me(index)) MyBase.RemoveItem(index) End Sub End Class

    Then you can use the collection on your WPF form instead like so:

    Imports NorthwindDAL
    
    Class Window1
        Private db As New NorthwindEntities
        Private CustomerData As CustomerCollection
        Private View As ListCollectionView
    
        Private Sub Window1_Loaded() Handles MyBase.Loaded
    
            Dim results = From c In db.Customers _
                          Where c.City.ToLower = "seattle" _
                          Order By c.LastName, c.FirstName _
                          Select c
    
            Me.CustomerData = New CustomerCollection(results, db)
            Dim customerSource = CType(Me.Resources("CustomerSource"), CollectionViewSource)
            customerSource.Source = Me.CustomerData
            Me.View = CType(customerSource.View, ListCollectionView)
        End Sub
        Private Sub btnSave_Click() Handles btnSave.Click
            Try
                db.SaveChanges()
                MsgBox("Customer data was saved.")
            Catch ex As Exception
                MsgBox(ex.ToString())
            End Try
        End Sub
        Private Sub btnDelete_Click() Handles btnDelete.Click
            If Me.View.CurrentPosition > -1 Then
                Me.View.RemoveAt(Me.View.CurrentPosition)
            End If
        End Sub
    
        Private Sub btnAdd_Click() Handles btnAdd.Click
            Dim customer = CType(Me.View.AddNew, Customer)
            'do something with customer if needed...
            Me.View.CommitNew()
        End Sub
    End Class

    Now any updates, adds or deletes you make in the UI will be propagated to the database through the Entity Framework. 

    Enjoy!

  • Beth Massi - Sharing the goodness

    CodeCast Episode 20 with Yours Truly!

    • 1 Comments

    In the latest episode of CodeCast, Ken interviews me about my role on the Visual Studio Community Team. Ken caught me a couple weeks ago when I was in Redmond and we had a chat in the lobby of building 41. Ken and I are good friends and go way back so it was a fun interview. We chat about Open XML, OBA, and I plug one of my favorite features of VS2010.

    I come on about 25 minutes into the show. And you know how sometimes you can’t stand hearing your own voice? Well I thought I sounded pretty good! – Ken always has cool gadgets so the recording device he had must have been top-o-the-line. ;-)

    CodeCast Episode 20: Biz Apps Team and VB with Beth Massi

    Links from the show:

    Enjoy!

  • Beth Massi - Sharing the goodness

    Notifying the UI when Entity References Change in Lookup Comboboxes

    • 10 Comments

    Last week I wrote about how to data bind WPF lookup comboboxes to entities returned from the Entity Framework. I described that the key to this type of binding is setting the SelectedItem to the object reference itself on the navigation property instead of setting SelectedValue and SelectedValuePath as in the case when you have foreign key scalar properties like LINQ to SQL classes or DataTables.

    However, depending on your UI, you may need a notification to fire when the entity reference changes. By default this doesn’t happen with entities generated by the EF designer. Only scalar properties raise change notifications. For instance, going back to our Customer (1)—(*) Order example, the Order entity has a reference to its Customer parent as specified by the navigation property:

    In the database there is a foreign key relationship on CustomerID and that is inferred here by EF. If you look at the Order class that is generated you will see only change notifications raised on the scalar properties, not the navigation properties. For instance, if we take a look at a scalar property that is generated you will see the change notification partial methods generated as well:

    Partial Public Class Order
        Inherits Global.System.Data.Objects.DataClasses.EntityObject
    .
    .
    . Public Property OrderID() As Integer Get Return Me._OrderID End Get Set Me.OnOrderIDChanging(value) Me.ReportPropertyChanging("OrderID") Me._OrderID = StructuralObject.SetValidValue(value) Me.ReportPropertyChanged("OrderID") Me.OnOrderIDChanged End Set End Property Private _OrderID As Integer
    Partial Private Sub
    OnOrderIDChanging(ByVal value As Integer) End Sub
    Partial Private Sub
    OnOrderIDChanged() End Sub
    .
    .
    .

    EF entities that are generated by the designer inherit from EntityObject that in turn inherits from StructuralObject that implements  INotifyPropertyChanged. This interface is necessary for notifying the UI (WPF and Winforms) that data bound controls should refresh their value. So say you programmatically change a scalar property then any controls bound to that property will be refreshed with the new value automatically. Or in many cases you have a UI with multiple controls bound to the same property. If the user makes a change to one control, the rest update automatically.

    However this notification isn’t generated on entity references. Which means that if you have a lookup combobox set up like I described in last week’s post and also have another control bound to the same Customer navigation property, then it won’t refresh properly.

    For instance, say we have an Order form with a combobox set up like before, where the SelectedItem is bound to the Customer property (SelectedItem="{Binding Path=Customer}"), but we also have a listbox that shows OrderDate, Customer.LastName, Customer.FirstName:

    image

    <ListBox Grid.Row="1" Name="ListBox1" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Width="60" Text="{Binding Path=OrderDate, StringFormat='d'}" />
                <TextBlock Text="{Binding Path=Customer.LastName}" />
                <TextBlock Width="5">, </TextBlock>
                <TextBlock Text="{Binding Path=Customer.FirstName}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>

    If the user changes the OrderDate then that change will automatically be reflected in the listbox. But if the user changes the Customer in the dropdown combobox then it will NOT update the listbox because a change notification is not raised on Customer. What’s also interesting is if you look at that part of the generated Order entity then you will actually see two properties, one we expect called Customer and one called CustomerReference:

    .
    .
    .
    Public Property
    Customer() As Customer Get Return CType(Me, IEntityWithRelationships).RelationshipManager. _ GetRelatedReference(Of Customer)("OMSModel.FK_Orders_Customer", "Customer").Value End Get Set(ByVal value As Customer) CType(Me, IEntityWithRelationships).RelationshipManager. _ GetRelatedReference(Of Customer)("OMSModel.FK_Orders_Customer", "Customer").Value = value End Set End Property
    .
    .
    . Public Property
    CustomerReference() As EntityReference(Of Customer) Get Return CType(Me, IEntityWithRelationships).RelationshipManager. _ GetRelatedReference(Of Customer)("OMSModel.FK_Orders_Customer", "Customer") End Get Set(ByVal value As EntityReference(Of Customer)) If (Not (value) Is Nothing) Then CType(Me, IEntityWithRelationships).RelationshipManager. _ InitializeRelatedReference(Of Customer)("OMSModel.FK_Orders_Customer", "Customer", value) End If End Set End Property

    The Customer property is a navigation property to the parent Customer entity itself as we expect. The CustomerReference is an EntityReference class. This class describes the relationship between the Order and Customer. It also defines an event called AssociationChanged that you can handle to notify the UI properly when the reference changes. When you change the reference this event will fire twice, first to remove the old reference and then again to add the new one. You can easily extend the Order partial class by creating another Partial Class declaration for Order in the same namespace (which is automatically imported in VB) and then calling the appropriate property change notifications:

    Imports System.ComponentModel
    
    Partial Public Class Order
        Sub New()
            MyBase.New()
            AddHandler Me.CustomerReference.AssociationChanged, AddressOf Customer_AssociationChanged
        End Sub
    
        Private Sub Customer_AssociationChanged(ByVal sender As Object, _
                                                ByVal e As CollectionChangeEventArgs)
            If e.Action = CollectionChangeAction.Remove Then
                OnPropertyChanging("Customer")
            Else
                OnPropertyChanged("Customer")
            End If
        End Sub
    End Class

    So now we can change the Customer in the dropdown and the UI will be notified properly. Sweet. For more information on Entity Framework and data binding see this topic in the MSDN library.

    Enjoy!

Page 1 of 2 (11 items) 12