سؤال

أخطط لإنشاء سيناريو ماجستير نموذجي ، أي مجموعة من العناصر المعروضة في أ ListView عن طريق ترتيب البيانات إلى ICollectionView, ، وتفاصيل حول العنصر المحدد في مجموعة منفصلة من عناصر التحكم (مربعات النص ، numupdowns ...).

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

متطلبات أخرى هي:

  • توافق MVVM (أي ليس الكثير من الكود)
  • قابلية التمديد (يمكن إضافة خصائص/أنواع جديدة لاحقًا)

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

شكرًا!
Gehho.

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

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

المحلول

في ViewModel الخاص بك ، قم بإنشاء خاصية ترتبط بـ SelecteMs الخاص بـ ListView الخاص بك.

قم بإنشاء خاصية أخرى تمثل كائن التفاصيل للعناصر المحددة.

قسم التفاصيل (في XAML) مرتبط بخاصية التفاصيل هذه (في ViewModel).

في كل مرة يتم فيها تعديل مجموعة العناصر المحددة (حدث Setter/CollectionChanged) ، تحتاج إلى تحديث كائن التفاصيل الخاص بك أيضًا (سيتكرر من خلال الخصائص ذات الصلة وتحديد ما إذا كانت ذات القيمة نفسها أم لا).

بمجرد تعديل خاصية في التفاصيل ، تحتاج إلى تكرار مجموعة العناصر المحددة وإجراء التغييرات ذات الصلة عليها.

هذا هو.

أتمنى أن يساعد ذلك

نصائح أخرى

أنا أواجه نفس القضية الدقيقة.

IsSynchronizedWithCurrentItem = "True" يحتفظ فقط بـ CurrentItem في المزامنة (العنصر الأخير الذي حددته دون عقد Ctrl أو Shift).

تمامًا كما كان لديك ، لقد بحثت في الإنترنت بعيدًا عن الإجابة ولم أتوصل أبدًا إلى واحدة. يحتوي السيناريو الخاص بي على 3 Tier Master> التفاصيل> ربط التفاصيل ، حيث يكون كل طبقة مرتبطة بـ Listbox الخاصة به.

لقد قمت بتزوير شيء يعمل في الوقت الحالي.

بالنسبة إلى Master> Detail> Tiers التفاصيل ، قمت بإنشاء مجموعة فردية CollectionViewSource لكل طبقة وتعيين That CollectionViewSource.Source إلى كائن الكيان المناسب. على حدث Selections -changed من MasterView Bound Bound Bound ، قمت بإجراء مرشح على MasterView.view لاسترداد الكائنات حيث مفتاح Master Primary = مفتاح خارجي تفاصيل.

إنه أمر قذر ، ولكن إذا وجدت طريقة أفضل لإنجاز هذا ، أحب أن أسمع ذلك.

لقد استخدمت نهجًا مشابهًا لـ الشخص الذي اقترحه الكابتن. لقد قمت بإنشاء خاصية واحدة في ViewModel الخاصة بي والتي تمثل عناصر متعددة (أي جميع العناصر المحددة). في الممتلكات ، استخدمت المحاكمة والوصول إلى الأساليب التالية لتحديد/تعيين القيم المشتركة من/لجميع العناصر. لا يستخدم هذا النهج أي انعكاس ، ولكنه يستخدم المندوبين في شكل تعبيرات Lambda مما يجعله سريعًا جدًا.

كنظرة عامة ، هذا هو تصميمي الأساسي:

public class MyMultiSelectionViewModel
{
    private List<MyItemType> m_selectedItems = new List<MyItemType>();

    public void UpdateSelectedItems(IList<MyItemType> selectedItems)
    {
        m_selectedItems = selectedItems;

        this.OnPropertyChanged(() => this.MyProperty1);
        this.OnPropertyChanged(() => this.MyProperty2);
        // and so on for all relevant properties
    }

    // properties using SharedValueHelper (see example below)

}

تبدو الخصائص هكذا:

public string Name
{
    get
    {
        return SharedValueHelper.GetSharedValue<MyItemType, string>(m_selectedItems, (item) => item.Name, String.Empty);
    }
    set
    {
        SharedValueHelper.SetSharedValue<MyItemType, string>(m_selectedItems, (item, newValue) => item.Name = newValue, value);
        this.OnPropertyChanged(() => this.Name);
    }
}

