c# - 将模型属性表达式传递给 View

标签 c# asp.net-mvc model-view-controller generics asp.net-mvc-2

我希望有一种方法可以让 View 以通用方式关注来自 Controller 的特定模型属性。

我目前拥有的是:


Controller :

// To become an extension/base class method
private void FocusOnField<TModel, TProperty>(Expression<Func<TModel, TProperty>> fieldExpression)
{
    ViewData["FieldToFocus"] = fieldExpression;
}

...

FocusOnField((ConcreteModelClass m) => m.MyProperty);

查看

    public static class ViewPageExtensions
    {
        public static MvcHtmlString FocusScript<TModel>(this ViewPage<TModel> viewPage)
        {
            if (viewPage.ViewData["FieldToFocus"] != null)
            {
                return MvcHtmlString.Create(
@"<script type=""text/javascript"" language=""javascript"">
    $(document).ready(function() {
        setTimeout(function() {
            $('#" + viewPage.Html.IdFor((System.Linq.Expressions.Expression<Func<TModel, object>>)viewPage.ViewData["FieldToFocus"]) + @"').focus();
        }, 500);
    });
</script>");
            }
            else
            {
                return MvcHtmlString.Empty;
            }
        }
    }

我现在面临的问题是,在 View 的 FocusScript 中方法 我不知道要关注的属性的返回类型,并转换为 (System.Linq.Expressions.Expression<Func<TModel, object>>)任何不返回对象的属性都会失败。

我不能只为属性添加第二个通用参数,因为我不知道 Controller 希望我关注的属性的返回类型是什么。

如何编写我的 View 扩展方法 FocusScript以一种通用的方式,以便它可以与不同返回类型的属性一起使用?


为什么会出现问题?

我知道我可以在 Controller 中传递我想要关注的控件的 ID,然后让 javascript 读取该 ID,找到该控件并关注它。但是,我不喜欢在 Controller 中硬编码属于 View 的内容(控件的 ID)。我想告诉方法我想要什么属性,它应该知道要使用的 Id,就像 View 通常获取/创建控件的 Id 一样。

假设我有一个模型:

class MyModel
{
    public int IntProperty { get; set; }
    public string StringProperty { get; set; }
}

在 Controller 的不同地方我想关注一个不同的领域:

FocusOnField((MyModel m) => m.IntProperty);
...
FocusOnField((MyModel m) => m.StringProperty);

现在,在第一种情况下,表达式是一个返回整数的函数,在第二种情况下,它返回一个字符串。结果,我不知道将我的 ViewData["FieldToFocus"] 转换到什么(将其传递给 IdFor<>() ),因为它因属性而异..

最佳答案

我想我已经找到了解决您问题的方法 - 它适用于我的环境,但我不得不猜测您的代码可能看起来如何。

public static class ViewPageExtensions
{
    public static MvcHtmlString GetIdFor<TViewModel, TProperty>(ViewPage<TViewModel> viewPage, Expression<Func<TViewModel, TProperty>> expression)
    {
        return viewPage.Html.IdFor(expression);
    }

    public static MvcHtmlString FocusScript<TViewModel>(this ViewPage<TViewModel> viewPage)
    {
        if (viewPage.ViewData["FieldToFocus"] == null)
            return MvcHtmlString.Empty;

        object expression = viewPage.ViewData["FieldToFocus"];

        Type expressionType = expression.GetType(); // expressionType = Expression<Func<TViewModel, TProperty>>
        Type functionType = expressionType.GetGenericArguments()[0]; // functionType = Func<TViewModel, TProperty>
        Type[] functionGenericArguments = functionType.GetGenericArguments(); // functionGenericArguments = [TViewModel, TProperty]
        System.Reflection.MethodInfo method = typeof(ViewPageExtensions).GetMethod("GetIdFor").MakeGenericMethod(functionGenericArguments); // method = GetIdFor<TViewModel, TProperty>

        MvcHtmlString id = (MvcHtmlString)method.Invoke(null, new[] { viewPage, expression }); // Call GetIdFor<TViewModel, TProperty>(viewPage, expression);

        return MvcHtmlString.Create(
            @"<script type=""text/javascript"" language=""javascript"">
                $(document).ready(function() {
                    setTimeout(function() {
                        $('#" + id + @"').focus();
                    }, 500);
                });
            </script>");
    }
}

也许有更优雅的方法,但我认为它归结为您试图将对象(即 ViewData["FieldToFocus"] 的返回类型)转换为正确的表达式树 Expression<Func<TViewModel, TProperty>>但正如您所说,您不知道 TProperty 应该是什么。

另外,为了完成这项工作,我必须向 GetIdFor 添加另一个静态方法。因为目前我不太确定如何调用扩展方法。它只是一个包装器来调用 IdFor扩展方法。

你可以让它不那么冗长(但可能不那么可读)。

object expression = viewPage.ViewData["FieldToFocus"];

MethodInfo method = typeof(ViewPageExtensions).GetMethod("GetIdFor")
    .MakeGenericMethod(expression.GetType().GetGenericArguments()[0].GetGenericArguments());

MvcHtmlString id = (MvcHtmlString)method.Invoke(null, new[] { viewPage, expression });

最后一个想法,HtmlHelper.IdFor 的输出不同于ExpressionHelper.GetExpressionText ? IdFor我不是很懂,不知道它会不会一直给你一个匹配属性名的字符串。

ViewData["FieldToFocus"] = ExpressionHelper.GetExpressionText(fieldExpression);

关于c# - 将模型属性表达式传递给 View ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11450774/

相关文章:

c# - 图片不出现在电子邮件中

asp.net - asp.net 中的分页结果

c# - 为什么 MouseMove 事件发生在 MouseUp 事件之后?

c# - 接受返回 null 的方法 - C# .NET MVC

c# - pictureBox 图像处理异常

c# - 如何更改 Windows Azure 网站的信任级别?

php - 谁应该捕获我的 $_POST 数据 : controller or model?

java - MVC4 验证在 IIS 部署后不起作用,但在 Visual Studio 服务器中工作正常

c# - 使用 c# 和 MySql 存储过程找出 Last_Insert_Id() (在数据访问层 MVC 中)

c# - 如何在调用自己的植入之前强制继承类的方法实现调用基方法?