في فبراير 2019 ، تم إصدار
ReactiveUI 9 ، إطار عمل عبر الأنظمة الأساسية لإنشاء تطبيقات واجهة المستخدم الرسومية على نظام Microsoft .NET الأساسي.
ReactiveUI هو أداة لدمج ملحقات رد الفعل بإحكام مع نمط تصميم MVVM. يمكن البدء في التعرف على الإطار من خلال
سلسلة من المقالات حول Habré أو
من الصفحة الأولى للوثائق . يتضمن تحديث ReactiveUI 9 العديد من
الإصلاحات والتحسينات ، ولكن ربما يكون التغيير الأكثر إثارة للاهتمام والأهم هو
التكامل الدقيق مع إطار DynamicData ، والذي يسمح بالعمل مع تغيير المجموعات بأسلوب تفاعلي. دعونا نحاول معرفة الحالات التي يمكن أن تأتي
DynamicData فيها بسهولة وكيف يتم ترتيب هذا الإطار التفاعلي القوي في الداخل!
الشروط
أولاً ، نحدد نطاق المهام التي
تحلها DynamicData ونكتشف لماذا لا تناسبنا الأدوات القياسية للعمل مع تغيير مجموعات البيانات من مساحة الاسم
System.Collections.ObjectModel
.
يتضمن قالب MVVM ، كما تعلمون ، تقسيم المسؤولية بين طبقات النموذج وعرض النموذج التقديمي للتطبيق. يتم تمثيل طبقة النموذج بواسطة كيانات وخدمات المجال ، ولا تعرف شيئًا عن نموذج العرض التقديمي. تقوم طبقة النموذج بتغليف منطق التطبيق المعقد بالكامل ، ويفوض نموذج العرض عمليات النموذج ، مما يتيح للعرض إمكانية الوصول إلى المعلومات حول الحالة الحالية للتطبيق من خلال الخصائص والأوامر والمجموعات القابلة للملاحظة. الأداة القياسية للعمل مع تغيير الخصائص هي واجهة
INotifyPropertyChanged
و
INotifyPropertyChanged
للعمل مع إجراءات المستخدم و
INotifyCollectionChanged
لتنفيذ المجموعات وتنفيذ
ObservableCollection
و
ReadOnlyObservableCollection
.

عادة ما يظل تطبيق
INotifyPropertyChanged
و
ICommand
على ضمير المطور وإطار عمل MVVM المستخدم ، لكن استخدام
ObservableCollection
يفرض عددًا من القيود علينا! على سبيل المثال ، لا يمكننا تغيير مجموعة من مؤشر ترابط الخلفية دون
Dispatcher.Invoke
أو مكالمة مماثلة ، وقد يكون ذلك مفيدًا في حالة العمل مع صفائف البيانات التي تتم مزامنتها في الخلفية مع عملية الخادم. تجدر الإشارة إلى أنه في MVVM الاصطلاحية ، لا تحتاج طبقة النموذج إلى معرفة بنية تطبيق واجهة المستخدم الرسومية المستخدمة ، وتكون متوافقة مع النموذج من MVC أو MVP ، وهذا هو السبب في أن العديد من
Dispatcher.Invoke
يسمح بالوصول إلى التحكم في واجهة المستخدم من مؤشر ترابط الخلفية قيد التشغيل في خدمة المجال ، تنتهك مبدأ تقاسم المسؤولية بين طبقات التطبيق.
بالطبع ، في خدمة المجال سيكون من الممكن إعلان حدث ، وكحجة لحدث ما ، تمرير قطعة مع البيانات التي تم تغييرها. ثم قم بالاشتراك في الحدث ، قم بلف
Dispatcher.Invoke
استدعاء في واجهة بحيث لا يعتمد على إطار واجهة المستخدم الرسومية المستخدم ، انقل
Dispatcher.Invoke
إلى نموذج العرض التقديمي وتغيير
ObservableCollection
الحاجة ، ولكن هناك طريقة أكثر بساطة وأكثر أناقة لحل مجموعة المهام المشار إليها دون الحاجة إلى كتابة دراجة . لنبدأ الدراسة!
ملحقات رد الفعل. إدارة تدفقات البيانات
للحصول على فهم كامل
للتجارب التي قدمتها
DynamicData ومبادئ العمل مع تغيير مجموعات البيانات التفاعلية ، دعونا نتذكر
ماهية البرمجة التفاعلية وكيفية تطبيقها في سياق نظام Microsoft .NET ونمط تصميم MVVM . طريقة لتنظيم التفاعل بين مكونات البرنامج يمكن أن تكون تفاعلية وتفاعلية. في التفاعل التفاعلي ، تستقبل وظيفة المستهلك بشكل متزامن البيانات من وظيفة الموفر (النهج القائم على السحب ،
T
،
IEnumerable
) ، وفي التفاعل التفاعلي ، تقوم وظيفة المستهلك بتسليم البيانات بشكل غير متزامن إلى وظيفة المستهلك (النهج القائم على الدفع ،
Task
،
IObservable
).
البرمجة التفاعلية هي البرمجة باستخدام تدفقات البيانات غير المتزامنة ، والإضافات التفاعلية هي حالة خاصة من تنفيذها ، استنادًا إلى
IObservable
و
IObserver
من مساحة اسم النظام ، والتي تحدد عددًا من العمليات المشابهة لـ LINQ على الواجهة
IObservable
، والتي تسمى LINQ over Observable. تدعم الملحقات التفاعلية Standard .NET وتعمل أينما تعمل منصة Microsoft .NET.

