ما الذي يسبب WPF ListCollectionView الذي يستخدم الفرز المخصص لإعادة تخطيط عناصره؟

StackOverflow https://stackoverflow.com/questions/601864

  •  03-07-2019
  •  | 
  •  

سؤال

ضع في اعتبارك هذا الرمز (اكتب الأسماء العامة لأغراض المثال):

// Bound to ListBox.ItemsSource
_items = new ObservableCollection<Item>();

// ...Items are added here ...

// Specify custom IComparer for this collection view
_itemsView = CollectionViewSource.GetDefaultView(_items)
((ListCollectionView)_itemsView).CustomSort = new ItemComparer();

عندما ضبطت CustomSort, ، يتم فرز المجموعة كما أتوقع.

ومع ذلك ، فإنني أطلب من البيانات إعادة توصيل نفسها في وقت التشغيل استجابةً لتغيير الخصائص على Item. ال Item فئة مستمدة من INotifyPropertyChanged وأنا أعلم أن الخاصية تطلق النار بشكل صحيح حيث يقوم قالب البيانات الخاص بي بتحديث القيم على الشاشة ، فقط لا يتم استدعاء منطق الفرز.

لقد حاولت أيضا رفع INotifyPropertyChanged.PropertyChanged تمرير سلسلة فارغة ، لمعرفة ما إذا كان الإخطار العام سيؤدي إلى بدء الفرز. لا موز.

تعديل استجابةً لاقتراح كينت ، اعتقدت أنني سأشير إلى أن فرز العناصر باستخدام هذا له نفس النتيجة ، أي أن المجموعة تهز مرة واحدة ولكن لا إعادة البيع مع تغير البيانات:

_itemsView.SortDescriptions.Add(
    new SortDescription("PropertyName", ListSortDirection.Ascending));
هل كانت مفيدة؟

المحلول

وجدت هذا المقال للدكتور WPF الذي يبدأ بإجابة على سؤالي ، ثم ينتقل لمناقشة تأثير أداء الاتصال Refresh. بعض المقتطفات الرئيسية:

لسوء الحظ ، تؤدي طريقة التحديث () إلى تجديد كامل للعرض. عند حدوث تحديث () في العرض ، فإنه يرفع إشعارًا محملاً ويوفر الإجراء كـ "إعادة تعيين". يتلقى itemContainerGenerator لـ ListBox هذا الإشعار ويستجيب من خلال التخلص من جميع الصور المرئية الموجودة للعناصر. ثم يقوم تمامًا بتجديد حاويات العناصر الجديدة والمرئيات.

ثم يصف الحل البديل الذي يحسن الأداء. بدلاً من استدعاء التحديث ، قم بإزالة ، قم بتغيير العنصر.

كنت أعتقد أنه من الممكن أن تتبع طريقة عرض القائمة عنصرًا يتغير ويعرف إعادة وضع هذا العنصر وحده في العرض.

تم تقديم نهج جديد في .NET 3.5 SP1 تنطوي على الواجهة IEditableObject الذي يوفر تحرير المعاملات عبر روابط البيانات إلى القالب مع الأساليب BeginEdit(), CancelEdit(), ، و EndEdit(). اقرأ المقالة للمزيد من المعلومات.

تعديل كما user346528 يشير, IEditableObject لم يكن في الواقع جديد في 3.5SP1. يبدو في الواقع أنه كان في الإطار منذ 1.0.

نصائح أخرى

نظرًا لأن الإجابة المقبولة توجهني ، فأنا قادر على إجبار إعادة وضع العنصر الفردي باستخدام الكود

IEditableCollectionView collectionView = DataGrid.Items;

collectionView.EditItem(changedItem);
collectionView.CommitEdit();

أين changedItem هل عرض النموذج (العنصر في ItemsSource مجموعة).

وبهذه الطريقة لا تحتاج إلى عناصرك لتنفيذ أي واجهات مثل IEditableObject (والتي في رأيي لديها معقدة للغاية ويصعب تنفيذ العقد في بعض الحالات).

