將資料繫結至控制項 (WCF Data Services)
您可以使用 WCF Data Services,將控制項 (例如 ComboBox 和 ListView 控制項) 繫結至 DataServiceCollection<T> 類別的執行個體。繼承自 ObservableCollection<T> 類別的這個集合包含來自 Open Data Protocol (OData) 摘要的資料。 此類別表示在加入或移除項目時提供通知的動態資料集合。 當您使用 DataServiceCollection<T> 的執行個體進行資料繫結時,WCF Data Services 用戶端程式庫會處理這些事件,以確保 DataServiceContext 所追蹤的物件會與繫結 UI 項目中的資料保持同步。
在集合中加入或移除物件時,DataServiceCollection<T> 類別會 (間接) 實作 INotifyCollectionChanged 介面以警示內容。 與 DataServiceCollection<T> 搭配使用的資料服務類型物件也必須實作 INotifyPropertyChanged 介面,以便在繫結集合中的物件屬性發生變更時警示 DataServiceCollection<T>。
注意
當您使用 [加入服務參考] 對話或 DataSvcUtil.exe 工具搭配 /dataservicecollection 選項來產生用戶端資料服務類別時,所產生的資料類別會實作 INotifyPropertyChanged 介面。如需詳細資訊,請參閱 HOW TO:手動產生用戶端資料服務類別 (WCF Data Services)。
建立繫結集合
以提供的 DataServiceContext 執行個體及選擇性的 DataServiceQuery<TElement> 或 LINQ 查詢 (執行此查詢時會傳回 IEnumerable<T> 執行個體) 呼叫其中一個類別建構函式方法,建立一個新的 DataServiceCollection<T> 類別執行個體。 此 IEnumerable<T> 會提供繫結集合的物件來源,這些物件是從 OData 摘要具體化而來。 如需詳細資訊,請參閱物件具體化 (WCF Data Services)。 根據預設,DataServiceContext 會自動追蹤對插入於集合中的繫結物件和項目所做的變更。 如需手動追蹤這些變更,請呼叫其中一個使用 trackingMode 參數的建構函式方法,並指定 None 的值。
下列範例示範如何根據所提供的 DataServiceContext 以及傳回所有客戶與相關訂單的 DataServiceQuery<TElement> 建立 DataServiceCollection<T> 執行個體。
' Create a new collection that contains all customers and related orders.
Dim trackedCustomers As DataServiceCollection(Of Customer) = _
New DataServiceCollection(Of Customer)(context.Customers.Expand("Orders"))
// Create a new collection that contains all customers and related orders.
DataServiceCollection<Customer> trackedCustomers =
new DataServiceCollection<Customer>(context.Customers.Expand("Orders"));
繫結資料至 Windows Presentation Foundation 項目
由於 DataServiceCollection<T> 類別繼承自 ObservableCollection<T> 類別,因此您可以在 Windows Presentation Foundation (WPF) 應用程式中將物件繫結至項目或控制項,就像使用 ObservableCollection<T> 類別進行繫結一樣。 如需詳細資訊,請參閱資料繫結 (Windows Presentation Foundation)。 繫結資料服務資料至 WPF 控制項的其中一個方法是將項目的 DataContext 屬性設定為包含查詢結果之 DataServiceCollection<T> 類別的執行個體。 在這種情況下,您可以使用 ItemsSource 屬性來設定控制項的物件來源。 使用 DisplayMemberPath 屬性來指定要顯示繫結物件的哪一個屬性。 如果您要將項目繫結至導覽屬性所傳回的相關物件,請在為 ItemsSource 屬性定義的繫結中加入路徑。 這個路徑是相對於父控制項 DataContext 屬性所設定的根物件位置。 下列範例會設定 StackPanel 項目的 DataContext 屬性,將父控制項繫結至客戶物件的 DataServiceCollection<T>:
' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
Where cust.Country = customerCountry _
Select cust
' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)
' Bind the root StackPanel element to the collection
' related object binding paths are defined in the XAML.
Me.LayoutRoot.DataContext = trackedCustomers
' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
Where cust.Country = customerCountry _
Select cust
' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customers)(customerQuery, _
TrackingMode.AutoChangeTracking, "Customers", _
AddressOf OnMyPropertyChanged, AddressOf OnMyCollectionChanged)
' Bind the root StackPanel element to the collection
' related object binding paths are defined in the XAML.
Me.LayoutRoot.DataContext = trackedCustomers
Me.LayoutRoot.UpdateLayout()
' Create a LINQ query that returns customers with related orders.
Dim customerQuery = From cust In context.Customers.Expand("Orders") _
Where cust.Country = customerCountry _
Select cust
' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery, _
TrackingMode.AutoChangeTracking, "Customers", _
AddressOf OnMyPropertyChanged, AddressOf OnMyCollectionChanged)
' Bind the root StackPanel element to the collection
' related object binding paths are defined in the XAML.
Me.LayoutRoot.DataContext = trackedCustomers
// Create a LINQ query that returns customers with related orders.
var customerQuery = from cust in context.Customers.Expand("Orders")
where cust.Country == customerCountry
select cust;
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery,
TrackingMode.AutoChangeTracking,"Customers",
OnPropertyChanged, OnCollectionChanged);
// Bind the root StackPanel element to the collection;
// related object binding paths are defined in the XAML.
this.LayoutRoot.DataContext = trackedCustomers;
// Create a LINQ query that returns customers with related orders.
var customerQuery = from cust in context.Customers.Expand("Orders")
where cust.Country == customerCountry
select cust;
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);
// Bind the root StackPanel element to the collection;
// related object binding paths are defined in the XAML.
LayoutRoot.DataContext = trackedCustomers;
下列範例顯示子控制項 DataGrid 和 ComboBox 的 XAML 繫結定義:
<StackPanel Orientation="Vertical" Height="Auto" Name="LayoutRoot" Width="Auto">
<Label Content="Customer ID" Margin="20,0,0,0" />
<ComboBox Name="customerIDComboBox" DisplayMemberPath="CustomerID" ItemsSource="{Binding}"
IsSynchronizedWithCurrentItem="True" SelectedIndex="0" Height="23" Width="120"
HorizontalAlignment="Left" Margin="20,0,0,0" VerticalAlignment="Center" />
<ListView ItemsSource="{Binding Path=Orders}" Name="ordersDataGrid" Margin="34,46,34,50">
<ListView.View>
<GridView AllowsColumnReorder="False" ColumnHeaderToolTip="Line Items">
<GridViewColumn DisplayMemberBinding="{Binding Path=OrderID, Mode=OneWay}"
Header="Order ID" Width="50"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=OrderDate, Mode=TwoWay}"
Header="Order Date" Width="50"/>
<GridViewColumn DisplayMemberBinding="{Binding Path=Freight, Mode=TwoWay}"
Header="Freight Cost" Width="50"/>
</GridView>
</ListView.View>
</ListView>
<Button Name="saveChangesButton" Content="Save Changes" Click="saveChangesButton_Click"
Width="80" Height="30" Margin="450,0,0,0"/>
</StackPanel>
如需詳細資訊,請參閱 HOW TO:將資料繫結至 Windows Presentation Foundation 項目 (WCF Data Services)。
實體加入一對多或多對多關聯性時,關聯性的導覽屬性會傳回相關物件集合。 當您使用 [加入服務參考] 對話方塊或 DataSvcUtil.exe 工具產生用戶端服務類別時,導覽屬性會傳回 DataServiceCollection<T> 的執行個體。 這樣可讓您將相關物件繫結至控制項,同時支援一般的 WPF 繫結案例,例如相關實體的主版詳細資料繫結模式。 在前述的 XAML 範例中,XAML 程式碼會將主版 DataServiceCollection<T> 繫結至根資料項目。 接著會將訂單 DataGrid 繫結至從所選 Customers 物件傳回的 Orders DataServiceCollection<T>,然後再繫結至 Window 的根項目。
將資料繫結至 Windows Form 控制項
若要將物件繫結至 Windows Form 控制項,請將控制項的 DataSource 屬性設定為包含查詢結果之 DataServiceCollection<T> 類別的執行個體。
注意
只有接聽變更事件的控制項才支援資料繫結,透過的方式是實作 INotifyCollectionChanged 和 INotifyPropertyChanged 介面。當控制項不支援這種變更通知時,對基礎 DataServiceCollection<T> 所做的變更不會反映在繫結控制項中。
下列範例會將 DataServiceCollection<T> 繫結到 ComboBox 控制項:
' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)
'Bind the Customers combobox to the collection.
customersComboBox.DisplayMember = "CustomerID"
customersComboBox.DataSource = trackedCustomers
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);
//Bind the Customers combobox to the collection.
customersComboBox.DisplayMember = "CustomerID";
customersComboBox.DataSource = trackedCustomers;
當您使用 [加入服務參考] 對話方塊產生用戶端資料服務類別時,也會根據所產生的 DataServiceContext 建立專案資料來源。 您可以使用此資料來源建立 UI 項目或控制項,將項目從 [資料來源] 視窗拖曳至設計工具上,以顯示資料服務的資料。 這些項目會成為繫結至資料來源之應用程式 UI 中的項目。 如需詳細資訊,請參閱 HOW TO:使用專案資料來源繫結資料 (WCF Data Services)。
繫結分頁資料
您可以設定資料服務來限制單一回應訊息中傳回的查詢資料量。 如需詳細資訊,請參閱設定資料服務 (WCF Data Services)。 當資料服務分頁回應資料時,每個回應都會包含一個連結以傳回下一頁結果。 如需詳細資訊,請參閱載入延後的內容 (WCF Data Services)。 在這個情況下,您必須傳遞從 NextLinkUri 屬性取得的 URI,在 DataServiceCollection<T> 呼叫 Load 方法,以明確地載入頁面,如下列範例所示:
' Create a new collection for binding based on the LINQ query.
trackedCustomers = New DataServiceCollection(Of Customer)(customerQuery)
' Load all pages of the response at once.
While trackedCustomers.Continuation IsNot Nothing
trackedCustomers.Load( _
context.Execute(Of Customer)(trackedCustomers.Continuation.NextLinkUri))
End While
// Create a new collection for binding based on the LINQ query.
trackedCustomers = new DataServiceCollection<Customer>(customerQuery);
// Load all pages of the response at once.
while (trackedCustomers.Continuation != null)
{
trackedCustomers.Load(
context.Execute<Customer>(trackedCustomers.Continuation.NextLinkUri));
}
相關物件會以類似的方式載入。 如需詳細資訊,請參閱 HOW TO:將資料繫結至 Windows Presentation Foundation 項目 (WCF Data Services)。
自訂資料繫結行為
DataServiceCollection<T> 類別可讓您攔截變更集合時所引發的事件,例如加入或移除物件,以及變更集合中物件的屬性時所引發的事件。 您可以修改資料繫結事件以覆寫預設的行為,包括下列條件約束:
委派內未執行驗證。
加入實體時會自動加入相關的實體。
刪除實體時不會刪除相關的實體。
當您建立新的 DataServiceCollection<T> 執行個體時,您可以選擇指定下列參數,這些參數會定義處理變更繫結物件時引發之事件的方法委派。
entityChanged:繫結物件變更時會呼叫此方法。 此 Func<T, TResult> 委派接受 EntityChangedParams 物件並傳回布林值,指出是否仍應發生預設行為 (呼叫 DataServiceContext 的 UpdateObject)。
entityCollectionChanged:在繫結集合中加入或移除物件時會呼叫此方法。 此 Func<T, TResult> 委派接受 EntityCollectionChangedParams 物件並傳回布林值,指出是否仍應發生預設行為 (呼叫 Add 動作的 AddObject,或在 DataServiceContext 呼叫 Remove 動作的 DeleteObject)。
注意
WCF Data Services 不會針對您在這些委派中實作的自訂行為執行驗證。
下列範例會自訂 Remove 動作以呼叫 DeleteLink 和 DeleteObject 方法來移除屬於已刪除之 Orders 實體的 Orders_Details 方法。 由於刪除父實體時不會自動刪除相依實體,因此會執行這個自訂行為。
' Method that is called when the CollectionChanged event is handled.
Private Function OnMyCollectionChanged( _
ByVal entityCollectionChangedinfo As EntityCollectionChangedParams) As Boolean
If entityCollectionChangedinfo.Action = _
NotifyCollectionChangedAction.Remove Then
' Delete the related items when an order is deleted.
If entityCollectionChangedinfo.TargetEntity.GetType() Is GetType(Orders) Then
' Get the context and object from the supplied parameter.
Dim context = entityCollectionChangedinfo.Context
Dim deletedOrder As Orders = _
CType(entityCollectionChangedinfo.TargetEntity, Orders)
' Load the related OrderDetails.
context.LoadProperty(deletedOrder, "Order_Details")
' Delete the order and its related items
For Each item As Order_Details In deletedOrder.Order_Details
'context.DeleteLink(deletedOrder, "Order_Details", item)
context.DeleteObject(item)
Next
' Delete the order and then return false since the object is already deleted.
context.DeleteObject(deletedOrder)
Return False
Else
Return True
End If
Else
' Use the default behavior.
Return True
End If
End Function
' Method that is called when the CollectionChanged event is handled.
Private Function OnMyCollectionChanged( _
ByVal entityCollectionChangedinfo As EntityCollectionChangedParams) As Boolean
If entityCollectionChangedinfo.Action = _
NotifyCollectionChangedAction.Remove Then
' Delete the related items when an order is deleted.
If entityCollectionChangedinfo.TargetEntity.GetType() Is GetType(Order) Then
' Get the context and object from the supplied parameter.
Dim context = entityCollectionChangedinfo.Context
Dim deletedOrder As Order = _
CType(entityCollectionChangedinfo.TargetEntity, Order)
If deletedOrder.Order_Details.Count = 0 Then
' Load the related OrderDetails.
context.LoadProperty(deletedOrder, "Order_Details")
End If
' Delete the order and its related items
For Each item As Order_Detail In deletedOrder.Order_Details
context.DeleteObject(item)
Next
' Delete the order and then return false since the object is already deleted.
context.DeleteObject(deletedOrder)
Return True
Else
Return False
End If
Else
' Use the default behavior.
Return False
End If
End Function
// Method that is called when the CollectionChanged event is handled.
private bool OnCollectionChanged(
EntityCollectionChangedParams entityCollectionChangedinfo)
{
if (entityCollectionChangedinfo.Action ==
NotifyCollectionChangedAction.Remove)
{
// Delete the related items when an order is deleted.
if (entityCollectionChangedinfo.TargetEntity.GetType() == typeof(Order))
{
// Get the context and object from the supplied parameter.
DataServiceContext context = entityCollectionChangedinfo.Context;
Order deletedOrder = entityCollectionChangedinfo.TargetEntity as Order;
if (deletedOrder.Order_Details.Count == 0)
{
// Load the related OrderDetails.
context.LoadProperty(deletedOrder, "Order_Details");
}
// Delete the order and its related items;
foreach (Order_Detail item in deletedOrder.Order_Details)
{
context.DeleteObject(item);
}
// Delete the order and then return true since the object is already deleted.
context.DeleteObject(deletedOrder);
return true;
}
else
{
return false;
}
}
else
{
// Use the default behavior.
return false;
}
}
如需詳細資訊,請參閱 HOW TO:自訂資料繫結行為 (WCF Data Services)。
使用 Remove 方法移除 DataServiceCollection<T> 中的物件時,預設行為是在 DataServiceContext 中將該物件也標記為已刪除。 若要變更此行為,您可以將委派指定為發生 CollectionChanged 事件時呼叫之 entityCollectionChanged 參數中的方法。
使用自訂用戶端資料類別資料繫結
若要將物件載入至 DataServiceCollection<T>,物件本身必須實作 INotifyPropertyChanged 介面。 使用 [加入服務參考] 對話方塊或 DataSvcUtil.exe 工具實作此介面時所產生的資料服務用戶端類別。 如果您自行提供用戶端資料類別,則必須使用另一種集合類型進行資料繫結。 物件變更時,您必須在資料繫結控制項中處理事件,以呼叫 DataServiceContext 類別的下列方法:
AddObject:將新的物件加入至集合中時。
DeleteObject:自集合移除物件時。
UpdateObject:集合中的物件屬性變更時。
AddLink:將物件加入至相關物件集合中時。
SetLink:將物件加入至相關物件集合中時。
如需詳細資訊,請參閱更新資料服務 (WCF Data Services)。