2010-05-04 19 views
10

मेरे पास ऐसी विधि है जो कुछ क्रिया करने के लिए पृष्ठभूमि धागा बनाती है। इस पृष्ठभूमि धागे में मैं वस्तु बनाते हैं। लेकिन रनटाइम में बनाते समय यह ऑब्जेक्ट मुझे अपवाद देता है:मैं पृष्ठभूमि थ्रेड में WPF नियंत्रण कैसे बना सकता हूं?

कॉलिंग थ्रेड एसटीए होना चाहिए, क्योंकि कई UI घटकों को इसकी आवश्यकता होती है।

मुझे पता है कि मुझे यूआई को कुछ प्रतिबिंबित करने के लिए डिस्पैचर का उपयोग करना होगा। लेकिन इस मामले में मैं सिर्फ एक वस्तु बना देता हूं और यूआई के साथ सक्रिय नहीं हूं। यह मेरा कोड है:

public void SomeMethod() 
     { 
     BackgroundWorker worker = new BackgroundWorker(); 
     worker.DoWork += new DoWorkEventHandler(Background_Method); 
     worker.RunWorkerAsync(); 
     } 

    void Background_Method(object sender, DoWorkEventArgs e) 
     { 
     TreeView tv = new TreeView(); 
     } 

मैं पृष्ठभूमि धागा में वस्तुओं कैसे बना सकते हैं?

मैं WPF आवेदन

+0

एक और सवाल: पृष्ठभूमि कार्यकर्ता विधि के लिए संभव है विशिष्ट प्रकार के कुछ मूल्य वापस? – Polaris

+2

RunWorker पूर्ण विधि में e.Result संपत्ति की जांच करें। http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx। – Amsakanna

उत्तर

6

TreeView एक UI नियंत्रण का उपयोग करें। आप यूआई थ्रेड पर केवल यूआई नियंत्रण बना सकते हैं और कुशलतापूर्वक उपयोग कर सकते हैं, इसलिए आप जो करने की कोशिश कर रहे हैं वह संभव नहीं है।

आप क्या करना चाहते हैं पृष्ठभूमि थ्रेड पर सभी समय लेने वाले काम करते हैं, और फिर यूआई में हेरफेर करने के लिए यूआई थ्रेड पर "वापस कॉल करें"। यह वास्तव में काफी आसान है:

void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    // ... time consuming stuff... 

    // call back to the window to do the UI-manipulation 
    this.BeginInvoke(new MethodInvoker(delegate { 
     TreeView tv = new TreeView(); 
     // etc, manipulate 
    })); 
} 

मैं वाक्य रचना BeginInvoke (यह मेरे सिर के ऊपर से है), लेकिन वहाँ तुम वैसे भी जाना के लिए गलत हो सकता है ...

+0

मुझे वेब सेवा से कुछ डेटा मिलता है और रनटाइम इसके लिए काफी समय बिताता है। यही कारण है कि मैं पृष्ठभूमि में डेटा प्राप्त करना चाहता हूं और डेटा तैयार होने पर अपना पेड़ देख सकता हूं। – Polaris

+0

मैंने अपने उत्तर को कुछ और टिप्पणियों के साथ अपडेट किया है कि आप कार्यकर्ता धागे से यूआई थ्रेड में सामान कैसे कर सकते हैं। –

0

बस काम अपने कोड बनाने के लिए , आपको Thread.SetApartmentState(ApartmentState.STA) पर कॉल करके STA COM अपार्टमेंट में शामिल होना चाहिए। चूंकि BackgroundWorker शायद कुछ साझा थ्रेड पूल का उपयोग कर रहा है, किसी विशेष अपार्टमेंट में शामिल होने से इस थ्रेड पूल के अन्य उपयोगकर्ताओं को प्रभावित हो सकता है या यह विफल हो सकता है यदि यह पहले से ही सेट हो चुका है। MTA पहले। यहां तक ​​कि यदि यह सब काम करता है, तो आपके नव निर्मित TreeView को इस कार्यकर्ता थ्रेड पर लॉक कर दिया जाएगा। आप इसे अपने मुख्य यूआई थ्रेड में उपयोग करने में सक्षम नहीं होंगे।

