سؤال

أقوم بتطوير تطبيق في Silverlight2 ومحاولة متابعة نمط عرض النموذج. أنا ملزم خاصية Isenabled على بعض الضوابط إلى ملكية منطقية على Viewmodel.

أنا في مشاكل عندما يتم اشتقاق تلك الخصائص من خصائص أخرى. دعنا نقول أن لدي زر حفظ لا أريد ممكنا فقط عندما يكون من الممكن حفظه (تم تحميل البيانات، ونحن غير مشغولين حاليا في العمل في قاعدة البيانات).

لذلك لدي اثنين من الخصائص مثل هذا:

    private bool m_DatabaseBusy;
    public bool DatabaseBusy
    {
        get { return m_DatabaseBusy; }
        set
        {
            if (m_DatabaseBusy != value)
            {
                m_DatabaseBusy = value;
                OnPropertyChanged("DatabaseBusy");
            }
        }
    }

    private bool m_IsLoaded;
    public bool IsLoaded
    {
        get { return m_IsLoaded; }
        set
        {
            if (m_IsLoaded != value)
            {
                m_IsLoaded = value;
                OnPropertyChanged("IsLoaded");
            }
        }
    }

الآن ما أريد القيام به هو:

public bool CanSave
{
     get { return this.IsLoaded && !this.DatabaseBusy; }
}

ولكن لاحظ عدم وجود إشعار تغير الممتلكات.

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

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

في الأساس ما قمت بتوصيله واجهة حددت قائمة أزواج القيمة الرئيسية لعقد الخصائص التي تعتمد على خصائص أخرى:

public interface INotifyDependentPropertyChanged
{
    // key,value = parent_property_name, child_property_name, where child depends on parent.
    List<KeyValuePair<string, string>> DependentPropertyList{get;}
}

بعد ذلك جعلت السمة للذهاب في كل خاصية:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = false)]
public class NotifyDependsOnAttribute : Attribute
{
    public string DependsOn { get; set; }
    public NotifyDependsOnAttribute(string dependsOn)
    {
        this.DependsOn = dependsOn;
    }

    public static void BuildDependentPropertyList(object obj)
    {
        if (obj == null)
        {
            throw new ArgumentNullException("obj");
        }

        var obj_interface = (obj as INotifyDependentPropertyChanged);

        if (obj_interface == null)
        {
            throw new Exception(string.Format("Type {0} does not implement INotifyDependentPropertyChanged.",obj.GetType().Name));
        }

        obj_interface.DependentPropertyList.Clear();

        // Build the list of dependent properties.
        foreach (var property in obj.GetType().GetProperties())
        {
            // Find all of our attributes (may be multiple).
            var attributeArray = (NotifyDependsOnAttribute[])property.GetCustomAttributes(typeof(NotifyDependsOnAttribute), false);

            foreach (var attribute in attributeArray)
            {
                obj_interface.DependentPropertyList.Add(new KeyValuePair<string, string>(attribute.DependsOn, property.Name));
            }
        }
    }
}

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

public class ViewModel : INotifyPropertyChanged, INotifyDependentPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyname)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyname));

            // fire for dependent properties
            foreach (var p in this.DependentPropertyList.Where((x) => x.Key.Equals(propertyname)))
            {
                PropertyChanged(this, new PropertyChangedEventArgs(p.Value));
            }
        }
    }

    private List<KeyValuePair<string, string>> m_DependentPropertyList = new List<KeyValuePair<string, string>>();
    public List<KeyValuePair<string, string>> DependentPropertyList
    {
        get { return m_DependentPropertyList; }
    }

    public ViewModel()
    {
        NotifyDependsOnAttribute.BuildDependentPropertyList(this);
    }
 }

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

    [NotifyDependsOn("Session")]
    [NotifyDependsOn("DatabaseBusy")]
    public bool SaveEnabled
    {
        get { return !this.Session.IsLocked && !this.DatabaseBusy; }
    }

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

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

المحلول

الطريقة التقليدية للقيام بذلك هي إضافة مكالمة OnPropertychanged إلى كل من الخصائص التي قد تؤثر على واحد المحسوب الخاص بك، مثل هذا:

public bool IsLoaded
{
    get { return m_IsLoaded; }
    set
    {
        if (m_IsLoaded != value)
        {
            m_IsLoaded = value;
            OnPropertyChanged("IsLoaded");
            OnPropertyChanged("CanSave");
        }
    }
}

هذا يمكن أن تحصل على فوضوي بعض الشيء (إذا، على سبيل المثال، حسابك في تغييرات cansave).

واحد (منظف؟ أنا لا أعرف) طريقة للتغلب على هذا سيكون لتجاوز onpropertychanged وجعل المكالمة هناك:

protected override void OnPropertyChanged(string propertyName)
{
    base.OnPropertyChanged(propertyName);
    if (propertyName == "IsLoaded" /* || propertyName == etc */)
    {
        base.OnPropertyChanged("CanSave");
    }
}

نصائح أخرى

تحتاج إلى إضافة إشعار لتغيير خاصية Cansave في كل مكان أحد الخصائص التي يعتمد عليها التغييرات:

OnPropertyChanged("DatabaseBusy");
OnPropertyChanged("CanSave");

و

OnPropertyChanged("IsEnabled");
OnPropertyChanged("CanSave");

ماذا عن هذا الحل؟

private bool _previousCanSave;
private void UpdateCanSave()
{
    if (CanSave != _previousCanSave)
    {
        _previousCanSave = CanSave;
        OnPropertyChanged("CanSave");
    }
}

ثم استدعاء UpdateCansave () في STELTISS لل ISLoaded و DableBusy؟

إذا لم تتمكن من تعديل STINTERS من ISLoaded و DatasyBusy لأنها في فئات مختلفة، فيمكنك تجربة استدعاء UpdateCanSave () في معالج الأحداث Vacycharchanged للكائن الذي يحدد ISLoaded و DatasyBusy.

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