والرمز ل SharedValueHelper يبدو الفصل هكذا:

/// <summary>
/// This static class provides some methods which can be used to
/// retrieve a <i>shared value</i> for a list of items. Shared value
/// means a value which represents a common property value for all
/// items. If all items have the same property value, this value is
/// the shared value. If they do not, a specified <i>non-shared value</i>
/// is used.
/// </summary>
public static class SharedValueHelper
{

    #region Methods

    #region GetSharedValue<TItem, TProperty>(IList<TItem> items, Func<TItem, TProperty> getPropertyDelegate, TProperty nonSharedValue)

    /// <summary>
    /// Gets a value for a certain property which represents a
    /// <i>shared</i> value for all <typeparamref name="TItem"/>
    /// instances in <paramref name="items"/>.<br/>
    /// This means, if all wrapped <typeparamref name="TItem"/> instances
    /// have the same value for the specific property, this value will
    /// be returned. If the values differ, <paramref name="nonSharedValue"/>
    /// will be returned.
    /// </summary>
    /// <typeparam name="TItem">The type of the items for which a shared
    /// property value is requested.</typeparam>
    /// <typeparam name="TProperty">The type of the property for which
    /// a shared value is requested.</typeparam>
    /// <param name="items">The collection of <typeparamref name="TItem"/>
    /// instances for which a shared value is requested.</param>
    /// <param name="getPropertyDelegate">A delegate which returns the
    /// property value for the requested property. This is used, so that
    /// reflection can be avoided for performance reasons. The easiest way
    /// is to provide a lambda expression like this:<br/>
    /// <code>(item) => item.MyProperty</code><br/>
    /// This expression will simply return the value of the
    /// <c>MyProperty</c> property of the passed item.</param>
    /// <param name="nonSharedValue">The value which should be returned if
    /// the values are not equal for all items.</param>
    /// <returns>If all <typeparamref name="TItem"/> instances have
    /// the same value for the specific property, this value will
    /// be returned. If the values differ, <paramref name="nonSharedValue"/>
    /// will be returned.</returns>
    public static TProperty GetSharedValue<TItem, TProperty>(IList<TItem> items, Func<TItem, TProperty> getPropertyDelegate, TProperty nonSharedValue)
    {
        if (items == null || items.Count == 0)
            return nonSharedValue;

        TProperty sharedValue = getPropertyDelegate(items[0]);
        for (int i = 1; i < items.Count; i++)
        {
            TItem currentItem = items[i];
            TProperty currentValue = getPropertyDelegate(currentItem);
            if (!sharedValue.Equals(currentValue))
                return nonSharedValue;
        }

        return sharedValue;
    }

    #endregion

    #region SetSharedValue<TItem, TProperty>(IList<TItem> a_items, Action<TItem, TProperty> a_setPropertyDelegate, TProperty a_newValue)

    /// <summary>
    /// Sets the same value for all <typeparamref name="TItem"/>
    /// instances in <paramref name="a_items"/>.
    /// </summary>
    /// <typeparam name="TItem">The type of the items for which a shared
    /// property value is requested.</typeparam>
    /// <typeparam name="TProperty">The type of the property for which
    /// a shared value is requested.</typeparam>
    /// <param name="items">The collection of <typeparamref name="TItem"/>
    /// instances for which a shared value should be set.</param>
    /// <param name="setPropertyDelegate">A delegate which sets the
    /// property value for the requested property. This is used, so that
    /// reflection can be avoided for performance reasons. The easiest way
    /// is to provide a lambda expression like this:<br/>
    /// <code>(item, newValue) => item.MyProperty = newValue</code><br/>
    /// This expression will simply set the value of the
    /// <c>MyProperty</c> property of the passed item to <c>newValue</c>.</param>
    /// <param name="newValue">The new value for the property.</param>
    public static void SetSharedValue<TItem, TProperty>(IList<TItem> items, Action<TItem, TProperty> setPropertyDelegate, TProperty newValue)
    {
        if (items == null || items.Count == 0)
            return;

        foreach (TItem item in items)
        {
            try
            {
                setPropertyDelegate(item, newValue);
            }
            catch (Exception ex)
            {
                // log/error message here
            }
        }
    }

    #endregion

    #endregion

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