2012-04-26 22 views
5

मुझे पता है कि SO पर इस विषय पर कुछ जवाब हैं, लेकिन मुझे मेरे लिए कोई भी समाधान काम नहीं मिल रहा है। मैं एक आईमैमंड से एक नई खिड़की खोलने की कोशिश कर रहा हूं, जो डाटामैप्लेट के भीतर से निकाल दिया गया है। दोनों निम्नलिखित ऊपर उल्लिखित त्रुटि जब नई विंडो ("नया MessageWindowP" के भीतर) instantiated है:"कॉलिंग थ्रेड एसटीए होना चाहिए" वर्कअराउंड

TPL/FromCurrentSynchronizationContext का उपयोगअद्यतन: काम करता है

public class ChatUserCommand : ICommand 
{ 
    public void Execute(object sender) 
    { 
     if (sender is UserC) 
     { 
      var user = (UserC)sender; 
      var scheduler = TaskScheduler.FromCurrentSynchronizationContext();     
      Task.Factory.StartNew(new Action<object>(CreateMessageWindow), user,CancellationToken.None, TaskCreationOptions.None,scheduler);   
     } 
    } 

    private void CreateMessageWindow(object o) 
    { 
     var user = (UserC)o; 
     var messageP = new MessageWindowP(); 
     messageP.ViewModel.Participants.Add(user); 
     messageP.View.Show(); 
    } 
} 

ThreadStart का उपयोग करना:अद्यतन: अनुशंसित नहीं है, जॉन का जवाब देखें

public class ChatUserCommand : ICommand 
{ 
    public void Execute(object sender) 
    { 
     if (sender is UserC) 
     { 
      var user = (UserC)sender; 

      var t = new ParameterizedThreadStart(CreateMessageWindow); 
      var thread = new Thread(t); 
      thread.SetApartmentState(ApartmentState.STA); 
      thread.Start(sender);   
     } 
    } 

    private void CreateMessageWindow(object o) 
    { 
     var user = (UserC)o; 
     var messageP = new MessageWindowP(); 
     messageP.ViewModel.Participants.Add(user); 
     messageP.View.Show(); 
    } 
} 

धन्यवाद

संपादित करें। प्रतिक्रियाओं के आधार पर, मैं यह इंगित करना चाहता हूं कि मैंने वर्तमान प्रेषक पर BeginInvoke की कोशिश की है, साथ ही साथ मूल विधि में कोड निष्पादित किया है (इस प्रकार कोड शुरू हुआ)। नीचे देखें:

BeginInvokeअद्यतन: नहीं की सिफारिश की देख जॉन की जवाब

public class ChatUserCommand : ICommand 
{ 
    public void Execute(object sender) 
    { 
     if (sender is UserC) 
     { 
      var user = (UserC)sender; 
      Dispatcher.CurrentDispatcher.BeginInvoke(new Action<object>(CreateMessageWindow), sender);  
     } 
    } 

    private void CreateMessageWindow(object o) 
    { 
     var user = (UserC)o; 
     var messageP = new MessageWindowP(); 
     messageP.ViewModel.Participants.Add(user); 
     messageP.View.Show(); 
    } 
} 

एक ही धागे मेंअद्यतन: काम करता है अगर आप पहले से

public class ChatUserCommand : ICommand 
{ 
    public void Execute(object sender) 
    { 
     if (sender is UserC) 
     { 
      var user = (UserC)sender; 
      var messageP = new MessageWindowP(); 
      messageP.ViewModel.Participants.Add(user); 
      messageP.View.Show();  
     } 
    } 

} 

यूआई धागे पर हैं BeginInvoke, पहले/मुख्य वाई के प्रेषक के संदर्भ में ndowअद्यतन: काम करता है

public void Execute(object sender) 
    { 
     if (sender is UserC) 
     { 
      var user = (UserC)sender; 
        GeneralManager.MainDispatcher.BeginInvoke(
           DispatcherPriority.Normal, 
           new Action(() => this.CreateMessageWindow(user)));  
     } 
    } 

जहां GeneralManager.MainDispatcher पहले खिड़की मैं बनाने की डिस्पैचर के लिए एक संदर्भ है: एक नुकसान में

 [somewhere far far away] 
     mainP = new MainP(); 
     MainDispatcher = mainP.View.Dispatcher; 

मैं कर रहा हूँ।

+1

और उसी धागे और 'BeginInvoke' में कॉल करने में समस्या क्या थी? आपके थ्रेड में कौन सा धागा चलता है? – Vlad

+1

आप यहां 'डिस्पैचर.कुरेंट डिस्पैचर' का उपयोग नहीं कर सकते जैसे आप यहां करते हैं। मेरे उत्तर में अपडेट देखें। – Jon

+0

