2013-01-20 38 views
8

मेरे पास विंडोज फोन 8 पर चल रहा एक एमवीवीएम क्रॉस एप्लिकेशन है जिसे मैंने हाल ही में पोर्टेबल क्लास लाइब्रेरीज़ का उपयोग करने के लिए पोर्ट किया है।पोर्टेबल क्लास लाइब्रेरी से यूआई थ्रेड अपडेट करें

दृश्य मॉडल पोर्टेबल क्लास लाइब्रेरी के भीतर हैं और उनमें से एक ऐसी संपत्ति का खुलासा करता है जो डेटा बाध्यकारी के माध्यम से WP टूलकिट के लिए सिल्वरलाइट से PerformanceProgressBar को सक्षम और अक्षम करता है।

जब उपयोगकर्ता एक बटन दबाता है तो रिलेकॉमैंड पृष्ठभूमि प्रक्रिया को बंद कर देता है जो संपत्ति को सत्य पर सेट करता है जो प्रगति पट्टी को सक्षम करता है और पृष्ठभूमि प्रसंस्करण करता है।

इससे पहले कि मैंने इसे पीसीएल पर पोर्ट किया था, मैं यूआई थ्रेड से परिवर्तन को लागू करने में सक्षम था ताकि प्रगति बार सक्षम हो सके, लेकिन डिस्पैचर ऑब्जेक्ट पीसीएल में उपलब्ध नहीं है। मैं इसके आसपास कैसे काम कर सकता हूं?

धन्यवाद

दान

+1

मुझे जीत-फोन में पूरी तरह से यकीन नहीं है, लेकिन क्या आप अपडेट का आह्वान करने के लिए 'Application.Current.Dispatcher' का उपयोग कर सकते हैं? या यह 'परिनियोजन होगा। वर्तमान। डिस्पैचर '? –

उत्तर

12

आप डिस्पैचर के लिए पहुँच नहीं है, तो आप सिर्फ अपने वर्ग के लिए BeginInvoke विधि के एक प्रतिनिधि पारित कर सकते हैं:

public class YourViewModel 
{ 
    public YourViewModel(Action<Action> beginInvoke) 
    { 
     this.BeginInvoke = beginInvoke; 
    } 

    protected Action<Action> BeginInvoke { get; private set; } 

    private void SomeMethod() 
    { 
     this.BeginInvoke(() => DoSomething()); 
    } 
} 

तो यह instanciate को (एक वर्ग से जिसमें प्रेषक तक पहुंच है):

var dispatcherDelegate = action => Dispatcher.BeginInvoke(action); 

var viewModel = new YourViewModel(dispatcherDelegate); 

या आप अपने प्रेषक के चारों ओर एक रैपर भी बना सकते हैं।

पहले, अपने पोर्टेबल वर्ग पुस्तकालय में एक IDispatcher इंटरफेस को परिभाषित:

public interface IDispatcher 
{ 
    void BeginInvoke(Action action); 
} 

फिर, परियोजना जो डिस्पैचर की पहुंच है में, लागू इंटरफ़ेस:

public class DispatcherWrapper : IDispatcher 
{ 
    public DispatcherWrapper(Dispatcher dispatcher) 
    { 
     this.Dispatcher = dispatcher; 
    } 

    protected Dispatcher Dispatcher { get; private set; } 

    public void BeginInvoke(Action action) 
    { 
     this.Dispatcher.BeginInvoke(action); 
    } 
} 

तो फिर तुम सिर्फ कर सकते हैं इस पोर्टेबल क्लास लाइब्रेरी में इस ऑब्जेक्ट को आईडीस्पैचर उदाहरण के रूप में पास करें।

+0

यह एक व्यवहार्य दृष्टिकोण है - और मूल रूप से यह वास्तव में एमवीवीएमक्रॉस करता है - केवल यह प्लेटफ़ॉर्म सेटअप स्तर पर आईओसी का उपयोग करता है – Stuart

+0

धन्यवाद - यह मेरे लिए काम करता है! –

+0

आपका कॉल ... लेकिन, यदि आप एमवीवीएमक्रॉस का उपयोग कर रहे हैं, तो आपको शायद 'InvokeOnMainThread (action)' का उपयोग करके देव को आसानी से मिल जाएगा - क्योंकि यह आपको प्रत्येक प्लेटफ़ॉर्म पर पूर्व-निर्मित कार्यान्वयन प्रदान करेगा (और इसमें ' प्रत्येक आमंत्रण से पहले चेकएप() 'कॉल) – Stuart

15

सभी MvvmCross प्लेटफार्मों की आवश्यकता है कि यूआई-कार्यों यूआई धागा/अपार्टमेंट के लिए पीठ पर मार्शल हो - लेकिन एक मंच इस अलग ढंग से करता है ....

इस हल करने के लिए, MvvmCross एक पार मंच तरीका प्रदान करता है ऐसा करने के लिए - एक IMvxViewDispatcherProvider इंजेक्शन ऑब्जेक्ट का उपयोग करना।

