2011-03-22 13 views
8

एक डब्ल्यूपीएफ ऐप में XamlReader.Load() विधि का उपयोग कर एक अलग फ़ाइल से उपयोगकर्ता नियंत्रण लोड करने का एक ऑपरेशन है:एक पृष्ठभूमि थ्रेड में XamlReader.Load। क्या यह संभव है?

StreamReader mysr = new StreamReader(pathToFile); 
DependencyObject rootObject = XamlReader.Load(mysr.BaseStream) as DependencyObject; 
ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
displayPage.Content = rootObject; 

प्रक्रिया को फ़ाइल के आकार के कारण कुछ समय लगता है, इसलिए यूआई कई सेकंड के लिए जमे हुए हो जाता है।

ऐप उत्तरदायी रखने के लिए मैं ऑपरेशन के उस हिस्से को करने के लिए पृष्ठभूमि थ्रेड का उपयोग करने का प्रयास करता हूं जो सीधे यूआई अपडेटिंग में शामिल नहीं है।

BackgroundWorker का उपयोग करने का प्रयास करते समय मुझे एक त्रुटि मिली: कॉलिंग थ्रेड एसटीए होना चाहिए, क्योंकि कई UI घटकों को इस

की आवश्यकता होती है, इसलिए, मैं एक और तरीका चला गया:

 private Thread _backgroundThread; 
_backgroundThread = new Thread(DoReadFile); 
_backgroundThread.SetApartmentState(ApartmentState.STA); 
_backgroundThread.Start(); 
void DoReadFile() 
{ 
    StreamReader mysr3 = new StreamReader(path2); 
    Dispatcher.BeginInvoke(
      DispatcherPriority.Normal, 
      (Action<StreamReader>)FinishedReading, 
      mysr3); 
} 

void FinishedReading(StreamReader stream) 
    {    
     DependencyObject rootObject = XamlReader.Load(stream.BaseStream) as DependencyObject; 
     ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
     displayPage.Content = rootObject; 
    } 

यह कुछ भी हल नहीं करता है क्योंकि हर समय उपभोग करने वाले ऑपरेशन यूआई थ्रेड में रहते हैं।

जब मैं इस तरह की कोशिश करता हूं, पृष्ठभूमि में सभी पार्सिंग कर रहा हूं:

private Thread _backgroundThread; 
_backgroundThread = new Thread(DoReadFile); 
_backgroundThread.SetApartmentState(ApartmentState.STA); 
_backgroundThread.Start(); 
void DoReadFile() 
{ 
    StreamReader mysr3 = new StreamReader(path2);  
    DependencyObject rootObject3 = XamlReader.Load(mysr3.BaseStream) as DependencyObject; 
     Dispatcher.BeginInvoke(
      DispatcherPriority.Normal, 
      (Action<DependencyObject>)FinishedReading, 
      rootObject3); 
    } 

    void FinishedReading(DependencyObject rootObject) 
    {    
    ContentControl displayPage = FindName("displayContentControl") as ContentControl; 
    displayPage.Content = rootObject; 
    } 

मुझे अपवाद मिला: कॉलिंग थ्रेड इस ऑब्जेक्ट तक नहीं पहुंच सकता है क्योंकि एक अलग थ्रेड इसका मालिक है। (लोड किए गए UserControl में अन्य नियंत्रण मौजूद हैं जो शायद त्रुटि दे सकते हैं)

क्या इस ऑपरेशन को यूआई को उत्तरदायी होने के तरीके में करने का कोई तरीका है?

+0

पृष्ठभूमि कार्यकर्ता का उपयोग करें, सुनिश्चित करें कि अगर आप किसी भी ऑब्जेक्ट को संशोधित करने (सेट/एड) करने जा रहे हैं जो थ्रेड के बजाय दायरे में नहीं हैं, तो पृष्ठभूमि कार्यकर्ता यह है कि आप एक func/action या प्रतिनिधि का उपयोग करते हैं बाहर निकलें और इसे पृष्ठभूमि कार्यकर्ता धागे में सेट न करें। यदि पृष्ठभूमि कार्यकर्ता के बजाय आपका काम कुछ भी करता है और जब आप पूरा कर लेते हैं तो परिणाम (e.result) को ऑनकंपलेट ईवेंट/विधि में ले जाएं और यूआई थ्रेड में अपनी ऑब्जेक्ट अपडेट करें। – Landern

उत्तर

7

पृष्ठभूमि थ्रेड लोड करने के लिए XAML प्राप्त करना अनिवार्य रूप से एक गैर-स्टार्टर है। डब्ल्यूपीएफ घटकों में थ्रेड एफ़िनिटी होती है और आमतौर पर वे केवल बनाए गए थ्रेड से उपयोग करने योग्य होते हैं। इसलिए पृष्ठभूमि थ्रेड पर लोडिंग यूआई को उत्तरदायी बना देगा लेकिन घटकों को बनाएगा जो तब यूआई थ्रेड में प्लग नहीं किए जा सकते हैं।

आपके पास सबसे अच्छा विकल्प है XAML फ़ाइल को छोटे टुकड़ों में तोड़ना और यूआई थ्रेड में उन्हें लोड करना सुनिश्चित करना सुनिश्चित करना है कि प्रत्येक लोड ऑपरेशन के बीच संदेश पंप की अनुमति दें। लोड को शेड्यूल करने के लिए Dispatcher ऑब्जेक्ट पर संभावित रूप से BeginInvoke का उपयोग करना।

2

जैसा कि आप पाएंगे, आप XamlReader.Load का उपयोग नहीं कर सकते हैं जब तक कि थ्रेड एसटीए न हो और यहां तक ​​कि यदि भी है, तो आपको इसे एक संदेश पंप शुरू करना होगा और उसके द्वारा बनाए गए नियंत्रणों तक सभी पहुंच को फ़नल करना होगा। यह एक मौलिक तरीका है कि डब्ल्यूपीएफ कैसे काम करता है और आप इसके खिलाफ नहीं जा सकते हैं।

तो अपने ही असली विकल्प हैं:

  1. छोटे टुकड़ों में XAML नीचे तोड़।
  2. प्रत्येक Load कॉल के लिए एक नया एसटीए थ्रेड प्रारंभ करें। Load रिटर्न के बाद, थ्रेड को एक संदेश लूप शुरू करने और बनाए गए नियंत्रणों को प्रबंधित करने की आवश्यकता होगी। आपके आवेदन को इस तथ्य को ध्यान में रखना होगा कि विभिन्न नियंत्रण अब विभिन्न धागे के स्वामित्व में हैं।
0

सिस्टम कहा जाता है। Xaml में Xaml​Background​Reader कक्षा है, शायद आप इसे अपने लिए काम करने के लिए प्राप्त कर सकते हैं। पृष्ठभूमि थ्रेड पर एक्सएएमएल पार्सर करें लेकिन यूआई थ्रेड पर ऑब्जेक्ट्स बनाएं।

संबंधित मुद्दे