我正在開發一個業務應用程序,使用Silverlight作爲UI,WCF使用Web服務作爲後端。在數據庫中我有許多查找表。當WCF服務返回一個業務對象時,其中一個屬性包含查找表中的整個行而不僅僅是外鍵,因此在UI中我可以顯示諸如查找表中的描述之類的東西,而無需再次調用服務。我現在要做的是提供一個綁定到整個查找值列表的組合框,並使其正確更新。我在本例中處理的業務對象稱爲Session,查找稱爲SessionType。數據綁定Silverlight組合框與對象列表 - 工作但很難看
下面是組合框的定義。 DataContext被設置爲Session的一個實例。我正在設置ItemTemplate,因爲組合框顯示的不僅僅是一串字符串。
<ComboBox
x:Name="SessionTypesComboBox"
ItemTemplate="{StaticResource SessionTypeDataTemplate}"
ItemsSource="{Binding Source={StaticResource AllSessionTypes}}"
SelectedItem="{Binding Path=SessionType, Mode=TwoWay}"
/>
業務對象和查找表都通過Web服務異步加載。如果我什麼都不做,組合框列表將填充SessionTypes,但它不會顯示來自Session的初始SessionType值。然而,如果組合框選擇被改變,會話將使用正確的SessionType進行更新。
似乎在發生的事情是,SelectedItem綁定不能將Session中的SessionType與SessionType列表中的等價物相匹配。對象值是相同的,但引用不是。
我找到的解決方法是加載會話和SessionTypes列表,然後使用SesstionTypes列表中相應的會話更新Session的當前SessionType。如果我這樣做,那麼組合框顯示正確。但對我來說這有一個不好的代碼味道。因爲一切都異步加載,所以我必須確定什麼時候一切都可用。以下是我正在做的是:
在我的Silverlight用戶控件的代碼隱藏:
// incremented every time we get data back during initial form load.
private volatile int m_LoadSequence = 0;
...
// Loaded event, called when the form is er... loaded.
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
// load session types
var sessionTypes = this.Resources["AllSessionTypes"] as Lookups.AllSessionTypes;
if (sessionTypes != null)
{
sessionTypes.DataLoadCompleted += (s, ea) =>
{
IncrementLoadSequence();
};
sessionTypes.LoadAsync();
}
// start loading another lookup table, same as above
// omitted for clarity
// set our DataContect to our business object (passed in when form was created)
this.LayoutRoot.DataContext = this.m_Session;
IncrementLoadSequence();
}
// This is the smelly part. This gets called by OnBlahCompleted events as web service calls return.
private void IncrementLoadSequence()
{
// check to see if we're expecting any more service calls to complete.
if (++m_LoadSequence < 3)
return;
// set lookup values on m_Session to the correct one in SessionType list.
// Get SessionType list from page resources
var sessionTypes = this.Resources["AllSessionTypes"] as Lookups.AllSessionTypes;
// Find the matching SessionType based on ID
this.m_Session.SessionType = sessionTypes.Where((st) => { return st.SessionTypeID == this.m_Session.SessionType.SessionTypeID; }).First();
// (other lookup table omitted for clarity)
}
所以基本上我有一個被我每次得到的數據從WebService後面加一個計數器。由於我期待3件事情(核心業務對象+ 2查找表),當該計數器達到3時,我會匹配引用。
對我來說,這看起來很詭異。我寧願看到組合框指定一個ValueMemberPath和SelectedValue,以將所選項目與列表中的一個匹配。
任何人都可以看到一個更乾淨的方式嗎?這種情況在商業應用程序中非常常見,所以我確信必須有一種很好的方式來做到這一點。
試圖記住原來的問題 - 我從那時起就改變了工作:) – geofftnz 2010-03-18 21:23:24