在开发Web应用程序时,经常需要在服务器端和客户端绑定数据。为了实现这一点,通常会使用一些库,比如Telerik的Grid组件。然而,标准的Grid组件并不总是提供想要的所有功能。例如,可能想要在Grid中添加一个"Open"链接,但是标准的Grid组件并没有提供这样的功能。
为了解决这个问题,可以编写一个扩展方法,这样就可以在服务器端和客户端绑定中使用相同的HTML。这样,就不需要为服务器端和客户端绑定编写两个不同的模板,从而避免了可能的错误。
下面是一个扩展方法的示例,它允许在服务器端和客户端绑定中使用相同的ActionLink。
public static GridTemplateColumnBuilder<T> ActionLink<T>(this GridColumnFactory<T> factory, string linkText, string action, Expression<Func<T, object>> routeValues) where T : class {
return ActionLink(factory, linkText, action, string.Empty, routeValues);
}
public static GridTemplateColumnBuilder<T> ActionLink<T>(this GridColumnFactory<T> factory, string linkText, string action, string controller, Expression<Func<T, object>> routeValues) where T : class {
if (string.IsNullOrEmpty(controller))
controller = factory.Container.ViewContext.Controller.GetType().Name.Replace("Controller", string.Empty);
var urlHelper = new UrlHelper(factory.Container.ViewContext.RequestContext);
var builder = factory.Template(x => {
var actionUrl = urlHelper.Action(action, controller, routeValues.Compile().Invoke(x));
return string.Format(@"", actionUrl, linkText);
});
if (!(routeValues.Body is NewExpression))
throw new ArgumentException("routeValues.Body must be a NewExpression");
RouteValueDictionary routeValueDictionary = ExtractClientTemplateRouteValues(((NewExpression)routeValues.Body));
var link = urlHelper.Action(action, controller, routeValueDictionary);
var clientTemplate = string.Format(@"", link, linkText);
return builder.ClientTemplate(clientTemplate);
}
private static RouteValueDictionary ExtractClientTemplateRouteValues(NewExpression newExpression) {
RouteValueDictionary routeValueDictionary = new RouteValueDictionary();
for (int index = 0; index < newExpression.Arguments.Count; index++) {
var argument = newExpression.Arguments[index];
var member = newExpression.Members[index];
object value;
switch (argument.NodeType) {
case ExpressionType.Constant:
value = ((ConstantExpression)argument).Value;
break;
case ExpressionType.MemberAccess:
MemberExpression memberExpression = (MemberExpression)argument;
if (memberExpression.Expression is ParameterExpression)
value = string.Format("<#= {0} #>", memberExpression.Member.Name);
else
value = GetValue(memberExpression);
break;
default:
throw new InvalidOperationException("Unknown expression type!");
}
routeValueDictionary.Add(member.Name, value);
}
return routeValueDictionary;
}
private static object GetValue(MemberExpression member) {
var objectMember = Expression.Convert(member, typeof(object));
var getterLambda = Expression.Lambda<Func<object>>(objectMember);
return getterLambda.Compile().Invoke();
}
这个扩展方法首先检查控制器名称是否为空,如果为空,则使用当前控制器的名称。然后,它创建一个新的UrlHelper对象,用于生成ActionLink的URL。接下来,它使用一个lambda表达式来生成服务器端的模板。
对于客户端模板,它解析routeValues表达式,生成一个包含路由值的RouteValueDictionary。然后,它使用这个字典来生成客户端模板。