यदि आपने अपने असली इरादों के बारे में कुछ और विस्तार से बताया है, तो आपको निश्चित रूप से बेहतर सहायता मिलेगी।

0

निम्नलिखित कोड का प्रयास करें:

public void SomeMethod() 
{ 

System.ComponentModel.BackgroundWorker myWorker = new System.ComponentModel.BackgroundWorker(); 

myWorker.DoWork += myWorker_DoWork; 

myWorker.RunWorkerAsync(); 

} 

private void myWorker_DoWork(object sender, 
    System.ComponentModel.DoWorkEventArgs e) 
{ 
    // Do time-consuming work here 
} 
3

HTH:

void Background_Method(object sender, DoWorkEventArgs e) 
    { 
     // Time Consuming operations without using UI elements 
     // Result of timeconsuming operations 
     var result = new object(); 
     App.Current.Dispatcher.Invoke(new Action<object>((res) => 
      { 
       // Working with UI 
       TreeView tv = new TreeView(); 
      }), result); 
    } 
0
void Background_Method(object sender, DoWorkEventArgs e) 
{ 
    TreeView tv = new TreeView(); 
    // Generate your TreeView here 
    UIDispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => 
    { 
     someContainer.Children.Add(tv); 
    }; 
} 
0

मैं मेरी समस्या हल। मैंने अभी RunWorker पूर्ण विधि की e.Result संपत्ति का उपयोग किया। मुझे पृष्ठभूमि धागे में डेटा मिलता है और फिर थ्रेड पूरा होने पर इस डेटा का उपयोग करें। उपयोगी तरीकों के लिए हर शरीर का धन्यवाद। e.Result संपत्ति के बारे में सिफारिश देने के लिए वीर को विशेष धन्यवाद।

+0

यदि आप कुछ अंतराल पर अपना यूआई अपडेट करना चाहते हैं, तो आप अपने डेटा भेजने के लिए ReportProgress विधि के UserState पैरामीटर का उपयोग कर सकते हैं और आवश्यक प्रकार के लिए e.UserState कास्टिंग करके अपनी प्रगति चेंज विधि में उनका उपयोग कर सकते हैं। – Amsakanna

0

इस प्रश्न पर जवाब देखें: How to run something in the STA thread?

जब आप अपने धागा परिभाषित करते हैं, जाँच के ApartmentState सेट:

thread.SetApartmentState(ApartmentState.STA); 

इस चाल करना चाहिए!

0

कोई भी विवरण में एक अलग एसटीए धागे के मामले पर चर्चा नहीं कर रहा है (भले ही अवधारणा बिल्कुल वही है)।

तो चलो कल्पना करते हैं एक सरल टैब नियंत्रण, क्लिक

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 

हम एक और एसटीए धागा

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     TabItem newTab = new TabItem() { Header = "New Tab" }; 
     tabMain.Items.Add(newTab); 
    } 
निश्चित रूप से

पर ले जाते हैं, तो हम एक System.InvalidOperationException

अब मिल एक बटन पर जोड़ा क्या होता है यदि हम नियंत्रण

private void AddToParent(string header) 
    { 
     TabItem newTab = new TabItem() { Header = header }; 
     tabMain.Items.Add(newTab); 
    } 

एक प्रतिनिधि विधि का उपयोग कर?

public void DelegateMethod(string header) 
    { 
     tabMain.Dispatcher.BeginInvoke(
       new Action(() => { 
        this.AddToParent(header); 
       }), null); 
    } 

यह काम करता है अगर तुम फोन यह

private void button_Click(object sender, RoutedEventArgs e) 
    { 
     Thread newThread = new Thread(new ThreadStart(ThreadStartingPoint)); 
     newThread.SetApartmentState(ApartmentState.STA); 
     newThread.IsBackground = true; 
     newThread.Start(); 
    } 
    private void ThreadStartingPoint() 
    { 
     DelegateMethod("new tab"); 
    } 

क्योंकि निश्चित रूप से अब हम एक ही मूल सूत्र में दृश्य पेड़ रहते हैं।

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