我有一个名为IMailSender和ISMSSender的接口。我有一个抽象类叫Device。
Device1继承自设备IMailSenderDevice2继承自Device、IMailSender、ISMSSender
我希望IMailSender的所有字段都调用notifypropertychanged。我是否也必须在Device1中实现所有IMailSender属性才能调用notifypropertychanged并在Device2中执行相同的代码,或者有更好的解决方案?
谢谢。
您的类必须引发PropertyChanged
事件,因为接口只能确保所有实现类都有一个返回类型相同的方法。一个好的方法是定义一个基类(这是MVVM模式中非常常见的方法,例如MVVM Light框架),该基类通过一个方法引发事件,所有其他适当的类都可以从该方法继承。例如:
...
public abstract class BaseViewModel : IMailSender, INotifyPropertyChanged
{
...
public void RaisePropertyChanged(string property)
{
if (property != null)
{
PropertyChanged(property);
}
}
}
继承类可以按如下方式使用:
...
public class AViewModel : BaseViewModel
{
...
private string _property;
public string Property
{
get
{
return _property;
}
set
{
_property = value;
RaisePropertyChanged("Property");
}
}
...
}
其他解决方案是面向方面的。例如postsharp。shttp://www.sharpcrafters.com/solutions/notifypropertychanged
因此,可以在属性上放置PropertyChanged属性。
同样使用.net 4.5,您可以使用CallerInfoAttribute来实现一个不需要属性名称的简单实现,例如:
http://danrigby.com/2012/04/01/inotifypropertychanged-the-net-4-5-way-revisited/->
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var eventHandler = this.PropertyChanged;
if (eventHandler != null)
{
eventHandler(this, new PropertyChangedEventArgs(propertyName));
}
}
有了它,你就可以在没有任何参数的情况下调用该方法
public int MyProperty
{
get
{
...
}
set
{
m_MyProperty=value;
OnPropertyChanged();
}
}
使用this,调用ObservableFactory.Create()并使用返回对象。要使用通知事件,只需将其强制转换为INotifyPropertyChanged
public static class ObservableFactory
{
public static T Create<T>(T target)
{
if (!typeof(T).IsInterface)
throw new ArgumentException("Target should be an interface", "target");
var proxy = new Observable<T>(target);
return (T)proxy.GetTransparentProxy();
}
}
internal class Observable<T> : RealProxy, INotifyPropertyChanged, INotifyPropertyChanging
{
private readonly T target;
internal Observable(T target)
: base(ImplementINotify(typeof(T)))
{
this.target = target;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
if (methodCall != null)
{
return HandleMethodCall(methodCall);
}
return null;
}
public event PropertyChangingEventHandler PropertyChanging;
public event PropertyChangedEventHandler PropertyChanged;
IMessage HandleMethodCall(IMethodCallMessage methodCall)
{
var isPropertySetterCall = methodCall.MethodName.StartsWith("set_");
var propertyName = isPropertySetterCall ? methodCall.MethodName.Substring(4) : null;
if (isPropertySetterCall)
{
OnPropertyChanging(propertyName);
}
try
{
object methodCalltarget = target;
if (methodCall.MethodName == "add_PropertyChanged" || methodCall.MethodName == "remove_PropertyChanged"||
methodCall.MethodName == "add_PropertyChanging" || methodCall.MethodName == "remove_PropertyChanging")
{
methodCalltarget = this;
}
var result = methodCall.MethodBase.Invoke(methodCalltarget, methodCall.InArgs);
if (isPropertySetterCall)
{
OnPropertyChanged(methodCall.MethodName.Substring(4));
}
return new ReturnMessage(result, null, 0, methodCall.LogicalCallContext, methodCall);
}
catch (TargetInvocationException invocationException)
{
var exception = invocationException.InnerException;
return new ReturnMessage(exception, methodCall);
}
}
protected virtual void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
protected virtual void OnPropertyChanging(string propertyName)
{
var handler = PropertyChanging;
if (handler != null) handler(this, new PropertyChangingEventArgs(propertyName));
}
public static Type ImplementINotify(Type objectType)
{
var tempAssemblyName = new AssemblyName(Guid.NewGuid().ToString());
var dynamicAssembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
tempAssemblyName, AssemblyBuilderAccess.RunAndCollect);
var moduleBuilder = dynamicAssembly.DefineDynamicModule(
tempAssemblyName.Name,
tempAssemblyName + ".dll");
var typeBuilder = moduleBuilder.DefineType(
objectType.FullName, TypeAttributes.Public | TypeAttributes.Interface | TypeAttributes.Abstract);
typeBuilder.AddInterfaceImplementation(objectType);
typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanged));
typeBuilder.AddInterfaceImplementation(typeof(INotifyPropertyChanging));
var newType = typeBuilder.CreateType();
return newType;
}
}