एक सुंदर डेटा-संचालित चांदी की रोशनी ऐप विकसित करने की मेरी तलाश में, मुझे लगातार कुछ प्रकार की दौड़ की स्थिति के खिलाफ आना पड़ता है जिसे आसपास काम करने की आवश्यकता होती है। नवीनतम एक नीचे है। किसी भी सहायता की सराहना की जाएगी।सिल्वरलाइट कम्बोबॉक्स डाटाबेसिंग रेस कंडीशन
आपके पास बैक एंड पर दो टेबल हैं: एक घटक है और एक निर्माता है। प्रत्येक घटक के पास एक निर्माता होता है। बिल्कुल असामान्य, विदेशी कुंजी लुकअप-रिश्ते नहीं।
मैं सिल्वरलाइट, मैं डब्ल्यूसीएफ सेवा के माध्यम से डेटा तक पहुंचता हूं। कॉम्बोबॉक्स के संभावित चयनों को पॉप्युलेट करने के लिए निर्माताओं की पूरी सूची प्राप्त करने के लिए मैं मौजूदा घटक (देखने या संपादित करने) और निर्माता/GetAll() को कॉल करने के लिए Components_Get (id) पर कॉल करूंगा। इसके बाद मैं मौजूदा घटक के लिए कॉम्बोबॉक्स पर कॉम्बोबॉक्स पर चयनित इटैम और संभावित निर्माता की सूची में कॉम्बोबॉक्स पर आइटमसोर्स को बांधता हूं। इस तरह:
<UserControl.Resources>
<data:WebServiceDataManager x:Key="WebService" />
</UserControl.Resources>
<Grid DataContext={Binding Components.Current, mode=OneWay, Source={StaticResource WebService}}>
<ComboBox Grid.Row="2" Grid.Column="2" Style="{StaticResource ComboBoxStyle}" Margin="3"
ItemsSource="{Binding Manufacturers.All, Mode=OneWay, Source={StaticResource WebService}}"
SelectedItem="{Binding Manufacturer, Mode=TwoWay}" >
<ComboBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding Name}" Style="{StaticResource DefaultTextStyle}"/>
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
यह लंबे समय के लिए महान काम किया, जब तक मैं चालाक हो गया और घटक के एक छोटे से ग्राहक साइड संचय (जो मैं निर्माता के लिए पर बारी के रूप में अच्छी तरह से योजना बनाई) किया था। जब मैंने घटक के लिए कैशिंग चालू कर दिया और मुझे कैश हिट मिला, तो सभी डेटा सही ढंग से ऑब्जेक्ट्स में होंगे, लेकिन चयनित इटिम बांधने में विफल रहेगा। इसका कारण यह है कि कॉल सिल्वरलाइट में असीमित है और कैशिंग के लाभ के साथ, निर्माता को निर्माताओं से पहले वापस नहीं किया जा रहा है। तो जब चयनित इटम्स आइटमसोर्स सूची में घटक .Current.Manufacturer को खोजने का प्रयास करता है, तो यह वहां नहीं है, क्योंकि यह सूची अभी भी खाली है क्योंकि निर्माता। सभी अभी तक डब्ल्यूसीएफ सेवा से लोड नहीं हुए हैं। दोबारा, अगर मैं घटक कैशिंग बंद कर देता हूं, तो यह फिर से काम करता है, लेकिन यह गलत लगता है - जैसे कि मैं सिर्फ भाग्यशाली हो रहा हूं कि समय काम कर रहा है। सही फिक्स आईएमएचओ एमएस के लिए कॉम्बोबॉक्स/आइटम नियंत्रण नियंत्रण को ठीक करने के लिए है यह समझने के लिए कि असिन्च कॉल मानक के साथ होगा।
- कैशिंग को हटा दें या बोर्ड भर में इसे चालू करने के लिए एक बार फिर से नकाब: लेकिन तब तक, मैं एक की जरूरत के लिए एक रास्ता यो इसे ठीक ...
यहां कुछ विकल्प है कि मैं के बारे में सोचा है की जरूरत है समस्या। अच्छा IMHO नहीं, क्योंकि यह फिर से असफल हो जाएगा। गलीचा के नीचे इसे वापस साफ करने के लिए वास्तव में तैयार नहीं है।
- एक मध्यस्थ वस्तु बनाएं जो मेरे लिए सिंक्रनाइज़ेशन करेगी (जो आइटम नियंत्रण में ही किया जाना चाहिए)। यह स्वीकार करेगा और आइटम और एक आइटम सूची और फिर आउटपुट और ItemWithItemsList संपत्ति जब दोनों पहुंचे हैं। मैं परिणामस्वरूप आउटपुट के लिए कॉम्बोबॉक्स को बांध दूंगा ताकि यह किसी दूसरे के सामने कभी भी एक आइटम न मिले। मेरी समस्या यह है कि यह दर्द की तरह लगता है लेकिन यह सुनिश्चित करेगा कि दौड़ की स्थिति फिर से नहीं होती है।
कोई भी संकेत/टिप्पणियां?
FWIW: मैं दूसरों के लाभ के लिए यहां अपना समाधान पोस्ट करूंगा।
@ जो: प्रतिक्रिया के लिए बहुत बहुत धन्यवाद। मैं केवल UI थ्रेड से यूआई को अपडेट करने की आवश्यकता से अवगत हूं। यह मेरी समझ है और मुझे लगता है कि मैंने डीबगर के माध्यम से यह पुष्टि की है कि एसएल 2 में, सेवा संदर्भ द्वारा उत्पन्न कोड आपके लिए इसका ख्याल रखता है। यानी जब मैं निर्माता/GetAll_Asynch() को कॉल करता हूं, तो मुझे निर्माता_GetAll_Completed ईवेंट के माध्यम से परिणाम मिलता है। यदि आप उत्पन्न होने वाले सेवा संदर्भ कोड के अंदर देखते हैं, तो यह सुनिश्चित करता है कि * पूर्ण ईवेंट हैंडलर को यूआई थ्रेड से बुलाया जाता है। मेरी समस्या यह नहीं है, यह है कि मैं दो अलग-अलग कॉल करता हूं (एक निर्माता सूची के लिए और एक घटक के लिए एक जो घटक की आईडी का संदर्भ देता है) और फिर इन दोनों परिणामों को एक कॉम्बोबॉक्स में बांधें। वे यूआई थ्रेड पर दोनों बांधते हैं, समस्या यह है कि अगर सूची चयन से पहले नहीं मिलती है, तो चयन को नजरअंदाज कर दिया जाता है।
यह भी ध्यान दें कि यह अभी भी एक समस्या है if you just set the ItemSource and the SelectedItem in the wrong order !!!
एक और अद्यतन: जबकि अभी भी combobox दौड़ की स्थिति है, मैंने कुछ और दिलचस्प खोजा। आपको कभी उस संपत्ति के लिए "गेटटर" के भीतर से एक संपत्ति चेंज किए गए ईवेंट को जनरेट करना चाहिए। उदाहरण: मेरे एसएल डेटा ऑब्जेक्ट में निर्माता डेटाटा में, मेरे पास "ऑल" नामक एक संपत्ति है।
public class ManufacturersData : DataServiceAccessbase
{
public ObservableCollection<Web.Manufacturer> All
{
get
{
if (!AllLoaded)
LoadAllManufacturersAsync();
return mAll;
}
private set
{
mAll = value;
OnPropertyChanged("All");
}
}
private void LoadAllManufacturersAsync()
{
if (!mCurrentlyLoadingAll)
{
mCurrentlyLoadingAll = true;
// check to see if this component is loaded in local Isolated Storage, if not get it from the webservice
ObservableCollection<Web.Manufacturer> all = IsoStorageManager.GetDataTransferObjectFromCache<ObservableCollection<Web.Manufacturer>>(mAllManufacturersIsoStoreFilename);
if (null != all)
{
UpdateAll(all);
mCurrentlyLoadingAll = false;
}
else
{
Web.SystemBuilderClient sbc = GetSystemBuilderClient();
sbc.Manufacturers_GetAllCompleted += new EventHandler<hookitupright.com.silverlight.data.Web.Manufacturers_GetAllCompletedEventArgs>(sbc_Manufacturers_GetAllCompleted);
sbc.Manufacturers_GetAllAsync(); ;
}
}
}
private void UpdateAll(ObservableCollection<Web.Manufacturer> all)
{
All = all;
AllLoaded = true;
}
private void sbc_Manufacturers_GetAllCompleted(object sender, hookitupright.com.silverlight.data.Web.Manufacturers_GetAllCompletedEventArgs e)
{
if (e.Error == null)
{
UpdateAll(e.Result.Records);
IsoStorageManager.CacheDataTransferObject<ObservableCollection<Web.Manufacturer>>(e.Result.Records, mAllManufacturersIsoStoreFilename);
}
else
OnWebServiceError(e.Error);
mCurrentlyLoadingAll = false;
}
}
ध्यान दें कि यह कोड एक "कैश हिट" पर विफल रहता है क्योंकि यह एक PropertyChanged घटना उत्पन्न करेगा: मिल में {} यह अगर यह लोड किया गया है को देखने के लिए, नहीं तो यह इसे इस तरह से लोड करता है की जाँच करता है ऑल {Get {}} विधि के भीतर से "ऑल" के लिए जो आमतौर पर बाध्यकारी सिस्टम को सभी {get {}} को कॉल करने का कारण बनता है ... मैंने स्कॉटगू ब्लॉग पोस्टिंग तरीके से बाइंडबल रजत रोशनी डेटा ऑब्जेक्ट्स बनाने के इस पैटर्न की प्रतिलिपि बनाई और उसने मुझे अच्छी तरह से सेवा दी है, लेकिन इस तरह की चीजें इसे बहुत मुश्किल बनाती हैं। सौभाग्य से फिक्स सरल है। मनाइए कि यह किसी और के लिए सहायक हो।
यह समाधान एक आम है। लंबे समय तक, मैं एक और सामान्य समाधान की तलाश कर रहा हूं जिसमें सभी चयनकर्ता नियंत्रण शामिल हैं; न केवल कॉम्बोबॉक्स, और किसी भी नियंत्रण से विरासत के बिना ऐसा करता है। व्यवहार के साथ ऐसा करने का एक तरीका है। यह प्रस्तावित समाधान यूडब्ल्यूपी में भी काम करता है, और शायद डब्ल्यूपीएफ: http://stackoverflow.com/questions/36003805/uwp-silverlight-combobox-selector-itemssource-selecteditem-race-condition-solu –