silverlight   发布时间:2022-05-03  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了silverlight – 计算属性的PropertyChanged通知大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

概述

我正在Silverlight2中开发一个应用程序,并尝试遵循Model-View-ViewModel模式.我将一些控件上的IsEnabled属性绑定到ViewModel上的布尔属性. 当这些属性从其他属性派生时,我遇到了问题.假设我有一个Save按钮,我只想在可以保存的情况下启用它(数据已加载,我们当前并没有忙于在数据库中执行操作). 所以我有几个这样的属性: private bool m_Dat
我正在Silverlight2中开发一个应用程序,并尝试遵循Model-View-viewmodel模式.我将一些控件上的IsEnabled属性绑定到viewmodel上的布尔属性.

当这些属性从其他属性派生时,我遇到了问题.假设我有一个Save按钮,我只想在可以保存的情况下启用它(数据已加载,我们当前并没有忙于在数据库中执行操作).

所以我有几个这样的属性

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; }
}

但请注意缺少属性更改通知.

所以问题是:什么是暴露我可以绑定的单个布尔属性的干净方式,但是计算而不是显式设置并提供通知,以便UI可以正确更新?

编辑:感谢大家的帮助 – 我得到了它,并开始制作自定义属性.我在这里发布消息来源以防任何人感兴趣.我确信它可以以更清洁的方式完成,所以如果您发现任何缺陷,请添加评论或答案.

基本上我所做的是创建了一个接口,它定义了一个键值对列表,用于保存依赖于其他属性属性

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));
            }
        }
    }
}

属性本身仅存储单个字符串.您可以为每个属性定义多个依赖项.属性内容位于BuildDependentPropertyList静态函数中.你必须在你的类的构造函数调用它. (任何人都知道是否有办法通过类/构造函数属性执行此操作?)在我的情况下,所有这些都隐藏在基类中,因此在子类中,您只需将属性放在属性上.然后修改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; }
    }

这里最大的警告是它只在其他属性是当前类的成员时才有效.在上面的示例中,如果this.Session.IsLocked发生更改,则通知无法通过.我解决这个问题的方法订阅this.Session.NotifyPropertyChanged并为“Session”触发PropertyChanged. (是的,这会导致事件发生在他们不需要的地方)

解决方法

执行此操作的传统方法是向可能影响计算属性的每个属性添加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");
    }
}

大佬总结

以上是大佬教程为你收集整理的silverlight – 计算属性的PropertyChanged通知全部内容,希望文章能够帮你解决silverlight – 计算属性的PropertyChanged通知所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。