MVVM Light DispatcherHelper วิธีที่ถูกต้องในการมัลติเธรดใน MVVM Light

วิธีที่แนะนำในการทำมัลติเธรดด้วย MVVM Light คืออะไร ฉันมีโมเดลที่มีคุณสมบัติบูลไม่ว่าง

 public bool Busy
    {
        get { return busy_; }
        set
        {
           Set(nameof(Busy), ref busy_, value, broadcast: true);
        }
    }

โมเดลมุมมองของฉันเผยแพร่โมเดลโดยตรงสำหรับมุมมอง (โมเดลนั้นสืบทอด ViewModelBase ของ MVVM Light) ดังนั้นมุมมองจึงเชื่อมโยงโดยตรงกับคุณสมบัติที่ไม่ว่างของโมเดล

ถ้าฉันเรียกโมเดลเสมอจากเธรด UI ทุกอย่างก็ดี แต่ถ้าฉันทำสิ่งต่อไปนี้ในโมเดลมุมมองของฉัน ดังนั้นมันอาจดำเนินการบนเธรดอื่น

Task.Factory.StartNew(() => 
{            
  model_.SomeFunctionThatWillSetBusyDuringItsExecution();
});

แน่นอนว่าไม่ว่างถูกตั้งค่าจากเธรดที่ไม่ใช่ UI จากนั้นการเชื่อมโยงล้มเหลวและแอปพลิเคชันขัดข้อง หากฉันใช้ Messenger ในตัวตั้งค่าคุณสมบัติ ดูเหมือนว่า Messenger จะไม่ส่งรหัสตัวจัดการ Messenger ไปยังเธรด UI โดยอัตโนมัติเช่นกัน

ฉันรู้ว่ามี DispatcherHelper ใน MVVM Light แต่สำหรับการเชื่อมโยงดูเหมือนจะไม่ช่วยอะไร ถ้าผมเปลี่ยนทรัพย์สินเป็น

    public bool Busy
    {
        get { return busy_; }
        set
        {
           DispatcherHelper.CheckBeginInvokeOnUI(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           });
        }
    }

ฉันยังคงได้รับข้อยกเว้นและแอปพลิเคชันขัดข้องเนื่องจากแหล่งที่มาที่เชื่อมโยงไม่ได้อยู่ในเธรดที่ถูกต้อง ดังนั้นคำถามของฉันจึงง่าย วิธีที่แนะนำในการทำมัลติเธรดเช่นนี้ใน MVVM Light คืออะไร

ฉันยังลองใช้ syncronizationContext ด้วย

           syncContext_.Post(() =>
           {
              Set(nameof(Busy), ref busy_, value, broadcast: true);
           }, null);

ใช้งานได้หากการโทรมาจากที่ไม่ใช่เธรด UI เสมอ หากการโทรนั้นมาจากเธรด UI อยู่แล้ว syncContext.Post จะส่งผลให้ฟังก์ชัน Set() จะไม่ถูกเรียกใช้จนกว่าโค้ดทั้งหมดในเมธอด ViewModel จะเสร็จสิ้น นั่นหมายความว่าสถานะไม่ว่างอาจไม่ได้รับการอัปเดตอย่างถูกต้องสำหรับโค้ดที่เหลือ ดังนั้นจึงไม่ใช่ทางออกที่ดีนัก

ฉันขอขอบคุณสำหรับความช่วยเหลือในหัวข้อนี้


person Johan    schedule 27.09.2018    source แหล่งที่มา
comment
ฉันคิดว่าปัญหาคือ Set accessor ของคุณไม่ควรดำเนินการดังกล่าว ฉันเชื่อว่ามีปัญหาการออกแบบที่นี่ IsBusy ของคุณควรตั้งค่าเป็น false/true ในบางเหตุการณ์/เงื่อนไขของวิธีเธรดของคุณ (ในเธรด UI) ด้วยวิธีนี้ คุณจะไม่ต้องกังวลกับ DispatcherHelper หรือปัญหาการเข้าถึงเธรดด้วยซ้ำ วิธีการของเธรดควรถูกแยกออกเสมอ และรายงานเฉพาะเงื่อนไขการเริ่มต้น/สิ้นสุด และการอัปเดตความคืบหน้า ซึ่งทั้งหมดนี้ควรเกิดขึ้นในเธรดหลัก/UI เสมอ   -  person Luishg    schedule 09.04.2019


คำตอบ (1)


แทนที่จะเพิ่มรหัส DispatcherHelper ภายในคุณสมบัติ ฉันเพิ่มมันในทุกที่ที่มีการแก้ไขคุณสมบัติ แล้วดูเหมือนว่าจะทำงานได้ดี

ปัญหาเดียว เนื่องจากหนึ่งในการส่งงานไปยังเธรด UI โค้ดใน ViewModel จะไม่ได้รับสถานะที่อัปเดตหากส่วนหนึ่งของวิธีโมเดลมุมมองทำงานบนเธรด UI แล้ว ฉันพบวิธีบังคับให้เธรด UI ประมวลผลคิว Messenger แม้ว่าจะตรวจสอบให้แน่ใจว่ามีสถานะ Busy ที่อัปเดตแล้ว มันไม่ใช่โซลูชันที่ดูดีที่สุด และมีแนวโน้มว่าจะมีผลกระทบต่อประสิทธิภาพที่ไม่ดีเนื่องจากการสลับบริบททั้งหมด แต่อย่างน้อยก็ใช้งานได้และเป็นบรรทัดเดียวที่เรียบง่าย

โค้ดเพื่อบังคับให้เธรด UI ประมวลผลข้อความทั้งหมดในคิว

  DispatcherHelper.UIDispatcher.Invoke(new Action(() => { }), DispatcherPriority.ContextIdle, null);

หากมีวิธีแก้ปัญหาที่เหมาะสมกว่านี้โปรดแจ้งให้เราทราบ ไม่เช่นนั้น ฉันจะตั้งสิ่งนี้เป็นคำตอบภายในไม่กี่วันต่อจากนี้

person Johan    schedule 27.09.2018