一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

Windows Presentation Foundation 數(shù)據(jù)綁定:第二部分

 Lewis 2007-09-16

簡介

社區(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、DataTableDataRow)和自定義業(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 中的 FirstNameLastName

<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ù)自動綁定到圖像。為了便于該操作,我們可以處理 ComboBoxSelectionChanged 事件以填充我們的 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ù)庫項目。

參考資料

?

Windows SDK (includes WinFX)

?

Programming the Windows Presentation Foundation、Chris Sells 和 Ian Griffiths

?

本系列文章的第一部分

轉(zhuǎn)到原英文頁面



?2007 Microsoft Corporation. 版權(quán)所有.  保留所有權(quán)利 |商標 |隱私權(quán)聲明
Microsoft

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多

    最近的中文字幕一区二区| 久久99这里只精品热在线| 亚洲男人的天堂久久a| 深夜视频在线观看免费你懂| 尤物天堂av一区二区| 亚洲国产精品久久综合网| 久久99爱爱视频视频| 国产精品欧美日韩中文字幕| 欧美成人欧美一级乱黄| 日韩国产亚洲欧美激情| 欧美亚洲国产日韩一区二区| 国产一区二区精品丝袜| 亚洲欧美国产精品一区二区| 亚洲少妇人妻一区二区| 九九热在线免费在线观看| 日韩欧美一区二区黄色| 欧美日韩乱码一区二区三区| 成人午夜视频在线播放| 国产精品不卡高清在线观看| 欧美乱视频一区二区三区| 少妇特黄av一区二区三区| 视频一区中文字幕日韩| 开心激情网 激情五月天| 国产精品视频第一第二区| 欧美日韩中黄片免费看| 69精品一区二区蜜桃视频| 小草少妇视频免费看视频| 午夜精品在线观看视频午夜| 欧美一级不卡视频在线观看| 亚洲天堂精品1024| 激情亚洲一区国产精品久久| 亚洲最新的黄色录像在线| 男女一进一出午夜视频| 成人精品日韩专区在线观看| 国产精品伦一区二区三区在线| 精品少妇人妻一区二区三区| 91欧美日韩中在线视频| 美女激情免费在线观看| 91亚洲国产成人久久| 九九热在线免费在线观看| 国产精品日韩精品一区|