WPF ، كيفية إلغاء تعاملات معالجات بشكل صحيح عند مشاهدة مطعم Typedescriptor

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

سؤال

أنا أستخدم WPF ، وأحاول اتباع نمط MVVM. قرر فريقنا استخدام التحكم في بيانات DataGrid ، وأنا أواجه بعض الصعوبات في الحصول عليها لتناسب نمط MVVM.

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

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

تمكنت من العمل عندما أقوم بتعيين مصدر الصف بشكل صريح في CodeBehind للصفحة (وفي محاولتي الأولى في عرض النموذج باستخدام مرجع مباشر إلى العرض لحظة!)

المشكلة الأولى التي أواجهها ، هي كيفية القيام بذلك دون وجود المنطق في الكود خلف أو في ViewModel. كان الحل الخاص بي هو تمديد فئة DataGridControl وإضافة الكود التالي:

    private IDictionary<string, IList> _GridFilters = null;
    public MyDataGridControl() : base()
    {
        TypeDescriptor.GetProperties(typeof(MyDataGridControl))["ItemsSource"].AddValueChanged(this, new EventHandler(ItemsSourceChanged));
    }

    void ItemsSourceChanged(object sender, EventArgs e)
    {
        UnsetGridFilterChangedEvent();
        SetGridFilterChangedEvent();
    }

    public void SetGridFilterChangedEvent()
    {
        if (this.ItemsSource == null)
            return;

        DataGridCollectionView dataGridCollectionView = (DataGridCollectionView)this.ItemsSource;

        _GridFilters = dataGridCollectionView.AutoFilterValues;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            ((INotifyCollectionChanged)autofilterValues).CollectionChanged += FilterChanged;
        }
    }

    /*TODO: Possible memory leak*/
    public void UnsetGridFilterChangedEvent()
    {
        if (_GridFilters == null)
            return;

        foreach (IList autofilterValues in _GridFilters.Values)
        {
            INotifyCollectionChanged notifyCollectionChanged = autofilterValues as INotifyCollectionChanged;

            notifyCollectionChanged.CollectionChanged -= FilterChanged;
        }

        _GridFilters = null;
    }

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

هل أنا على حق في افتراض هذا؟ وهل يمكن لأي شخص التفكير في طريقة أفضل لإدارة هؤلاء المعالجات مع السماح لي بالحفاظ على هذه الوظيفة مغلفة في صفي الممتد؟

آسف على طول المنشور ، وشكرا مقدمًا على المساعدة!

-فونجر

هل كانت مفيدة؟

المحلول

أنت محق في أن القياس التلقائية للتأسيس ستتغير بالفعل في تلك المرحلة ، لذلك سوف تكون غير معالجات خاطئة ، مما يؤدي إلى تسرب الذاكرة.

الحل سهل جدا. افعل ما تفعله بالضبط ولكن استخدم List<IList> بدلاً من مجرد الرجوع إلى القياس التلقائي:

private List<IList> _GridFilters;

والاستخدام ToList() لعمل نسخة من المرشحات التي تقوم بتعيين معالجاتها على:

_GridFilters = dataGridCollectionView.AutoFilterValues.Values.ToList();

منذ _gridfilters الآن أ List<IList>, ، عليك أيضًا تغيير الحلقات:

foreach(IList autofilterValues in _GridFilters) 
  ...

السبب في أن هذا يعمل هو أن القائمة الفعلية لقوائم المرشحات القديمة يتم نسخها إلى _gridfilters ، بدلاً من مجرد الرجوع إلى خاصية المرحلات التلقائية.

هذه تقنية عامة لطيفة تنطبق في العديد من المواقف.

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