WPF Master and Detail

  • 1057
  • 0
  • 2013-05-09

WPF Master and Detail 的作法

[Forward from MSDN]

http://msdn.microsoft.com/en-us/library/aa480226.aspx

 

This simple example is fairly straightforward, but what if we are using related DataTables inside a DataSet? Let's see whether it is just as easy.

Binding Related DataTables

Let's extend the Employee Browser to include orders for which the employees are the salesperson. To do this, we will need to get order information. We could do this with a new query every time we switch users, but instead, let's load the data into a DataSet alongside theEmployee, and use a DataRelation to relate the two pieces of information.

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

This code will create a DataSet that has two tables: Employees and Orders. These tables are related by the EmployeeID through aRelation called Emp2Ord. We can still bind to the Employee DataTable so that our original data binding in the XAML works just fine. Much like Windows Forms or ASP.NET data binding, we can bind to the name of the Relation, to allow us to bind to a set of related records.

 
 
        <ListBox Name="OrderList" Width="280" Height="200"
               ItemsSource="{Binding Emp2Ord}" 
               ItemTemplate="{StaticResource OrderListTemplate}" />

This list box still uses the same DataContext as the rest of the Employee Browser; it is just specifying binding through the relationship instead. Once we bind the list box to the Relation, we can bind to individual fields in the ItemTemplate, just as we did in the employee combo box.

 
 
    <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>

With this additional data binding, we are now showing a list box of the order information that is related only to the selected user, as shown in Figure 2.

Aa480226.wpfdabndpt202(en-us,MSDN.10).gif

Figure 2. Our improved Employee Browser