Setting Up a Data Source Before you can bind to data in the window, you’ll need a data source to work with data.. This book shows you how to use LINQ to SQL, which is connected by select
Trang 1Notice that the class in this code is named NewOrder, illustrating that a window is just
another class As you know, you can instantiate classes and call their methods, which is
the technique you’ll use to open this window from the NewOrder_Click event handler in the code-behind of the MainWindow window.
In practice, you’ll populate the NewOrder window with whatever controls you need
to implement a new order You would populate the window by dragging and dropping
controls, just like the Button in this example However, we’ll skip that task for now because the current focus is on adding code to the NewOrderButton_Click event handler
so that you can learn how to code an event handler and open another window Go back to
the NewOrderButton_Click event handler in MainWindow.xaml.cs and add the following
code:
C#:
private void NewOrderButton_Click(object sender, RoutedEventArgs e) {
NewOrder newOrd = new NewOrder();
newOrd.Show();
}
VB:
Private Sub NewOrderButton_Click(
ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs)
Handles NewOrderButton.Click
Dim newOrd As New NewOrder
newOrd.Show()
End Sub
Since NewOrder is a class, you can instantiate it as shown in the preceding code example To open the window, call the Show method.
Now you have a WPF program that handles events and opens new windows Press F5
to run the program Click New Order and observe that the New Order window appears The New Order window isn’t very useful because it lacks controls and data management The next section shows you how to populate window controls with data
Working with Data in WPF
This section builds upon what you learned in Chapter 7 by showing how to bind data
to WPF controls Binding is the process of populating and retrieving data to and from
controls You’ll learn how to show data in your user interface The examples in the
Trang 2Chapter 8: Building Desktop Applications with WPF 235
following sections show you how to perform create, read, update, and delete (CRUD)
operations via WPF You’ll first see how to insert data, using VS tools to construct a data
entry screen Then you’ll learn how to read, modify, and delete data through a DataGrid
We’ll start with single value binding To make the examples more interesting, I added
extra fields to the tables You can review Chapter 7 to learn how to add fields to a database and create a LINQ to SQL entity model
Setting Up a Data Source
Before you can bind to data in the window, you’ll need a data source to work with data To get started, update the Order table, created in Chapter 7, so that it has the following fields:
● OrderID, int, primary key, auto-increment
● CustomerID, int
● OrderDate, datetime
● Location, varchar(50)
● Amount, money
Then update the Customer table with the following fields:
● CustomerID, int, primary key, auto-increment
● Name, nvarchar(50)
● Age, int
● Birthday, datetime
● Income, money
With the database updated, you can add a LINQ to SQL entity model to the project,
using the same techniques described in Chapter 7
To add the data source for binding, open the NewOrder window in the Designer, and
select the Data | Add New Data Source menu, which opens the Choose A Data Source
Type window, shown in Figure 8-11
There are different ways to connect to a data source, including directly to the database, via a Web service, via an object, or through SharePoint This book shows you how to use
LINQ to SQL, which is connected by selecting Object and clicking Next, which shows the Select The Data Objects window in Figure 8-12
Trang 3Figure 8-11 Choosing a new data source
On the Select The Data Objects window, check the box next to each object you want
to bind in your application The example in this chapter uses Customer and Order objects,
which you can see checked in Figure 8-12 Clicking Finish will configure the data source for use in the application You can view data sources by selecting Data | Show Data Sources, shown in Figure 8-13
The Data Sources window allows you to create controls on a form that are bound
to each field of a data source In the Data Sources window in Figure 8-13, you can see
that both Customer and Object are listed with their fields What is also evident is the
icons associated with each field The icons describe what type of control should be
associated with each data field For example, Name on Customer is a TextBox because it is nvarchar(50), but Birthday is a calendar because it is a datetime If you don’t like a default
control type for a field, you can change it by selecting the field and choosing another control type from the drop-down list, as shown in Figure 8-14
Trang 4Chapter 8: Building Desktop Applications with WPF 237
Figure 8-12 Selecting data objects
Figure 8-13 The Data Sources window
Trang 5In Figure 8-14, the CustomerID is being changed to a ComboBox because it makes
more sense to give the user the option of selecting a customer from a list for a new order, rather than typing in an ID number Also, the object defaults to a Grid control, but in this first example, we only want to add a new order, meaning that the control type should be changed to Detail To create a new order form with controls bound to order data, select the
Order object in the Data Sources window and drag and drop the order onto the Designer
of the NewOrder window Figure 8-15 shows this new window
Figure 8-15 shows how VS added a Grid layout with two columns and a row for each
field in the Order table As explained, the CustomerID is a ComboBox and the OrderDate
is a calendar VS was smart enough to put spaces between the words in the labels, too
VS didn’t put the Save button on the screen, which is something you would need to do
to save the data In addition to adding controls to the Designer, VS added the following
CollectionViewSource control to the NewOrder window’s XAML:
<Window.Resources>
<CollectionViewSource x:Key="orderViewSource"
d:DesignSource="{d:DesignInstance my:Order, CreateList=True}" />
</Window.Resources>
Figure 8-14 Changing the control type for a field
Trang 6Chapter 8: Building Desktop Applications with WPF 239
This is another reason it’s important to be able to read the XAML for a window, so
you can see how objects like this are added and configure them if you need to In our
case, we need to know the name of the CollectionViewSource, which is orderViewSource
We need to add an Order object to the CollectionViewSource so that the controls that are
bound to it have a place to save data that the user enters Press F7 to see the code that VS
added to the Window Loaded event handler, as follows:
C#:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
System.Windows.Data.CollectionViewSource
orderViewSource =
((System.Windows.Data.CollectionViewSource)
(this.FindResource("orderViewSource")));
// Load data by setting the
//CollectionViewSource.Source property:
// orderViewSource.Source = [generic data source]
}
Figure 8-15 Controls bound via a data source
Trang 7Private Sub Window_Loaded(
ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded Dim OrderViewSource As System.Windows.Data.CollectionViewSource = CType(Me.FindResource("OrderViewSource"),
System.Windows.Data.CollectionViewSource)
'Load data by setting the CollectionViewSource.Source property: 'OrderViewSource.Source = [generic data source]
End Sub
The preceding skeleton code gets a reference to OrderViewSource, but that’s all The
commented portion of the code suggests how you might populate that control However,
we aren’t interested in populating OrderViewSource with data because the purpose of
this screen is to insert a new record Instead, the proper approach is to bind an empty object Later, you’ll see how to pull the data from that object after the user fills in the
form and clicks on the Save button In addition to assigning a blank Order object to
OrderViewSource, we need to populate the ComboBox that holds the list of customers
and their IDs The following code is a revision to the Window_Loaded event handler that assigns a blank Order object to the OrderViewSource and binds customers to the
ComboBox holding customers:
C#:
private void Window_Loaded(object sender, RoutedEventArgs e)
{
var orderViewSource =
FindResource("orderViewSource") as CollectionViewSource; orderViewSource.Source =
new List<Order>
{
new Order
{
OrderDate = DateTime.Now
}
};
customerIDComboBox.ItemsSource =
from cust in new MyShopDataContext().Customers
select cust;
}
Trang 8Chapter 8: Building Desktop Applications with WPF 241
VB:
Private Sub Window_Loaded(
ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Dim OrderViewSource As CollectionViewSource =
CType(FindResource("OrderViewSource"), CollectionViewSource)
OrderViewSource.Source =
New List(Of Order) From
{
New Order With
{
OrderDate = DateTime.Now
}
}
CustomerIDComboBox.ItemsSource =
From cust In New MyShopDataContext().Customers
End Sub
The previous re-write of Window_Loaded accomplishes two things: assigning an order
to orderViewSource and populating customerIDComboBox with customers The Order
object assigned to the Source property of orderViewSource is empty, except assigning
today’s date to OrderDate, demonstrating how you can set default values When the user
fills out the form on the page, WPF will populate this Order with data because it is data
bound, through orderViewSource, to the controls on the screen This section showed you
how the data is assigned to the controls, but some controls require even more attention to
ensure they display the data correctly The next section expands upon what you must do to get the ComboBox to work
Configuring a ComboBox
A couple of the particularly more complex controls to configure are ComboBox and
ListBox The reason is that they have a few different properties that must be set to ensure
that whatever is selected can be read and correctly referenced back to the original data
source This section doesn’t try to teach you about WPF binding because there are entire
books with multiple chapters related to the subject Instead, you’ll learn an essential skill
for helping you figure out how to set the right properties on a ComboBox control In so
doing, you’ll get a better feel for the features of VS that help you perform the task of
setting up controls
Trang 9The previous example assigns the results of a LINQ query for Customer objects to the customerIDComboBox, but this is only the first step to getting the combo box to work properly; you must specify which property of Customer must display, which property of
Customer maps to Order, and which property of Order to bind the selected item to To do
this binding, open the NewOrder.xaml file in the Designer, select the combo box, and set the properties as specified in Table 8-2
The following XAML shows the results of the settings you should make in the Properties window, based on Table 8-2:
<ComboBox DisplayMemberPath="Name"
SelectedValue="{Binding Path=CustomerID}"
SelectedValuePath="CustomerID"
Grid.Column="1" Grid.Row="1"
Height="23" HorizontalAlignment="Left"
Margin="3" Name="customerIDComboBox"
VerticalAlignment="Center" Width="120">
</ComboBox>
DisplayMemberPath and SelectedValuePath are names of the properties from the
Customer objects bound to the ComboBox However, the SelectedValue syntax uses a binding expression, where Path identifies the property of the Order that will be assigned
to with SelectedValuePath The binding for SelectedValue is based on the Order object
Table 8-2 ComboBox Properties for Data Binding
Property Explanation
ItemsSource We set this through code in the Window_Loaded event It holds the collection
of objects that will appear in the combo box You need two properties, one to display and one for the key of the object being displayed The key will be used
to map the object back to the database or associate the object in a relationship
with another object In the case of the Customer list, the properties of interest are Name for display and CustomerID for key Since we are creating a new Order, the CustomerID for the Name selected in the combo box will be assigned to the CustomerID field of the Order That way, when the Order is saved, its database record will have the CustomerID for the customer the user selected.
DisplayMemberPath This is the Name property from each Customer object bound to the combo box.
SelectedValuePath As explained for ItemsSource, you need to associate the selected Customer with
the Order being created SelectedValuePath is the name of the Customer object’s key, which is CustomerID in our example.
SelectedValue When saving the Order, you must have the key associated with the selected
customer The SelectedValue is a binding to the property of the Order that will
be set with the key from the selected Customer.
Trang 10Chapter 8: Building Desktop Applications with WPF 243
that was assigned to the Source property of the orderViewSource in Window_Loaded
Coming full circle, the orderViewSource is what the default binding of the containing
Grid layout is based on; it was set when dragging and dropping the Order data source
onto the Design surface
Now you have an input form that displays data, allowing the user to enter new
order information After the user fills in the form, you need to save the data, which is
discussed next
Reading and Saving Data
Next, you’ll want to save the order when a user clicks Save To do this, add a Button
control to the form, set its Content property to Save, and set its Name property to
SaveButton, which you learned how to do earlier in this chapter Then double-click Save
to create a Click event handler like this:
C#:
private void SaveButton_Click(object sender, RoutedEventArgs e)
{
CollectionViewSource orderViewSource =
FindResource("orderViewSource") as CollectionViewSource;
List<Order> ordList =
orderViewSource.Source as List<Order>;
Order ord = ordList.FirstOrDefault();
var ctx = new MyShopDataContext();
ctx.Orders.InsertOnSubmit(ord);
ctx.SubmitChanges();
MessageBox.Show("Order Saved!");
}
VB:
Private Sub SaveButton_Click(
ByVal sender As System.Object,
ByVal e As System.Windows.RoutedEventArgs)
Handles SaveButton.Click
Dim OrderViewSource As CollectionViewSource =
CType(FindResource("OrderViewSource"), CollectionViewSource)