उदाहरण के लिए, WindowsPhone IMvxViewDispatcherProvider पर अंततः MvxMainThreadDispatcher द्वारा https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross.WindowsPhone/Views/MvxMainThreadDispatcher.cs

में प्रदान की जाती है यह InvokeOnMainThread लागू करता है का उपयोग करते हुए:

private bool InvokeOrBeginInvoke(Action action) 
    { 
     if (_uiDispatcher.CheckAccess()) 
      action(); 
     else 
      _uiDispatcher.BeginInvoke(action); 

     return true; 
    } 

कोड के लिए ViewModels में:

  • अपने ViewModel inherits MvxNotifyPropertyChanged वस्तु एक MvxNotifyPropertyChanged
  • से MvxViewModel
  • MvxViewModel inherits एक MvxApplicationObject
  • MvxApplicationObject inherits से से एक MvxMainThreadDispatchingObject

MvxMainThreadDispatchingObject से विरासत https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxMainThreadDispatchingObject.cs

public abstract class MvxMainThreadDispatchingObject 
    : IMvxServiceConsumer<IMvxViewDispatcherProvider> 
{ 
    protected IMvxViewDispatcher ViewDispatcher 
    { 
     get { return this.GetService().Dispatcher; } 
    } 

    protected void InvokeOnMainThread(Action action) 
    { 
     if (ViewDispatcher != null) 
      ViewDispatcher.RequestMainThreadAction(action); 
    } 
} 

तो है ... आपकै विचार मॉडल सिर्फ नोट करने के लिए InvokeOnMainThread(() => DoStuff());


एक आगे की बात कॉल कर सकते हैं कि MvvmCross स्वचालित रूप से RaisePropertyChanged() तरीकों के माध्यम से जो (किसी भी MvxNotifyPropertyChanged वस्तु में या वास्तव में) में एक MvxViewModel संकेत कर रहे हैं संपत्ति अद्यतन के लिए यूआई धागा रूपांतरण करता है - देखें:

protected void RaisePropertyChanged(string whichProperty) 
    { 
     // check for subscription before going multithreaded 
     if (PropertyChanged == null) 
      return; 

     InvokeOnMainThread(
      () => 
       { 
        var handler = PropertyChanged; 

        if (handler != null) 
         handler(this, new PropertyChangedEventArgs(whichProperty)); 
       }); 
    } 
https://github.com/slodge/MvvmCross/blob/vnext/Cirrious/Cirrious.MvvmCross/ViewModels/MvxNotifyPropertyChanged.cs


इस में

RaisePropertyChanged() कॉल की स्वचालित मार्शलिंग अधिकांश स्थितियों के लिए अच्छी तरह से काम करती है, लेकिन यदि आप पृष्ठभूमि थ्रेड से बहुत से बदले गए गुणों को बढ़ाते हैं तो यह थोड़ा अक्षम हो सकता है - इससे बहुत सारे थ्रेड संदर्भ स्विचिंग हो सकते हैं। यह कुछ आप अपने कोड के अधिकांश में के बारे में पता होने की जरूरत नहीं है - लेकिन अगर आप कभी भी यह एक समस्या है, तो इसे बदलने के लिए मदद कर सकते हैं कोड की तरह:

MyProperty1 = newValue1; 
MyProperty2 = newValue2; 
// ... 
MyProperty10 = newValue10; 

रहे हैं:

InvokeOnMainThread(() => { 
     MyProperty1 = newValue1; 
     MyProperty2 = newValue2; 
     // ... 
     MyProperty10 = newValue10; 
}); 

क्या तुमने कभी ObservableCollection उपयोग करते हैं, तो कृपया ध्यान दें MvvmCross करता है कि नहींINotifyPropertyChanged या INotifyCollectionChanged घटनाओं इन कक्षाओं से निकाल दिया के लिए प्राथमिकता निर्धारण किसी भी धागा करते हैं - तो यह मार्शल के लिए इन परिवर्तनों एक डेवलपर के रूप आप पर निर्भर है ।

कारण: ObservableCollection एमएस और मोनो कोड बेस में मौजूद है - इसलिए कोई आसान तरीका नहीं है कि एमवीएमक्रॉस इन मौजूदा कार्यान्वयन को बदल सकता है।

1

एक और विकल्प जो आसान हो सकता है, अपने वर्ग के निर्माता में सिंक्रनाइज़ेशन कॉन्टेक्स्ट.क्यूरेंट का संदर्भ संग्रहीत करना है। फिर, बाद में, आप संदर्भ पर आह्वान करने के लिए _context.Post (() => ...) का उपयोग कर सकते हैं - जो WPF/WinRT/SL में UI थ्रेड है।

class MyViewModel 
{ 
    private readonly SynchronizationContext _context; 
    public MyViewModel() 
    { 
     _context = SynchronizationContext.Current. 
    } 

    private void MyCallbackOnAnotherThread() 
    { 
     _context.Post(() => UpdateTheUi()); 
    } 
}