【发布时间】:2012-12-31 01:56:58
【问题描述】:
我正在为我的 WPF viewModel 基类编写一个小扩展,它允许我以比在 getter 中引发多个 PropertyChanged 事件的标准方法更简洁的方式定义属性之间的依赖关系:
所以而不是:
public int ThisProperty
{
get
{
thisProperty = value;
RaisePropertyChangedEvent("ThisProperty");
RaisePropertyChangedEvent("FirstDependentProperty");
RaisePropertyChangedEvent("SecondDependentProperty");
}
}
我希望能够在我的 ViewModels 构造函数中做这样的事情:
RegisterDependencies("This Property",
"FirstDependentProperty", "SecondDependentProperty");
我在 viewModel 中定义了以下方法(删除了错误检查以减少代码量):
public void RegisterDependencies(string property, params string[] dependencies)
{
foreach (string item in dependencies)
{
IList<string> deps;
if (dependenciesList.TryGetValue(item, out deps))
{
if (!deps.Contains(property))
{
deps.Add(property);
}
}
else
{
deps = new List<string>();
deps.Add(property);
dependenciesList[item] = deps;
}
}
}
我的视图模型使用以下方法订阅PropertyChanged 事件:
void ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
IList<string> dependencies;
if (dependenciesList.TryGetValue(e.PropertyName, out dependencies))
{
foreach (string item in dependencies)
{
RaisePropertyChangedEvent(item);
}
}
}
这只是检查属性是否有任何依赖关系,如果有,也会引发PropertyChanged 事件。这一切都很好,到目前为止一切都很好。
我真正想要的是使用 lambda 表达式而不是字符串,以便获得自动完成和更好的重构支持。我所追求的是这样的:
RegisterDependencies<ViewModelType>(p => p.Property,
p => p.FirstDependency,
p => p.SecondDependency); //and so on...
我已将方法签名重新定义为如下所示:
public void RegisterDependencies<T>(Expression<Func<T, object>> property,
prams Expression<Func<T, object>>[] dependencies)
{
}
目前该方法只是尝试将表达式转换为字符串,这就是我要解决的问题。我不确定如何从表达式中获取属性的名称并将其转换为字符串。
Josh Smith 的 MVVM Foundation 包含一个名为 PropertyChangedObserver 的类,其中有一段代码可以执行此操作,我已尝试对其进行调整以适应我的示例:
private static string GetPropertyName<T>(Expression<Func<T, object>> expression)
{
var lambda = expression as LambdaExpression;
MemberExpression memberExpression;
if (lambda.Body is UnaryExpression)
{
var unaryExpression = lambda.Body as UnaryExpression;
memberExpression = unaryExpression.Operand as MemberExpression;
}
else
{
memberExpression = lambda.Body as MemberExpression;
}
return memberExpression != null ? ((PropertyInfo)memberExpression.Member).Name : null;
}
这是在我更新的RegisterDependencies 方法中调用的(这实际上是该方法的全部代码):
string propertyName = GetPropertyName(property);
foreach (Expression<Func<T, object>> expr in dependencies)
{
string dependencyName = GetPropertyName(expr);
}
运行时会生成XamlParseException。这很难调试,因为它不会抛出标准异常窗口。 Visual Studio 的输出窗口提供了更多信息,最初的异常似乎是 InvalidCastException,尽管我不确定为什么,因为两个表达式属于同一类型。
谁能解释一下并帮助我解决这个问题?
【问题讨论】:
-
因为我在该代码中看到的唯一演员是
(PropertyInfo)之一,您可以尝试通过在该行上设置断点并检查memberExpression.Member是否实际上是PropertyInfo 来缩小问题范围。
标签: c# generics lambda expression extension-methods