FirePropertyChanged中的PropertyChangedEventHandler为null

时间:2010-09-16 12:27:44

标签: mvvm viewmodel inotifypropertychanged event-handling propertychanged

我有一个名为EmployeeViewModel的viewmodel,它继承自ViewModelBase。这是ViewModelBase的实现。

    public event PropertyChangedEventHandler PropertyChanged;
    public void FirePropertyChanged(string propertyname)
    {
        var handler = PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyname));
    }
    public void FirePropertyChanged<TValue>(Expression<Func<TValue>> propertySelector)
    {
        if (PropertyChanged != null)
        {
            var memberExpression = propertySelector.Body as MemberExpression;
            if (memberExpression != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
            }
        }
    }

我的EmployeeViewModel有一个属性名称GridResults,它绑定到View on Grid,这是属性定义。

    public PagedCollectionView GridResults
    {
        get { return _gridResults; }
        set 
        { 
            _gridResults = value;
            FirePropertyChanged(()=>GridResults); 
        }
    }

现在,当我在EmployeeViewModel的代码中的某处设置GridResults的值时,它会触发属性更改事件并进入

FirePropertyChanged(Expression&gt; propertySelector)

但在该方法中,其PropertyChangedEventHandler始终保持为null,并且它会阻止方法的完整执行。最终,我的网格视图仍未被注意到它的基础项源已被更改。

我错过了什么吗?

提前谢谢

-K9

1 个答案:

答案 0 :(得分:1)

你的ViewModelBase真的实现了INotifyPropertyChanged吗?

如果是,请尝试使用字符串参数FirePropertyChanged。

public PagedCollectionView GridResults
{
    get { return _gridResults; }
    set 
    { 
        _gridResults = value;
        FirePropertyChanged("GridResults"); 
    }
}

这是我使用的INPCBase类:

/// <summary>
/// Basisklasse für INotifyPropertyChanged.
/// </summary>
public class INPCBase : INotifyPropertyChanged
{
    #region INotifyPropertyChanged Members

    public event PropertyChangedEventHandler PropertyChanged;

    /// <summary>
    /// Notify mittels PropertyInfo. HINWEIS: diese Variante ist ungefähr 3x langsamer wie 
    /// <see cref="NotifyPropertyChanged(string)"/> bzw. <see cref="NotifyPropertyChanged(System.ComponentModel.PropertyChangedEventArgs)"/>.
    /// </summary>
    /// <example>
    /// <code>
    /// public string InfoMessage
    /// {
    ///     get {return this.infomessage;}
    ///     set 
    ///     {
    ///         this.infomessage = value;
    ///         this.NotifyPropertyChanged(()=> this.InfoMessage);
    ///     }
    /// }
    /// </code>
    /// </example>
    /// <typeparam name="T"></typeparam>
    /// <param name="property"></param>
    protected void NotifyPropertyChanged<T>(Expression<Func<T>> property)
    {
        var propertyInfo = ((MemberExpression)property.Body).Member as PropertyInfo;

        if (propertyInfo == null)
        {
            throw new ArgumentException("The lambda expression 'property' should point to a valid Property");
        }

        this.VerifyPropertyName(propertyInfo.Name);

        var handler = PropertyChanged;

        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyInfo.Name));
    }

    /// <summary>
    /// Notify using pre-made PropertyChangedEventArgs
    /// </summary>
    /// <param name="args"></param>
    protected void NotifyPropertyChanged(PropertyChangedEventArgs args)
    {
        this.VerifyPropertyName(args.PropertyName);

        var handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, args);
        }
    }

    /// <summary>
    /// Notify using String property name
    /// </summary>
    protected void NotifyPropertyChanged(String propertyName)
    {
        this.VerifyPropertyName(propertyName);

        var handler = PropertyChanged;

        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    #endregion

    #region Debugging Aides

    /// <summary>
    /// Warns the developer if this object does not have
    /// a public property with the specified name. This 
    /// method does not exist in a Release build.
    /// </summary>
    [Conditional("DEBUG")]
    [DebuggerStepThrough]
    public void VerifyPropertyName(string propertyName)
    {
        // Verify that the property name matches a real,  
        // public, instance property on this object.
        if (TypeDescriptor.GetProperties(this)[propertyName] != null)
            return;

        var msg = "Invalid property name: " + propertyName;

        if (this.ThrowOnInvalidPropertyName)
            throw new Exception(msg);

        Debug.Fail(msg);
    }

    /// <summary>
    /// Returns whether an exception is thrown, or if a Debug.Fail() is used
    /// when an invalid property name is passed to the VerifyPropertyName method.
    /// The default value is false, but subclasses used by unit tests might 
    /// override this property's getter to return true.
    /// </summary>
    protected virtual bool ThrowOnInvalidPropertyName { get; private set; }

    #endregion // Debugging Aides
}