تصطدم منشور قديم ، ولكن فقط قم بعمل فئة تجميع جديدة ترث من ListViewCollection وتجاوز OnpropertyChanged (بالنسبة إلى IbindingList ، سوف تحتوي الأحداث على تغيير الممتلكات في معلمة ListChangedeventArgs). وتأكد من أن العناصر الموجودة في المجموعة تنفذ وتستخدم InotifyPropertyChange كلما تغيرت خاصية (تربى من قبلك) ، أو لن ترتبط المجموعة بتغييرات الممتلكات.

ثم في هذه الطريقة onpropertyChanged ، سيكون المرسل هو العنصر. قم بإزالة العنصر إذا-وفقط-خاصية من شأنها أن تتسبب في تغيير منتجع ، ثم أعد إضافةه (أدخله في موضع فرز إذا لم يضفه هذا بالفعل). من الأفضل نقل عنصر إذا كان متاحًا بدلاً من إزالته/إضافته. وبالمثل ، ينبغي أن يتم ذلك أيضًا مع التصفية (التحقق من مسند المرشح).

غير مطلوبة غير مطلوبة! إذا كنت ترغب في تحرير العديد من الخصائص ، ثم أنهي التحرير (مثل تحرير 3 خصائص ثم الاختيار على صف مختلف في WinForm DataGridView) ، ثم وجوده ، سيكون هذا هو الطريقة المناسبة للحصول على هذا العمل. ولكن في كثير من الأحيان ، ربما تريد أن تقوم المجموعة بالملاحفة بعد تغيير كل عقار دون الحاجة إلى الاتصال يدويًا. IedableBject ، راجع للشغل ، موجود في إطار .NET 2.0 وليس جديدًا على .NET 3.5 (إذا قرأت مقالة الدكتور).

ملاحظة: يمكن أن تحدث المشكلات باستخدام LeginedIt () و endedit () مع تعديلات متعددة لنفس العنصر-ما لم تكن الزيادة (للصواب)/الانخفاض (لخطأ) عدد صحيح بدلاً من تعيين منطقية! تذكر زيادة/انخفاض عدد صحيح لمعرفة حقًا عند الانتهاء من التحرير.

إن الاحتفاظ بقائمة مصنفة بشكل دائم تستغرق وقتًا طويلاً ومعرضًا للمرور (ويمكن أن تقسم عقد الإدراج إذا أجبرت الإدراج المصنفة) ، ويجب استخدامها فقط في أماكن معينة مثل comboBoxes. على أي شبكة ، هذه فكرة سيئة للغاية ، لأن تغيير الصف سيؤدي إلى الخروج من الموضع الحالي للمستخدمين.

Public Class ListView
  Inherits ListCollectionView

  Protected Overrides Sub OnPropertyChanged(sender As Object, e As PropertyChangedEventArgs)

    ' Add resorting/filtering logic here.
  End Sub
End Class

أفضل مثال على المجموعة التي تشبه ما تحتاجه هو Jesse Johnsons ObjectListView ، على الرغم من أن هذا هو .NET 2.0 محدد (IbindingList بدلاً من inotifyCollectionChanged/ObservableCollection/ListCollectionView) ويستخدم ترخيصًا مقيدًا للغاية. قد لا تزال مدونته ذات قيمة كبيرة في كيفية إنجاز هذا.

يحرر:

نسيت أن أضيف أن المرسل سيكون العنصر الذي تحتاجه إلى المنتجع ، و e.propertyname هو ما ستحتاج إلى استخدامه لتحديد ما إذا كان ضمن موصوصات SortDescription. إذا لم يكن الأمر كذلك ، فلن يؤدي التغيير إلى هذا العقار إلى حاجة إلى منتجع. إذا لم يكن e.propertyname شيئًا ، فهذا يشبه التحديث ، حيث قد تكون العديد من الخصائص قد تغيرت ويجب إجراء اللجوء.

لتحديد ما إذا كان يحتاج إلى ترشيح ، ما عليك سوى تشغيله من خلال المرشح ، وإزالته إذا لزم الأمر. التصفية أقل تكلفة بكثير من الفرز.

نأمل أن يكون مفيدًا ،

Tamusjroyce

بالنظر إلى أنك تستخدم الفرز المخصص ، لا توجد طريقة ل ListCollectionView لمعرفة المعايير التي يجب أن تؤدي إلى تحديث. لذلك ، ستحتاج إلى الاتصال Refresh() في المجموعة عرض نفسك.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top