簡介
社區(qū)中大多數(shù)有爭議的 WPF 示例都與圖形引擎的問題有關(guān)。對于大多數(shù)用戶界面開發(fā)人員而言,他們的大部分工作是在企業(yè)開發(fā)領(lǐng)域開發(fā)日常數(shù)據(jù)項窗體。WPF 是否有解決其問題的方法?當然有……
綁定到數(shù)據(jù)庫數(shù)據(jù)
在本系列的第一部分中,我們探究了原始綁定語法以及如何將簡單對象綁定到 XAML 對象。雖然這是該難題的一個重要部分,但大多數(shù)情況下,實際的要求是綁定到數(shù)據(jù)庫中存儲的數(shù)據(jù)。在大多數(shù)情況下,它支持兩種不同方案中的綁定:數(shù)據(jù)庫數(shù)據(jù)(例如,DataSet、DataTable 和 DataRow)和自定義業(yè)務(wù)對象。
綁定到數(shù)據(jù)庫數(shù)據(jù)
目前,數(shù)據(jù)庫仍然是進行大多數(shù)開發(fā)工作的中心,特別是企業(yè)開發(fā)。為了舉例說明,我們可以使用一個簡單的 WPF 對話框示例,它將允許用戶瀏覽數(shù)據(jù)庫中的雇員。我們希望能夠在瀏覽器中顯示一小部分信息,包括雇員照片。還需要加載一個包含所需全部信息的表。通過新建一個包含數(shù)據(jù)庫信息的 DataTable,我們可以實現(xiàn)該操作:
在 C# 中:
DataTable theTable = new DataTable();
string connString =
ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
string query = @"SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo
FROM Employees";
// Fill the Set with the data
using (SqlConnection conn = new SqlConnection(connString))
{
SqlDataAdapter da = new SqlDataAdapter(query, conn);
da.Fill(theTable);
}
在 Visual Basic .NET 中:
Dim theTable As DataTable = New DataTable()
String connString =
ConfigurationManager.ConnectionStrings("Northwind").ConnectionString
String query = "SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo " + _
" FROM Employees"
‘ Fill the Set with the data
Using conn as New SqlConnection(connString))
Dim da As SqlDataAdapter = New SqlDataAdapter(query,conn)
da.Fill(theTable)
End Using
我們擁有數(shù)據(jù)之后,可以使用這些數(shù)據(jù)設(shè)置 DataContext 以允許在 XAML 中對其進行綁定:
在 C# 中:
// Set the Data Context
DataContext = theTable;
在 Visual Basic .NET 中:
‘ Set the Data Context
DataContext = theTable
既然我們要獲得數(shù)據(jù)并將其輸出到窗口,我們就可以在 XAML 中進行數(shù)據(jù)綁定。ComboBox 中的 Binding 僅指示綁定從父級的 DataContext(在本例中,它沿控件樹向上,直至在 Window 中找到一個 DataContext)獲得數(shù)據(jù):
<ComboBox Name="theCombo"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
... />
IsSynchronizedWithCurrentItem 屬性很重要,因為當選擇發(fā)生變化時,就窗口而言,是該屬性更改"當前項"。它告訴 WPF 引擎將使用該對象更改當前項。如果沒有該屬性,DataContext 中的當前項不會改變;因此,您的文本框?qū)⒓俣ó斍绊椚匀皇橇斜碇械牡谝豁棥?/p>
要在組合框中顯示雇員姓名,我們在 ItemsTemplate 中創(chuàng)建綁定以顯示 DataTable 中的 FirstName 和 LastName:
<DataTemplate x:Key="EmployeeListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=FirstName}" />
<TextBlock Text=" " />
<TextBlock Text="{Binding Path=LastName}" />
</StackPanel>
</DataTemplate>
接下來,我們添加文本框以顯示我們的姓名、頭銜和雇傭日期:
<TextBlock Canvas.Top="5">First Name:</TextBlock>
<TextBox Canvas.Top="5" Text="{Binding Path=FirstName}" />
<TextBlock Canvas.Top="25">Last Name:</TextBlock>
<TextBox Canvas.Top="25" Text="{Binding Path=LastName}" />
<TextBlock Canvas.Top="45">Title:</TextBlock>
<TextBox Canvas.Top="45" Text="{Binding Path=Title}" />
<TextBlock Canvas.Top="65">Hire Date:</TextBlock>
<TextBox Canvas.Top="65" Text="{Binding Path=HireDate}" />
由于我們也需要照片,因此需要向 XAML 添加一個圖像:
<Image Name="theImage" Canvas.Top="5" Canvas.Left="5" Width="75"/>
圖像唯一的問題在于,它不支持將照片數(shù)據(jù)自動綁定到圖像。為了便于該操作,我們可以處理 ComboBox 的 SelectionChanged 事件以填充我們的 Image:
<ComboBox Name="theCombo"
IsSynchronizedWithCurrentItem="True"
Width="200"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource EmployeeListTemplate}"
SelectionChanged="theCombo_OnSelectionChanged" />
在代碼中,我們需要從 DataTable 加載圖像,然后創(chuàng)建一個 BitmapImage 對象來填寫 Image 標記。請注意,這不是 GDI+ (System.Drawing) 中的 Bitmap,而是 WPF 中新增的 Bitmap 對象:
// Handler to show the image
void theCombo_OnSelectionChanged(object sender, RoutedEventArgs e)
{
ShowPhoto();
}
// Shows the Photo for the currently selected item
void ShowPhoto()
{
object selected = theCombo.SelectedItem;
DataRow row = ((DataRowView)selected).Row;
// Get the raw bytes of the image
byte[] photoSource = (byte[])row["Photo"];
// Create the bitmap object
// NOTE: This is *not* a GDI+ Bitmap object
BitmapImage bitmap = new BitmapImage();
MemoryStream strm = new MemoryStream();
// Well-known work-around to make Northwind images work
int offset = 78;
strm.Write(photoSource, offset, photoSource.Length - offset);
// Read the image into the bitmap object
bitmap.BeginInit();
bitmap.StreamSource = strm;
bitmap.EndInit();
// Set the Image with the Bitmap
theImage.Source = bitmap;
}
在 Visual Basic .NET 中:
‘ Handler to show the image
Sub theCombo_OnSelectionChanged(ByVal sender As Object, ByVal e As RoutedEventArgs)
ShowPhoto();
End Sub
// Shows the Photo for the currently selected item
Sub ShowPhoto()
Dim selected As Object = theCombo.SelectedItem
Dim row As DataRow = (CType(selected, DataRowView)).Row
‘ Get the raw bytes of the image
Dim photoSource() As Byte = CType(row("Photo"), Byte())
‘ Create the bitmap object
‘ NOTE: This is *not* a GDI+ Bitmap object
Dim bitmap As BitmapImage = New BitmapImage()
Dim strm As MemoryStream = New MemoryStream()
‘ Well-known work-around to make Northwind images work
Dim offset As Integer = 78
strm.Write(photoSource, offset, photoSource.Length - offset)
‘ Read the image into the bitmap object
bitmap.BeginInit()
bitmap.StreamSource = strm
bitmap.EndInit()
‘ Set the Image with the Bitmap
theImage.Source = bitmap
End Sub
我們從 ComboBox 中抽取 SelectedItem 并將其轉(zhuǎn)換成 DataRow,這樣我們就可以獲得自己的數(shù)據(jù)。然后,我們從 Photo 列抽取字節(jié)數(shù)組。這是存儲在 Northwind 數(shù)據(jù)庫中的照片。我們可以使用內(nèi)存中流將照片字節(jié)流入到 BitmapImage 對象中。唯一的改動是常用的替代方案,即跳過 Northwind 圖像頭的前 78 個字節(jié),因為不再使用這些字節(jié)。一旦我們將流讀入位圖中,就可以將其作為源分配給 Image 對象。
我們希望確保數(shù)據(jù)綁定是雙向的,因此需要生成一個顯示當前信息的按鈕,這樣我們就可以知道它在我們的 DataRow 中:
在 C# 中:
void SaveButton_OnClick(object sender, RoutedEventArgs e)
{
object selected = theCombo.SelectedItem;
DataRow row = ((DataRowView)selected).Row;
MessageBox.Show(string.Format("{0} {1} {2} - {3:d}",
row["Title"], row["FirstName"], row["LastName"], row["HireDate"]));
}
在 Visual Basic .NET 中:
Sub SaveButton_OnClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
Dim selected As Object = theCombo.SelectedItem
Dim row As DataRow = (CType(selected, DataRowView)).Row
MessageBox.Show(String.Format("{0} {1} {2} - {3:d}", _
row("Title"), row("FirstName"), row("LastName"), row("HireDate")))
End Sub
完整的 XAML 文件其結(jié)尾部分如下所示:
<Window x:Class="ExampleCS.EmployeeBrowser"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
Title="Employee Browser"
Loaded="OnLoaded"
Width="300"
Height="170"
WindowStartupLocation="CenterScreen"
>
<Window.Resources>
<DataTemplate x:Key="EmployeeListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="<b>{Binding Path=FirstName}</b>" />
<TextBlock Text=" " />
<TextBlock Text="<b>{Binding Path=LastName}</b>" />
</StackPanel>
</DataTemplate>
</Window.Resources>
<Window.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
<LinearGradientBrush.GradientStops>
<GradientStop Color="DarkGray" Offset="0" />
<GradientStop Color="White" Offset=".75" />
<GradientStop Color="DarkGray" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Window.Background>
<StackPanel Name="theStackPanel"
VerticalAlignment="Top">
<ComboBox Name="theCombo"
IsSynchronizedWithCurrentItem="True"
Width="200"
ItemsSource="<b>{Binding}</b>"
ItemTemplate="{StaticResource EmployeeListTemplate}"
SelectionChanged="<b>theCombo_OnSelectionChanged</b>" />
<Canvas>
<Canvas.Resources>
<Style TargetType="{x:Type TextBox}">
<Setter Property="Canvas.Left" Value="160" />
<Setter Property="Padding" Value="0" />
<Setter Property="Height" Value="18" />
<Setter Property="Width" Value="120" />
</Style>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Canvas.Left" Value="90" />
<Setter Property="Padding" Value="0" />
<Setter Property="Height" Value="18" />
<Setter Property="FontWeight" Value="Bold" />
</Style>
</Canvas.Resources>
<Image Name="theImage" Canvas.Top="5" Canvas.Left="5" Width="75"/>
<TextBlock Canvas.Top="5">First Name:</TextBlock>
<TextBox Canvas.Top="5" Text="<b>{Binding Path=FirstName}</b>" />
<TextBlock Canvas.Top="25">Last Name:</TextBlock>
<TextBox Canvas.Top="25" Text="<b>{Binding Path=LastName}</b>" />
<TextBlock Canvas.Top="45">Title:</TextBlock>
<TextBox Canvas.Top="45" Text="<b>{Binding Path=Title}</b>" />
<TextBlock Canvas.Top="65">Hire Date:</TextBlock>
<TextBox Canvas.Top="65" Text="<b>{Binding Path=HireDate}</b>" />
<Button Canvas.Top="85" Canvas.Left="90" Width="190"
Name="SaveButton" Click="SaveButton_OnClick">Save</Button>
</Canvas>
</StackPanel>
</Window>
現(xiàn)在,如果我們運行瀏覽器,將獲得如圖 1 所示的界面:
圖 1. 雇員瀏覽器
這個簡單的示例相當簡單易懂,但如果我們在 DataSet 中使用相關(guān)的 DataTable,該怎么辦呢?我們看看是否一樣簡單。
綁定相關(guān)的 DataTable
我們可以擴展雇員瀏覽器以包括業(yè)務(wù)員的定單。為此,我們需要獲得定單信息。我們可以在每次切換用戶時利用一個新查詢來實現(xiàn)該操作,不過,我們還是將數(shù)據(jù)隨 Employee 一起加載到 DataSet 中,并使用 DataRelation 使這兩部分信息相關(guān):
在 C# 中:
DataSet theSet = new DataSet();
string connString = ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
string employeeQuery = @"
SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo
FROM Employees
";
string orderQuery = @"
SELECT o.OrderID, EmployeeID, CompanyName, OrderDate, SUM((UnitPrice * Quantity)* (1-Discount)) as OrderTotal
FROM Orders o
JOIN [Order Details] od on o.OrderID = od.OrderID
JOIN Customers c on c.CustomerID = o.CustomerID
GROUP BY o.OrderID, o.EmployeeID, o.OrderDate, CompanyName";
// Fill the Set with the data
using (SqlConnection conn = new SqlConnection(connString))
{
SqlDataAdapter da = new SqlDataAdapter(employeeQuery, conn);
da.Fill(theSet, "Employees");
da.SelectCommand.CommandText = orderQuery;
da.Fill(theSet, "Orders");
}
// Create the relationship
DataTable empTable = theSet.Tables["Employees"];
DataTable ordTable = theSet.Tables["Orders"];
theSet.Relations.Add("Emp2Ord",
empTable.Columns["EmployeeID"],
ordTable.Columns["EmployeeID"],
false);
// Set the Context of the Window to be the
// DataTable we‘ve created
DataContext = empTable;
在 Visual Basic .NET 中:
Dim theSet As DataSet = New DataSet()
Dim connString As String = _
ConfigurationManager.ConnectionStrings("Northwind").ConnectionString
String employeeQuery = _
"SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo " + _
" FROM Employees"
String orderQuery = _
"SELECT o.OrderID, EmployeeID, CompanyName, OrderDate, " + _
" SUM((UnitPrice * Quantity)* (1-Discount)) as OrderTotal " +
"FROM Orders o " +
"JOIN (Order Details) od on o.OrderID = od.OrderID " +
"JOIN Customers c on c.CustomerID = o.CustomerID " +
"GROUP BY o.OrderID, o.EmployeeID, o.OrderDate, CompanyName"
‘ Fill the Set with the data
Using conn as New SqlConnection(connString)
Dim da As SqlDataAdapter = New SqlDataAdapter(employeeQuery,conn)
da.Fill(theSet, "Employees")
da.SelectCommand.CommandText = orderQuery
da.Fill(theSet, "Orders")
End Using
‘ Create the relationship
Dim empTable As DataTable = theSet.Tables("Employees")
Dim ordTable As DataTable = theSet.Tables("Orders")
theSet.Relations.Add("Emp2Ord",
empTable.Columns("EmployeeID"),
ordTable.Columns("EmployeeID"),
False)
‘ Set the Context of the Window to be the
‘ DataTable we‘ve created
DataContext = empTable
這段代碼將創(chuàng)建一個具有兩個表的 DataSet:Employees 和 Orders。這兩個表通過 Emp2Ord 關(guān)系與 EmployeeID 相關(guān)。我們?nèi)匀豢梢越壎ǖ?Employee DataTable,這樣 XAML 中的原始數(shù)據(jù)綁定即可以正常工作。與 Windows 窗體或 ASP.NET 數(shù)據(jù)綁定非常類似,我們可以綁定到關(guān)系的名稱,從而使我們能夠綁定到一組相關(guān)記錄:
<ListBox Name="OrderList" Width="280" Height="200"
ItemsSource="{Binding Emp2Ord}"
ItemTemplate="{StaticResource OrderListTemplate}" />
該列表框仍然使用與雇員瀏覽器的其余部分相同的 DataContext;它僅通過關(guān)系指定綁定。一旦將列表框綁定到關(guān)系,我們就可以像在雇員組合框中那樣綁定到 ItemTemplate 中的各個字段:
<DataTemplate x:Key="OrderListTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock VerticalAlignment="Top" Width="100"
Text="{Binding Path=CompanyName}" />
<StackPanel>
<TextBlock Text="{Binding Path=OrderID}" />
<TextBlock Text="{Binding Path=OrderDate}" />
<TextBlock Text="{Binding Path=OrderTotal}" />
</StackPanel>
</StackPanel>
</DataTemplate>
通過這個額外的數(shù)據(jù)綁定,我們現(xiàn)在正在顯示一個列表框,僅包括與所選用戶有關(guān)的定單信息:
圖 2. 改進的雇員瀏覽器
這使我們能夠綁定到更復雜的數(shù)據(jù),而不僅僅是簡單的成塊數(shù)據(jù)。在許多組織中,它們使用自定義的 .NET 類型(或業(yè)務(wù)對象)來保存其數(shù)據(jù)和業(yè)務(wù)邏輯。WPF 會像 DataSet 一樣輕松地綁定到這些對象嗎?
綁定到"業(yè)務(wù)對象"
在 .NET 的最初表現(xiàn)形式(包括 Windows 窗體和 ASP.NET)中,DataSet 及其相關(guān)的對象是一等公民。它們簡單地綁定數(shù)據(jù),正常地工作。如果選擇構(gòu)建對象模型或業(yè)務(wù)對象來保存數(shù)據(jù),您只能手動將對象中的數(shù)據(jù)綁定到控件。在 .NET 2.0 中,對象升級為一等公民,從而可以簡化到對象的綁定。在 WPF 中也是一樣。就像將對象作為 WPF 中的 DataSet 綁定一樣簡單。
要用業(yè)務(wù)對象創(chuàng)建喜愛的雇員瀏覽器,我們先創(chuàng)建一個類來保存 Employee。
在 C# 中:
public class Employee
{
// Fields
int _employeeID;
string _firstName;
string _lastName;
string _title;
DateTime _hireDate;
BitmapImage _photo;
// Constructor
public Employee(IDataRecord record)
{
_employeeID = (int) record["EmployeeID"];
_firstName = (string) record["FirstName"];
_lastName = (string)record["LastName"];
_title = (string)record["Title"];
_hireDate = (DateTime)record["HireDate"];
CreatePhoto((byte[])record["Photo"]);
}
// BitmapImage creation
void CreatePhoto(byte[] photoSource)
{
// Create the bitmap object
// NOTE: This is *not* a GDI+ Bitmap object
_photo = new BitmapImage();
MemoryStream strm = new MemoryStream();
// Well-known hack to make Northwind images work
int offset = 78;
strm.Write(photoSource, offset, photoSource.Length - offset);
// Read the image into the bitmap object
_photo.BeginInit();
_photo.StreamSource = strm;
_photo.EndInit();
}
}
在 Visual Basic .NET 中:
Public Class Employee
‘ Fields
Dim _employeeID As Integer
Dim _firstName As String
Dim _lastName As String
Dim _title As String
Dim _hireDate As DateTime
Dim _photo As BitmapImage
‘ Constructor
Public Sub New(ByVal record As IDataRecord)
_employeeID = CType(record("EmployeeID"), Integer)
_firstName = CType(record("FirstName"), String)
_lastName = CType(record("LastName"), String)
_title = CType(record("Title"), String)
_hireDate = CType(record("HireDate"), DateTime)
CreatePhoto(CType(record("Photo"), Byte()))
End Sub
‘ BitmapImage creation
Private Sub CreatePhoto(ByVal photoSource() As Byte)
‘ Create the bitmap object
‘ NOTE: This is *not* a GDI+ Bitmap object
_photo = New BitmapImage()
Dim strm As MemoryStream = New MemoryStream()
‘ Well-known hack to make Northwind images work
Dim offset As Integer = 78
strm.Write(photoSource, offset, photoSource.Length - offset)
‘ Read the image into the bitmap object
_photo.BeginInit()
_photo.StreamSource = strm
_photo.EndInit()
End Sub
End Class
該類接受一個 IDataRecord 類(DataReader 的單一結(jié)果,不過我們馬上就會對此進行介紹),并填寫我們在本文前面的 DataTable 示例中使用的那些字段。請注意,我們已經(jīng)將此處的 BitmapImage 創(chuàng)建移至業(yè)務(wù)對象,從而可以在 UI 類中更簡單地使用雇員。
接下來,我們將需要這些字段的屬性訪問器:
在 C# 中:
// Read-Only
public int EmployeeID
{
get { return _employeeID; }
}
public string FirstName
{
get { return _firstName; }
set { _firstName = value; }
}
public string LastName
{
get { return _lastName; }
set { _lastName = value; }
}
public string Title
{
get { return _title; }
set { _title = value; }
}
public DateTime HireDate
{
get { return _hireDate; }
set { _hireDate = value; }
}
// Read-Only
public BitmapImage Photo
{
get { return _photo; }
}
在 Visual Basic .NET 中:
‘ Read-Only
Public ReadOnly Property EmployeeID() As Integer
Get
Return _employeeID
End Get
End Property
Public Property FirstName() As String
Get
Return _firstName
End Get
Set (ByVal Value As String)
_firstName = value
End Set
End Property
Public Property LastName() As String
Get
Return _lastName
End Get
Set (ByVal Value As String)
_lastName = value
End Set
End Property
Public Property Title() As String
Get
Return _title
End Get
Set (ByVal Value As String)
_title = value
End Set
End Property
Public Property HireDate() As DateTime
Get
Return _hireDate
End Get
Set (ByVal Value As DateTime)
_hireDate = value
End Set
End Property
‘ Read-Only
Public ReadOnly Property Photo() As BitmapImage
Get
Return _photo
End Get
End Property
在這些代碼中,我們僅允許對類中的字段進行讀寫(或只讀)訪問?,F(xiàn)在,可以編寫一個集合來保存我們的雇員:
在 C# 中:
public class EmployeeList : ObservableCollection
{
public EmployeeList()
{
string connString =
ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
string query = @"
SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo
FROM Employees
";
// Fill the Set with the data
using (SqlConnection conn = new SqlConnection(connString))
{
try
{
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = query;
conn.Open();
SqlDataReader rdr = cmd.ExecuteReader();
while (rdr.Read())
{
Add(new Employee(rdr));
}
}
finally
{
if (conn.State != ConnectionState.Closed) conn.Close();
}
}
}
}
在 Visual Basic .NET 中:
Public Class EmployeeList
Inherits ObservableCollection
Public Sub New()
String connString =
ConfigurationManager.ConnectionStrings("Northwind").ConnectionString
String query = _
"SELECT EmployeeID, FirstName, LastName, Title, HireDate, Photo " + _
" FROM Employees"
‘ Fill the Set with the data
Using conn as New SqlConnection(connString)
Try
Dim cmd As SqlCommand = conn.CreateCommand()
cmd.CommandText = query
conn.Open()
Dim rdr As SqlDataReader = cmd.ExecuteReader()
While rdr.Read()
Add(New Employee(rdr))
End While
Finally
If conn.State <> ConnectionState.Closed Then
conn.Close()
End If
End Try
End Using
End Sub
End Class
該集合的基類是 ObservableCollection 類,它提供一種機制,使得 UI 可以知道該集合中是否添加了新成員。我們已經(jīng)將數(shù)據(jù)訪問從 UI 頁移至 Collection 類。創(chuàng)建該類后,我們查詢數(shù)據(jù)庫并通過 DataReader 向該集合添加新雇員。既然我們具有了集合和單個對象,就可以通過映射將類導入 XAML 中(本系列文章的第一部分對此進行了詳細解釋):
<Window
...
xmlns:e="Example"
DataContext="{StaticResource EmployeeList}"
>
<Window.Resources>
<e:EmployeeList x:Key="EmployeeList" />
...
</Window.Resources>
...
</Window>
我們用 ?Mapping 聲明將該類導入 XAML 文檔中,并在 Resources 中指定 EmployeeList,這樣我們就可以將其用作窗口的 DataContext。這樣,XAML 文件的其余部分就與原始雇員瀏覽器完全相同了,因為我們?nèi)詫L試在 DataSet 示例中使用的那些字段名。唯一的改動是綁定 XAML 文檔中的 BitmapImage,而不是在隱藏代碼中進行該操作:
...
<Image Name="theImage" Canvas.Top="5" Canvas.Left="5" Width="75"
Source="{Binding Path=Photo}"
/> ...
現(xiàn)在,我們具有一個行為相同的雇員瀏覽器:
圖 3. 基于業(yè)務(wù)對象的雇員瀏覽器
除了使用類型映射,您還可以使用 ObjectDataProvider 將對象置于 XAML 中。正如我在本文第一部分中介紹的那樣,只需指定一個鍵和類型名稱:
<ObjectDataProvider x:Key="EmployeeList"
TypeName="Example.Data.EmployeeList, ExampleCS"/>
x:Key 只是一個要在綁定中使用的名字對象,Typename 是類名和程序集(在本例中是我們的 UI 所在的程序集)。XAML 的其余部分保持不變,因為我們要加載相同的數(shù)據(jù)。
我們所處的位置
現(xiàn)在,我們可以使用 DataSet 或自定義對象從數(shù)據(jù)庫下載數(shù)據(jù),然后將數(shù)據(jù)直接綁定到 WPF 對象。您應(yīng)該準備好探究您的第一個 WPF 數(shù)據(jù)庫項目。
參考資料
轉(zhuǎn)到原英文頁面