يدعو إطار ReactiveUI مطوري التطبيقات إلى الاستفادة من التطبيق التفاعلي لـ
ICommand
و
INotifyPropertyChanged
، مما يوفر أدوات قوية مثل
ReactiveCommand<TIn, TOut>
و
WhenAnyValue
.
WhenAnyValue
يتيح
WhenAnyValue
تحويل خاصية لفئة تنفذ INotifyPropertyChanged إلى دفق حدث من النوع
IObservable<T>
، مما يبسط تطبيق الخصائص التابعة.
public class ExampleViewModel : ReactiveObject { [Reactive]
يتيح لك
ReactiveCommand<TIn, TOut>
العمل مع الأمر كما هو الحال مع حدث من النوع
IObservable<TOut>
، والذي يتم نشره عندما يكمل الأمر التنفيذ. أيضًا ، يحتوي أي أمر على خاصية
ThrownExceptions
من النوع
IObservable<Exception>
.
طوال هذا الوقت ، عملنا مع
IObservable<T>
، كما هو الحال مع حدث ينشر قيمة جديدة من النوع
T
كلما تغيرت حالة الكائن الذي تتم مراقبته. ببساطة ،
IObservable<T>
هو دفق من الأحداث ، تسلسل ممتد عبر الوقت.
بالطبع ، يمكننا العمل مع المجموعات بنفس السهولة والطبيعية - عندما تتغير المجموعة ، ننشر مجموعة جديدة تحتوي على عناصر تم تغييرها. في هذه الحالة ، ستكون القيمة المنشورة من النوع
IEnumerable<T>
أو أكثر تخصصًا ، وسيكون الحدث نفسه من النوع
IObservable<IEnumerable<T>>
. ولكن ، كما يشير قارئ التفكير الناقد بشكل صحيح ، فإن هذا محفوف بالمشاكل الخطيرة في أداء التطبيق ، خاصة إذا لم يكن هناك أكثر من عشرة عناصر في مجموعتنا ، ولكن هناك مئات ، أو حتى عدة آلاف!
مقدمة في DynamicData
DynamicData هي مكتبة تتيح لك استخدام القوة الكاملة للملحقات التفاعلية عند العمل مع المجموعات. لا توفر الملحقات التفاعلية خارج الصندوق أفضل الطرق للعمل مع تغيير مجموعات البيانات ، وتتمثل
مهمة DynamicData في إصلاحها. في معظم التطبيقات ، هناك حاجة إلى تحديث المجموعات ديناميكيًا - عادةً ما يتم تعبئة المجموعة ببعض العناصر عند بدء تشغيل التطبيق ، ثم يتم تحديثه بشكل غير متزامن ، مع مزامنة المعلومات مع خادم أو قاعدة بيانات. التطبيقات الحديثة معقدة للغاية ، وغالباً ما تكون هناك حاجة لإنشاء توقعات المجموعات - تصفية العناصر أو تحويلها أو فرزها. تم تصميم DynamicData فقط للتخلص من التعليمات البرمجية المعقدة بشكل لا يصدق التي سنحتاج إليها لإدارة مجموعات البيانات المتغيرة ديناميكيًا. تم تطوير الأداة بشكل نشط ووضع اللمسات الأخيرة عليها ، ويدعم الآن أكثر من 60 مشغلًا للعمل مع المجموعات.
DynamicData ليس تطبيقًا بديلًا لـ
ObservableCollection<T>
. تعتمد بنية
DynamicData أساسًا على مفاهيم البرمجة الخاصة بالمجال. تستند أيديولوجية الاستخدام إلى حقيقة أنك تدير بعض مصادر البيانات ، وهي مجموعة يمكن الوصول إليها من خلال الكود المسؤول عن مزامنة وتغيير البيانات. بعد ذلك ، تقوم بتطبيق عدد من العوامل على المصدر ، والتي يمكنك من خلالها تحويل البيانات بشكل تعريفي ، دون الحاجة إلى إنشاء مجموعات أخرى وتعديلها يدويًا. في الواقع ، مع
DynamicData يمكنك فصل عمليات القراءة والكتابة ، ويمكنك فقط القراءة بطريقة رد الفعل - لذلك ، ستتم دائمًا مزامنة المجموعات الموروثة مع المصدر.
بدلاً من
IObservable<T>
الكلاسيكية
IObservable<T>
، تحدد DynamicData العمليات على
IObservable<IChangeSet<T>>>
و
IObservable<IChangeSet<TValue, TKey>>
، حيث
IChangeSet
عبارة عن قطعة تحتوي على معلومات حول تغيير المجموعة - نوع التغيير والعناصر التي تأثرت. يمكن لهذا النهج تحسين أداء الكود بشكل ملحوظ للعمل مع المجموعات المكتوبة بأسلوب تفاعلي. في الوقت نفسه ، يمكن دائمًا تحويل
IObservable<IChangeSet<T>>
إلى
IObservable<IEnumerable<T>>
دائمًا إذا أصبح من الضروري معالجة جميع عناصر المجموعة دفعة واحدة. إذا بدا الأمر معقدًا - فلا تشعر بالقلق ، من أمثلة الكود سوف يصبح كل شيء واضحًا وشفافًا!
مثال DynamicData
دعونا نلقي نظرة على سلسلة من الأمثلة لفهم كيفية عمل DynamicData بشكل أفضل ، وكيف يختلف عن
System.Reactive
والمهام التي يمكن للمطورين العاديين لبرنامج التطبيق باستخدام واجهة المستخدم الرسومية حلها. لنبدأ بمثال شامل
نشرته DynamicData على جيثب . في المثال ، مصدر البيانات هو
SourceCache<Trade, long>
، والذي يحتوي على مجموعة من المعاملات. تتمثل المهمة في إظهار المعاملات النشطة فقط ، وتحويل النماذج إلى كائنات وكيل ، وفرز المجموعة.
في المثال أعلاه ، عندما تقوم بتغيير
SourceCache
، وهو مصدر البيانات ، فإن
ReadOnlyObservableCollection
تتغير أيضًا وفقًا لذلك. في هذه الحالة ، عند حذف العناصر من المجموعة ، سيتم استدعاء طريقة
Dispose
، وسيتم دائمًا تحديث المجموعة فقط في دفق واجهة المستخدم الرسومية وتبقى مرتبة ومرشحة. بارد ، لا
Dispatcher.Invoke
ورمز معقدة!
SourceList و SourceCache مصادر البيانات
توفر
DynamicData مجموعتين متخصصتين يمكن استخدامهما كمصدر بيانات قابل للتغيير. هذه المجموعات هي من أنواع
SourceList
و
SourceCache<TObject, TKey>
. يوصى باستخدام
SourceCache
كلما كان مفتاح
TObject
فريدًا ، وإلا استخدم
SourceList
. توفر هذه الكائنات واجهة برمجة التطبيقات لمطوري .NET المألوفين لتعديل البيانات -
Add
،
Remove
،
Insert
وما شابه. لتحويل مصادر البيانات إلى
IObservable<IChangeSet<T>>
أو
IObservable<IChangeSet<T, TKey>>
، استخدم عامل التشغيل
IObservable<IChangeSet<T, TKey>>
.Connect()
. على سبيل المثال ، إذا كان لديك خدمة تقوم بتحديث مجموعة العناصر في الخلفية ، فيمكنك مزامنة قائمة هذه العناصر بسهولة مع واجهة المستخدم الرسومية ، دون
Dispatcher.Invoke
والتجاوزات المعمارية:
public class BackgroundService : IBackgroundService {
تستخدم
DynamicData أنواع .NET مضمنة لتعيين البيانات إلى العالم الخارجي. باستخدام مشغلات DynamicData القوية ، يمكننا تحويل
IObservable<IChangeSet<Trade>>
إلى
ReadOnlyObservableCollection
طراز العرض الخاص بنا.
public class TradesViewModel : ReactiveObject { private readonly ReadOnlyObservableCollection<TradeVm> _trades; public ReadOnlyObservableCollection<TradeVm> Trades => _trades; public TradesViewModel(IBackgroundService background) {
بالإضافة إلى
Transform
و
Filter
و
Sort
، تتضمن DynamicData مجموعة من العوامل الأخرى ، وتدعم التجميع ، والعمليات المنطقية ، وتنعيم المجموعة ، باستخدام وظائف التجميع ، باستثناء العناصر المتطابقة ، وعناصر الفرز ، وحتى الافتراضية على مستوى نموذج التمثيل. اقرأ المزيد عن جميع المشغلين في
مشروع README على جيثب .

مجموعات مترابطة واحدة وتغيير التتبع
بالإضافة إلى
SourceList
و
SourceCache
، تتضمن مكتبة DynamicData أيضًا
SourceCache
وحيدًا لمجموعة قابلة للتغيير -
ObservableCollectionExtended
. لمزامنة مجموعتين في نموذج العرض الخاص بك ، قم بتعريف أحدهما كـ
ObservableCollectionExtended
والآخر مثل
ReadOnlyObservableCollection
واستخدم عامل التشغيل
ToObservableChangeSet
، الذي يتصرف بنفس طريقة
Connect
، ولكنه مصمم للعمل مع
ObservableCollection
.
يدعم
DynamicData أيضًا تعقب التغييرات في الفئات التي تقوم
INotifyPropertyChanged
واجهة
INotifyPropertyChanged
. على سبيل المثال ، إذا كنت تريد أن يتم إعلامك بتغيير المجموعة كلما تغيرت خاصية لعنصر ما ، استخدم
AutoRefresh
وتمرير محدد الخاصية المرغوبة باستخدام الوسيطة. سيسمح لك
AutoRefesh
وغيره من مشغلي DynamicData بالتحقق من صحة عدد ضخم من النماذج والنماذج المتداخلة المعروضة على الشاشة بسهولة وبشكل طبيعي.
استنادًا إلى وظيفة DynamicData ، يمكنك إنشاء واجهات معقدة إلى حد ما - وهذا ينطبق بشكل خاص على الأنظمة التي تعرض قدرًا كبيرًا من البيانات في الوقت الفعلي وأنظمة المراسلة الفورية وأنظمة المراقبة.

استنتاج
الامتدادات التفاعلية هي أداة قوية تتيح لك العمل بشكل تعريفي مع البيانات وواجهة المستخدم ، وكتابة التعليمات البرمجية المحمولة والمدعومة ، وحل المشكلات المعقدة بطريقة بسيطة وأنيقة. يسمح
ReactiveUI لمطوري .NET بدمج ملحقات التفاعل عن كثب في مشاريعهم باستخدام بنية MVVM من خلال توفير تطبيقات تفاعلية لـ
INotifyPropertyChanged
و
ICommand
، في حين أن
DynamicData تهتم بمزامنة التجميع من خلال تطبيق
INotifyCollectionChanged
، مما يوسع من قدرات ملحقات
INotifyCollectionChanged
على الأداء.
تتوافق
مكتبات ReactiveUI و
DynamicData مع أطر عمل واجهة المستخدم الرسومية الأكثر شعبية في نظام .NET ، بما في ذلك Windows Presentation Foundation و Universal Windows Platform و
Avalonia و Xamarin.Android و Xamarin Forms و Xamarin.iOS. يمكنك البدء في تعلم DynamicData من
صفحة وثائق ReactiveUI المقابلة . تأكد أيضًا من مراجعة مشروع
DynamicData Snippets ، الذي يحتوي على أمثلة لاستخدام DynamicData لجميع المناسبات.