我正在开发中Silverlight2应用程序,并试图按照模型 - 视图 - 视图模型模式。我在某些控件IsEnabled属性绑定到在视图模型的布尔属性。

我运行到问题时,这些属性从其他属性的。比方说,我有一个保存按钮,我只想要启用时,它可能保存(数据已加载,并且我们目前不旺数据库做的东西)。

所以,我有几个属性是这样的:

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

在属性本身只存储一个字符串。您可以定义每个属性的多个依赖性。该属性的胆量是在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和火灾的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");
    }
}

其他提示

您需要添加一个通知的CanSave性质变化无处不在的特性之一这取决于变化:

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

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

这样如何溶液?

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

然后,在IsLoaded和DatabaseBusy的制定者调用UpdateCanSave()?

如果您不能修改IsLoaded和DatabaseBusy的制定者,因为他们在不同的班级,你可以尝试在定义IsLoaded和DatabaseBusy对象PropertyChanged事件处理程序调用UpdateCanSave()。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top