Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

AdventureWorks.WPF (Part 1)

0.00/5 (No votes)
4 Apr 2008 2  
My quest to create a real world line-of-business application

Background

Is WPF ready for the real world? And the answer is hell yes! So, prove it!

These next few articles are my documentation of trying to write a real world line-of-business application using WPF! What is important to notice is that I only use the goodness provided by WPF and nothing else!!! Part 1 will lay the foundation for the future articles.

Why Write This Article, Isn't It Covered Already?

Probably, but what better way to learn than to play? On a more serious note, the only real reference application out there that I have seen is the DinnerNow application. DinnerNow is a perfect example of using all that .NET 3.0 has to offer, but it is a little over complicated. The purpose of these articles is to address some of the basics that can potentially be used to create a similar application like DinnerNow!!!

Disclaimer

This is a beginner article, but it assumes some knowledge of WPF, SQL Server, MVC and LINQ.

WPF Introduction

Advanced WPF

MVC

LINQ/SQL Server

WPF Bootcamp

Most LOB applications consume and manipulate data... So, let's start there!

Before We Begin...

OK, so this is obvious but create a new WPF application project using Visual Studio 2008!

Data

It is safe to assume that Microsoft SQL Server is a popular source of data. Download the AdventureworksLT SQL database and install it.

Creating a LINQ-to-SQL Mapping

Add a new item to the project using "LINQ to SQL Classes" template.

Open server explorer and add a data connection. Type in your server name and select AdventureWorksLT as the database.

Once added, select all the tables and drag them on to the design surface. This will create all the needed entities (our model).

Model-View-Controller?

I am loosely following Josh's implementation of the MVC pattern, mine will more likely resemble Dr. WPF's MV-poo though.

Model

The domain-specific representation of the information on which the application operates.

Disclaimer

I am not a Software Architect and this article is not a design guide on how to architect an nTier or MVC application.

Although this is my quest to create a real world LOB application... for now, I am going to cheat a little. I am going to use my data sets returned by LINQ as my Model. What is nice about this approach is that it already implements the INotifyPropertyChanged event! Before all the REAL architects start flaming me, future articles will address this.

Not to give away too much, but the future plan is to have an SQL DB -> LINQ-to-SQL -> WCF Service -> Model.

The main purpose of the Model is to represent the data in an easy to bind format!

About the Code

If you run the sample code provided, remember to change the connection string in the settings file. It currently uses this connection string:

Data Source=
    localhost\sqlexpress;Initial Catalog=AdventureWorksLT;Integrated Security=True

View

Renders the model into a form suitable for interaction. This is where WPF really shines... I am creating various User Controls and binding them to the content of my window!

Communication between the view and model is via data binding and routed commands (via the controller).

Each view will be loaded into a new Window. I will use these attached properties to keep track of my open windows.

local:WindowViewState.IsManaged="True"

Sales Orders

SalesOrderView

Ok, so I don't have a Grant Hinkson in my back pocket... It's not beautiful but it is functional!!!

The purpose of this view is to allow a user to view/edit any existing sales order. Data like order date, due date, ship date, ship method, etc. can be changed. To change the customer details, a separate view will be used. Each customer has a list of addresses associated with it, the ship to and bill to addresses can only be changed to a valid address already in the list.

The following commands will also be supported: New, Delete and Update (to be implemented in future articles).

The sales order view is data bound to the SalesOrderHeaders collection.

Customers

CustomersView

This view is used to view/edit customers. Details like first name, middle name, last name, etc. can be changed.

The customers view is data bound to the Customers collection.

Products

ProductsView

This view is used to view/edit products. Details like name, part number, list price, etc. can be changed.

The products view is data bound to the Products collection.

Controller (AKA Poo)

Processes responds to events, typically user actions, and may invoke changes on the model. The controller is basically the glue to hold together the model and the view.

The controller is used to interact with the model (i.e. add new sales order, delete a sales order, update a sales order).

I have created some routed commands for each action the view can perform. For more information on routed commands, read this article published by Josh Smith.

Binding Issue 1 of n

This article mainly focuses on data binding. Before we dig in, please read this article about what I have learned about binding... It will be used extensively in these articles!!!

Binding to a Normalized Database

Let's take the AdventureWorksLT as a example. Each customer has a list of addresses associated with it. Each sales order has a customer. If I now want to create a data entry screen for a sales order, how do I bind it correctly so that I can change the delivery/billing address but still have my options constrained to the available addresses?

<ComboBox ItemsSource="
    {Binding Path=Customer.CustomerAddresses, Mode=TwoWay, UpdateSourceTrigger=Explicit}"
     SelectedValue="{Binding Path=ShipToAddressID}" SelectedValuePath="AddressID" />

The ComboBox fitted this perfectly, I first bind the ComboBox.ItemsSource to all the available addresses (constrained by Customer). All that is now left to do is tell the ComboBox which item it should currently select. The SelectedValuePath determines which property should be used to "identify" the current item and the SelectedValue is then bound...

Examine this carefully... the ComboBox is bound to Customer.CustomerAddresses but the SelectedValue is actually using the binding source up the visual tree!

This is a very common scenario in a normalized database...

BindingMode.TwoWay

The default binding mode is not always the same for different controls. It is always a safe practice to explicitly set the binding mode. In this scenario, we are going to use BindingMode.TwoWay most of the time. We want the binding to update our model automatically!

Mode=TwoWay

Master/Detail Binding

A common scenario is a master/detail binding... If I can take the sales order example... I bind a ComboBox to a list of open sales orders (Master), once a sales order is selected, its details are showed in the details pane (Detail).

Their are two common ways to do it:

Bind the details pane DataContext to the ComboBox.SelectedItem:

DataContext="{Binding Path=SelectedItem, ElementName=SalesOrdersListBox}"

Or use the {Binding Path=/} syntax.

To use this binding, first set the IsSynchronizedWithCurrentItem="True" and then bind the DataContext as follows:

DataContext="{Binding Path=/}"

UpdateSourceTrigger.Explicit

I want to control when my data source is updated. More about this later...

UpdateSourceTrigger=Explicit

What Does WPF Not Have (Yet)

I am sure time was the only constraint here but there are two controls that WPF needs urgently to enter the LOB market...

DatePicker

Here I used the Marlon's AvalonControlsLibrary.(It is free and the full source code is supplied.)

DataGrid

Currently I am just using a ListView, but I will soon upgrade to an Xceed DataGrid.(It is free.)

Future Issues to be Addressed

  • Controller & routed commands (Providing New, Delete and Update)
  • Validation
  • Moving to a data service model and crossing the machine boundaries

This is all for part 1... If you found this useful, please vote for my article... any comments (good or bad) are very welcome!

Website

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here