关于通用视图模型

时间:2015-07-23 16:49:12

标签: c# asp.net-mvc-3 generics viewmodel html-helper

我正在尝试在强类型视图上创建HtmlHelper方法,其中视图模型是通用的。但是有一个复杂的问题。我想简化我的语法,以便在视图模型上指定属性的成员表达式。请考虑以下事项。

public interface ViewModel<T>
{
    T Model { get; set; }
}

public class DocViewModel : ViewModel<Document> 
{
    public IEnumerable<string> Options { get; set; }
    public Document Model { get; set; }
}

public class Document
{
    public string Name { get; set; }
    public string Value { get; set; }
}

现在,我可以轻松创建一个引用视图模型本身的帮助器,并像这样使用它:

@model DocViewModel
<div>
    @Html.DoSomething(vm => vm.Options);
    @Html.DoSomethingElse(vm => vm.Model.Name);
    @Html.DoSomethingYetAgain(vm => vm.Model.Value);
</div>

但我希望能够简单地在模型上传递一个表达式,如下所示:

@model DocViewModel
<div>
    @Html.DoSomething(vm => vm.Options);
    @Html.DoSomethingElse(vm => vm.Name);
    @Html.DoSomethingYetAgain(vm => vm.Value);
</div>

现在,我可以用这样的方式编写助手,如果我在调用中显式引用类型参数,我就可以这样做:

@model DocViewModel
<div>
     @Html.DoSomething<Document>(vm => vm.Name);
</div>

但是那种方式违背了我要追求的目标。看起来我应该能够编写一个HtmlHelper,它可以利用DocViewModel上强类型视图的事实,它本身就是一个ViewModel,并且@Html()返回

HtmlHelper<DocViewModel> //HtmlHelper<ViewModel<Document>>

因此,Document所代表的类型参数是隐式已知的,因此我可以编写

public static string DoSomethingElse<TModel, TProperty>(this HtmlHelper<ViewModel<TModel>> helper, Expression<Func<TModel, TProperty>> expression) 
{
    return "Whatever";
}

但无法完成转换。那么我有什么方法可以做到这一点?或者我只是不得不忍受丑陋的语法?

编辑:将对“KoViewModel”的错误引用更改为“ViewModel”

再次编辑:此外,制作ViewModel泛型的要点是我可以声明任何其他类型的ViewModel:

public class ProgramViewModel : ViewModel<Program>
{
    //other stuff
    public Program Model { get; set; }
}
public class Program
{
    public string Something { get; set; }
    //other properties I want to reference
}

在另一种观点中:

@model ProgramViewModel
<div>
    @Html.DoSomethingElse(vm => vm.Something)
</div>

同样,我希望能够在视图的视图模型以及视图模型的Model属性上取消引用属性,而无需在方法调用中显式引用类型。

我上面定义的方法的问题是HtmlHelper和HtmlHelper之间显然没有隐式转换,因此编译器无法解析视图中的@Html调用,如上所述(“不包含定义for and no extension method blah blah blah“)。当然,明确的演员阵容会使这项工作成功,但这正是我想要避免的。

1 个答案:

答案 0 :(得分:0)

如果您可以将ViewModel更改为抽象类,请执行以下操作:

public abstract class ViewModel<TModel>
{
    public class HtmlHelper : HtmlHelper<ViewModel<TModel>> {}
    public TModel Model;
}

然后编写以下静态扩展方法:

public static TProperty DoSomethingElse<TModel, TProperty>(this ViewModel<TModel>.HtmlHelper helper, Expression<Func<TModel, TProperty>> expression) 
{
    return default(TProperty);
}

这应该隐含地解决。