INotifyPropertyChanged包装器

时间:2015-09-11 08:19:58

标签: c# wpf

我发现了一些solution的INotifyPropertyChanged包装器,但它没有做任何事情。我做错了什么?名称更新异步但Windows中的值不会更改。为什么?* *

namespace WpfApplication1.ViewModel
{
class CustomerViewModel : INotifyPropertyChanged, IWeakEventListener
{
    private readonly Customer _customer;

    internal CustomerViewModel(Customer customer)
    {
        if (customer == null)
        {
            throw new ArgumentNullException("personModel");
        }

        _customer = customer;
        NotifyPropertyChangedEventManager.AddListener(_customer, this);

        Action Start = new Action(UpdateAsync);
        IAsyncResult result = Start.BeginInvoke(null, null);
    }
    private void UpdateAsync()
    {
        int i = 0;
        while (true)
        {
            System.Threading.Thread.Sleep(1000);
            _customer.Name = (++i).ToString();
        }
    }

    public string Name
    {
        get { return _customer.Name; }
        set { _customer.Name = value; }
    }

    public string JobTitle
    {
        get { return _customer.Work; }
        set { _customer.Work = value; }
    }

    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion

    #region IWeakEventListener Members
    public bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e)
    {
        PropertyChangedEventArgs pcArgs = e as PropertyChangedEventArgs;
        if (pcArgs != null)
        {
            OnPropertyChanged(pcArgs.PropertyName);
            return true;
        }
        return false;
    }
    #endregion
}
public class NotifyPropertyChangedEventManager : WeakEventManager
{
    public static NotifyPropertyChangedEventManager CurrentManager
    {
        get
        {
            var manager_type = typeof(NotifyPropertyChangedEventManager);
            var manager = WeakEventManager.GetCurrentManager(manager_type) as NotifyPropertyChangedEventManager;
            if (manager == null)
            {
                manager = new NotifyPropertyChangedEventManager();
                WeakEventManager.SetCurrentManager(manager_type, manager);
            }
            return manager;
        }
    }

    public static void AddListener(INotifyPropertyChanged source, IWeakEventListener listener)
    {
        CurrentManager.ProtectedAddListener(source, listener);
        return;
    }

    public static void RemoveListener(INotifyPropertyChanged source, IWeakEventListener listener)
    {
        CurrentManager.ProtectedRemoveListener(source, listener);
        return;
    }
    protected override void StartListening(object source)
    {
        ((INotifyPropertyChanged)source).PropertyChanged += Source_PropertyChanged; return;
    }
    protected override void StopListening(object source)
    {
        ((INotifyPropertyChanged)source).PropertyChanged -= Source_PropertyChanged;
        return;
    }

    void Source_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        { CurrentManager.DeliverEvent(sender, e); };
    }
}

}

客户

    public class Customer:INotifyPropertyChanged
{
    public string Name { get; set; }
    public string Number { get; set; }
    public string Work { get; set; }

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

和Xaml代码

<Grid>
    <Label Content="{Binding Name}"></Label>
</Grid>

4 个答案:

答案 0 :(得分:4)

您也可以使用Fody.PropertyChanged,而不是自己进行PropertyChanged。 (https://github.com/Fody/PropertyChanged

您可以在Visual Studio中通过Nuget安装它。

在编译时自动添加PropertyChanged实现是什么。

您的代码:

using PropertyChanged;

[ImplementPropertyChanged]
public class Person 
{        
    public string GivenNames { get; set; }
    public string FamilyName { get; set; }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }
}

汇编的内容:

public class Person : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    string givenNames;
    public string GivenNames
    {
        get { return givenNames; }
        set
        {
            if (value != givenNames)
            {
                givenNames = value;
                OnPropertyChanged("GivenNames");
                OnPropertyChanged("FullName");
            }
        }
    }

    string familyName;
    public string FamilyName
    {
        get { return familyName; }
        set 
        {
            if (value != familyName)
            {
                familyName = value;
                OnPropertyChanged("FamilyName");
                OnPropertyChanged("FullName");
            }
        }
    }

    public string FullName
    {
        get
        {
            return string.Format("{0} {1}", GivenNames, FamilyName);
        }
    }

    public virtual void OnPropertyChanged(string propertyName)
    {
        var propertyChanged = PropertyChanged;
        if (propertyChanged != null)
        {
            propertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

还有其他功能,请在维基阅读:https://github.com/Fody/PropertyChanged/wiki

答案 1 :(得分:1)

你必须调用OnPropertyChanged("Name"); 最好的地方是Name poperty setter。

答案 2 :(得分:1)

除了上面的好答案之外,您可以使用DynamicObject包装器来实现此行为,包装所访问的类,并代表更改其属性,从而触发属性更改事件。

我还没有尝试过(我可能会选择Fody),但像这样的伪可能有效:

public class InpcWrapperViewModel<T> : DynamicObject, INotifyPropertyChanged
{
    public T Original { get; }
    public InpcWrapperViewModel(T original)
    {
      Original = original;
    }

    public override bool TryGetMember(GetMemberBinder binder, out object result)
    {
      //set property of Original with reflection etc.
      //raise property changed 
    }

    public override bool TrySetMember(SetMemberBinder binder, object value)
    {
        //set with reflection etc.
        return true;
    }
}

用法:

dynamic x = new InpcWrapperViewModel<TEntity>(entity);
window.DataContext = x;
x.FirstName = "Hello"; //triggers INPC

如果您正在使用Prism或任何其他DI等,您可以创建一个自动包装项目的ViewModel工厂。

同样,以上是从未测试或尝试的伪代码。

答案 3 :(得分:1)

我知道这个问题已经过时了,而且没有完全回答你的问题。我认为这对你来说是更好的解决方案。

Bindable使用字典作为属性存储。很容易为子类添加必要的重载,以使用ref参数管理自己的后备字段。

  • 没有魔法字符串
  • 没有反思
  • 可以改进以抑制默认字典查找

代码:

"es6-promise-plugin": "file:node_modules/es6-promise-plugin",

像这样使用

    public class Bindable : INotifyPropertyChanged
    {
        private Dictionary<string, object> _properties = new Dictionary<string, object>();

        /// <summary>
        /// Gets the value of a property
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        protected T Get<T>([CallerMemberName] string name = null)
        {
            object value = null;
            if (_properties.TryGetValue(name, out value))
                return value == null ? default(T) : (T)value;
            return default(T);
        }

        /// <summary>
        /// Sets the value of a property
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="value"></param>
        /// <param name="name"></param>
        protected void Set<T>(T value, [CallerMemberName] string name = null)
        {
            if (Equals(value, Get<T>(name)))
                return;
            _properties[name] = value;
            OnPropertyChanged(name);
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }