มีรูปแบบที่เป็นทางการที่ดีในการจัดการสถานะใน MVVM หรือไม่?


21

ฉันเริ่มเรียนรู้เกี่ยวกับ Redux และ React ในเว็บโลกและยิ่งฉันเรียนรู้มากเท่าไหร่ฉันก็ยิ่งรู้ว่าการจัดการสถานะเจ็บปวดในเดสก์ท็อปโลกด้วยสถาปัตยกรรมสไตล์ MVVM ของ WPF (โดยใช้ Caliburn โดยเฉพาะเพื่อผูกมัด Views ไปยัง ViewModels)

Redux มีหลักการง่ายๆสองสามข้อที่บอกให้ทราบว่ารัฐควรจัดการอย่างไรการปรับปรุง UI การจัดการเหตุการณ์และการเปลี่ยนแปลงสถานะสามารถคาดการณ์ได้มากขึ้น หลักการคือ:

  • แหล่งความจริงเดียว (สถานะที่ไม่แน่นอนทั้งหมดจะถูกเก็บไว้ในวัตถุที่ใช้ร่วมกันเดียว)
  • สถานะเป็นแบบอ่านอย่างเดียว มันไม่สามารถแก้ไขได้โดยส่วนประกอบผ่านรหัสซึ่งมักจะเกิดขึ้นใน WPF
  • สถานะสามารถแก้ไขได้โดยฟังก์ชันบริสุทธิ์เท่านั้น

สถาปัตยกรรม MVVM ของ WPF ช่วยให้คุณสามารถสร้างมุมมองแบบโต้ตอบได้อย่างรวดเร็ว แต่การดีบักปัญหาเมื่อ viewmodels และเหตุการณ์ต่าง ๆ เปลี่ยนสถานะทั้งหมดเป็นฝันร้าย ตัวอย่างเช่นเหตุการณ์ที่ทำให้เกิดการเปลี่ยนแปลงมุมมองและพยายามตั้งค่าแท็บเริ่มต้น แต่ข้อมูลยังไม่เสร็จสิ้นการโหลดแบบอะซิงโครนัสจากเว็บเซอร์วิสดังนั้นแท็บจึงไม่มีอยู่ (ยัง) จึงไม่มีอะไรเกิดขึ้น

ฉันใช้เวลาหลายชั่วโมงในการวาดไดอะแกรมเพื่อลองและทำความเข้าใจกับการโต้ตอบที่ซับซ้อนระหว่างองค์ประกอบ viewModels ที่เกี่ยวกับอินเตอร์ที่อัปเดตกัน

ฉันเข้าใจว่า Redux ตั้งเป้าหมายที่จะแก้ปัญหาความไม่แน่นอนในเรื่องนี้ มีบางอย่างที่คล้ายกันหรือรูปแบบสถาปัตยกรรมที่เหมาะกับ WPF เพื่อช่วยจัดการสถานะให้ดีขึ้นหรือไม่? ฉันไม่แน่ใจว่าหลักการ Redux จะทำงานได้ดีเพียงใดใน. NET เนื่องจากฉันยังไม่ได้ลองใช้ บางทีใครบางคนอาจมีประสบการณ์ที่สามารถให้คำแนะนำได้บ้าง?


เรามีปัญหาคล้ายกันในเบราว์เซอร์ จาวาสคริปต์ที่ตรงไปตรงมาจะทำงานเร็วและ DOM ยังไม่ได้สร้างดังนั้นจึงไม่สามารถหาองค์ประกอบ UI ใด ๆ ได้ โชคดีที่มีจำนวนของกิจกรรมเราสามารถใช้เพื่อเรียกการทำงานของสคริปต์บางอย่างล่าช้าจนกว่าสิ่งอื่น ๆ จะพร้อมต่อไป (เช่น DOMContentLoaded)
Erik Eidt

1
สถานะใน redux มีการปรับปรุงจริงไม่เคยแก้ไข
Andy

1
ฉันรู้ว่าฉันมางานปาร์ตี้ช้า แต่มีโครงการที่เรียกว่าReact.NETที่นำสถาปัตยกรรม Redux มาสู่. NET
SiberianGuy

สำหรับผู้ที่ชอบวิธีการของngrx / ร้านค้าในโครงการเชิงมุมมีNetRx.Store - การจัดการของรัฐสำหรับโครงการ. Net แรงบันดาลใจจาก ngrx / ร้านค้า คุณสามารถค้นหาได้ที่Nugetเช่นกัน นอกจากนี้ยังมีตัวอย่างการใช้งานที่ดีNetRx.Store ด้วยรูปแบบ MVVM ในโครงการ WPF
Vitalii Ilchenko

คำตอบ:


8

ฉันคิดว่าฉันรู้ว่าคุณหมายถึงอะไร โดยทั่วไปคุณแก้ปัญหาด้วยการเพิ่มมุมมอง 'คอนโทรลเลอร์' หรือ 'ต้นแบบ' (แก้ตัว psudocode)

กล่าวคือ

public class MasterVM
{
    public ChildVM View1 {get;set;}
    public ChildVM View2 {get;set;}

    private Data data;
    public MasterVM()
    {
        View1.OnEvent += updateData;
    }

    private Action<int> updateData(int value)
    {
         View2.Value = value;
    }
}

เมื่อคุณทำสิ่งนี้ด้วยรูปแบบสื่อกลางฉันคิดว่าคลาสนั้นเป็นตัวควบคุม กล่าวคือ

public class Controller
{
    public Controller(MediatorService m)
    {
        m.Subscribe("valueupdated", updateData);
    }

    private Action<int> updateData(int value)
    {
         m.Publish("showvalue", value);
    }
}

public class View2
{
    public View2(MediatorService m)
    {
        m.Subscribe("showvalue", (int v)=> {Value = v;});
    }
}

สิ่งนี้ช่วยให้คุณใส่ 'flow logic' หรือ Event Orchestration ของคุณในคลาสที่ยังคงอยู่ระดับสูงเหล่านี้และทำให้ไฟโค้ด VMs คงอยู่ หากคุณต้องการเปลี่ยน 'เมื่อผู้ใช้คลิกซื้อคำสั่งซื้อจะถูกประมวลผล' ชนิดของสิ่งที่คุณรู้ว่าจะดูใน 'OrderFlowController' หรือ 'OrderProcessVM' หรืออย่างไรก็ตามคุณต้องการตั้งชื่อพวกเขา แทนที่จะเป็นการรวมกันของ BasketVM, PaymentVM, 3dSecureVM ฯลฯ

ดังนั้นในตัวอย่างเฉพาะของคุณ 'แท็บยังไม่พร้อม' คุณอาจมี

public class Controller
{
    bool dataLoadCompleted;
    public Controller(MediatorService m)
    {
        m.Subscribe("setTabRequest", setTab); //message from view model with set tab button
        m.Subscribe("dataLoadComplete", dataLoadComplete); //message from data loading view model or some other controller?
    }

    private Action<int> setTab(int value)
    {
         if(!dataLoadCompleted)
         {
             m.Publish("error", "Please wait for data to load"); //message for error alert view model
         }
         else
         {
             m.Publish("setDefaultTab", value); //message for tab viewmodel
         }
    }

    private Action dataLoadComplete()
    {
         //persist state;
         dataLoadCompleted = true;
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.