दोस्तों। अभी भी कोई भाग्य नहीं है ... :(फिर से अपडेट देखें। –

उत्तर

7

कॉलिंग थ्रेड केवल एसटीए नहीं होना चाहिए, लेकिन इसमें एक संदेश लूप भी होना चाहिए। आपके एप्लिकेशन में केवल एक थ्रेड है जिसमें पहले से ही एक संदेश लूप है, और यह आपका मुख्य धागा है। इसलिए आपको अपनी मुख्य थ्रेड से अपनी विंडो खोलने के लिए Dispatcher.BeginInvoke का उपयोग करना चाहिए।

उदा। अगर आप अपने मुख्य अनुप्रयोग विंडो (MainWindow) के लिए एक संदर्भ है, तो आप क्या कर सकते हैं

MainWindow.BeginInvoke(
    DispatcherPriority.Normal, 
    new Action(() => this.CreateMessageWindow(user))); 

अद्यतन:सावधान: आप नहीं आँख बंद करके Dispatcher.CurrentDispatcher कॉल कर सकते हैं, क्योंकि यह है कि तुम क्या यह लगता है कि ऐसा नहीं करता है कर देता है। documentation का कहना है कि CurrentDispatcher:

अगर एक पहले से ही धागा साथ संबद्ध नहीं है धागा वर्तमान में क्रियान्वित करने के लिए डिस्पैचर हो जाता है और बनाता है एक नई डिस्पैचर।

यही कारण है कि आप Dispatcher (उपरोक्त उदाहरण में के रूप में अपने मुख्य विंडो) की तरह पहले से मौजूदा UI नियंत्रण के साथ जुड़े का उपयोग करना चाहिए है।

+0

कोई अन्य विचार जॉन? मेरी मुख्य विंडो के डिस्पैचर का उपयोग करने का प्रयास किया। –

3

आप पृष्ठभूमि धागे से एक विंडो बनाने की कोशिश कर रहे हैं। आप विभिन्न कारणों से ऐसा नहीं कर सकते हैं। आम तौर पर आपको मुख्य अनुप्रयोग धागे में विंडो बनाने की आवश्यकता होती है।

अपने मामले के लिए, एक साधारण विचार होगा बस, इसे तुरंत बजाय एक Task आवंटन की (सिर्फ CreateMessageWindowExecute अंदर कहते हैं) करते हैं, क्योंकि अपने आदेश होगा निश्चित रूप से मुख्य (यूआई) धागे से आग। यदि आप थ्रेड के बारे में अनिश्चित हैं, जहां आपका Execute रन है, तो आप इसे Dispatcher.BeginInvoke() का उपयोग करके UI थ्रेड पर मार्शल कर सकते हैं।

वास्तव में कुछ मामले हैं जब आप अपनी नई विंडो को गैर-मुख्य धागे में चलाने के लिए चाहते हैं। यदि यह वास्तव में आपके मामले में वास्तव में आवश्यक है, तो आपको messageP.View.Show(); (कोड के दूसरे संस्करण का उपयोग करके) Dispatcher.Run(); जोड़ना चाहिए। यह नए धागे में संदेश पाश शुरू करता है।

आपको टीपीएल के थ्रेड में विंडो चलाने की कोशिश नहीं करनी चाहिए, क्योंकि ये धागे आमतौर पर थ्रेडपूल धागे होते हैं, और इसलिए आपके नियंत्रण से बाहर होते हैं। उदाहरण के लिए, आप यह सुनिश्चित नहीं कर सकते कि वे एसटीए हैं (आमतौर पर, वे एमटीए हैं)।

संपादित करें:
अपने अपडेट किए गए कोड में त्रुटि से, यह स्पष्ट है कि Execute कुछ गैर-UI थ्रेड में चलता है। Dispatcher.CurrentDispatcher के बजाय Application.Current.Dispatcher का उपयोग करने का प्रयास करें। (CurrentDispatcher वर्तमान धागा, यदि वर्तमान धागा मुख्य एक नहीं है जो गलत हो सकता है की डिस्पैचर का मतलब है।)

+0

हाय वहाँ। आपकी मदद के लिए धन्यवाद। जो भी आप कहते हैं वह समझ में आता है, लेकिन मैंने केवल उन तकनीकों का सहारा लिया क्योंकि रनन निष्पादन के अंदर कोड को एक ही त्रुटि के कारण। मैंने कोशिश की है कि अधिक चीजों के लिए अद्यतन प्रश्न देखें। –

+0

@ हैरी: उत्तर भी अपडेट किया गया। – Vlad

4

TPL के साथ आप उपयोग कर सकते हैं StaTaskScheduler from the TPL Extras

यह एसटीए धागे पर कार्य चलेंगे।

केवल COM के लिए इसका इस्तेमाल किया गया। कभी भी कई यूआई धागे चलाने की कोशिश नहीं की।

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

  • कोई संबंधित समस्या नहीं^_^