当我们用MVVM的时候要实现INotifyPropertyChanged,如果你是基于.net4.5以下的framework(.net4.5已有新特性我这里就不说了)
你很可能会这么写
public
class
MyModel : INotifyPropertyChanged
{
private
string
_Name;
public
string
Name
{
get
{
return
_Name;
}
set
{
_Name = value;
OnPropertyChanged(
"Name"
);
//会造成硬编码错误
}
}
public
event
PropertyChangedEventHandler PropertyChanged;
public
void
OnPropertyChanged(
string
propertyName)
{
if
(PropertyChanged !=
null
)
{
PropertyChanged(
this
,
new
PropertyChangedEventArgs(propertyName));
}
}
}
这样的写法很可能会造成硬编码错误
你是不是有点烦每次要写一个字段还要写一个属性还要加上OnPropertyChanged,有没好一点的方法让我们少写
代码呢,能是能用现有的技术实现我们想要的像下面这样
public
class
MyModel : PropertyNotifyObject
{
public
string
Name
{
get
{
return
this
.GetValue(x => x.Name);
}
set
{
this
.SetValue(x => x.Name, value);
}
}
}
哇!这么写看着好简单呀,而且还能有效避免硬编码对你带来的问题。
写一个x.就能出现你要的属性
对!这样你就能省下更多的时间去写加的代码了,
先说明一下用到的技术没有新的只是只用到了泛型和扩展方法和一点linq,要怎么实现呢?来让我们一步一步的实现
我们先写一个公共类方法
public
class
MyCommMetoh
{
//得到属性的名称
public
static
string
GetPropertyName<T, U>(Expression<Func<T, U>> exp)
{
string
_pName =
""
;
if
(exp.Body
is
MemberExpression)
{
_pName = (exp.Body
as
MemberExpression).Member.Name;
}
else
if
(exp.Body
is
UnaryExpression)
{
_pName = ((exp.Body
as
UnaryExpression).Operand
as
MemberExpression).Member.Name;
}
return
_pName;
}
}
|
这个GetPropertyName方法是根据一个Lambda表达式得到属性的名称
像这上面 this.GetValue(x => x.Name) ,这个方法就是用x => x.Name做为参数得到Name这个名字
这样可以有效的防止硬编码错误
实现一下INotifyPropertyChanged接口
public
class
NotifyPropertyBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public
void
OnPropertyChanged(
string
propertyName)
{
if
(PropertyChanged !=
null
)
{
PropertyChanged(
this
,
new
PropertyChangedEventArgs(propertyName));
}
}
public
event
PropertyChangedEventHandler PropertyChanged;
#endregion
}
public
static
class
NotifyPropertyBaseEx
{
public
void
OnPropertyChanged<T, U>(
this
T npb, Expression<Func<T, U>> exp)
where
T : NotifyPropertyBase,
new
()
{
string
_PropertyName = MyCommMetoh.GetPropertyName(exp);
npb.OnPropertyChanged(_PropertyName);
}
}
|
上边的类我想你并不陌生吧,下这那个是个扩展类,如果你不太明白那就先回去看一下基础吧
是利用扩展根据lambda用上边我们写的公共类方法得到属性的名称,这也是为防止硬编码而做的工作
下面才是我们真正的基类PropertyNotifyObject,这个类是我们存放数据值,修改和查询值的
看一下我是怎么写的
public
class
PropertyNotifyObject : NotifyPropertyBase,IDisposable
{
public
PropertyNotifyObject() { }
Dictionary<
object
,
object
> _ValueDictionary =
new
Dictionary<
object
,
object
>();
#region 根据属性名得到属性值
public
T GetPropertyValue<T>(
string
propertyName)
{
if
(
string
.IsNullOrEmpty(propertyName))
throw
new
ArgumentException(
"invalid "
+ propertyName);
object
_propertyValue;
if
(!_ValueDictionary.TryGetValue(propertyName,
out
_propertyValue))
{
_propertyValue =
default
(T);
_ValueDictionary.Add(propertyName, _propertyValue);
}
return
(T)_propertyValue;
}
#endregion
public
void
SetPropertyValue<T>(
string
propertyName, T value)
{
if
(!_ValueDictionary.ContainsKey(propertyName) || _ValueDictionary[propertyName] != (
object
)value)
{
_ValueDictionary[propertyName] = value;
OnPropertyChanged(propertyName);
}
}
#region Dispose
public
void
Dispose()
{
DoDispose();
}
~PropertyNotifyObject()
{
DoDispose();
}
void
DoDispose()
{
if
(_ValueDictionary !=
null
)
_ValueDictionary.Clear();
}
#endregion
}
public
static
class
PropertyNotifyObjectEx
{
public
static
U GetValue<T, U>(
this
T t, Expression<Func<T, U>> exp)
where
T : PropertyNotifyObject
{
string
_pN = MyCommMetoh.GetPropertyName(exp);
return
t.GetPropertyValue<U>(_pN);
}
public
static
void
SetValue<T, U>(
this
T t, Expression<Func<T, U>> exp, U value)
where
T : PropertyNotifyObject
{
string
_pN = MyCommMetoh.GetPropertyName(exp);
t.SetPropertyValue<U>(_pN, value);
}
}
这是用一个字典把所有的存放了起来,看下面有一个扩展这个扩展就能让我们实现
public
string
Name
{
get
{
return
this
.GetValue(x => Name);
}
set
{
this
.SetValue(x => x.Name, value);
}
}
|
的x => x.Name。这样就能让我们写完x.后就能出现我们要的属性