简体   繁体   English

添加Razor关键字

[英]Adding Razor keywords

What is the best process to extend the Razor view-engine to add additional keywords? 扩展Razor视图引擎以添加其他关键字的最佳流程是什么?

I'm not a fan of the dynamic ViewBag property, so for all of my pages I define both a strongly-typed ViewModel POCO, but also a strongly-typed ViewData object: 我不是dynamic ViewBag属性的粉丝,因此对于我的所有页面,我既定义了强类型的ViewModel POCO,又定义了强类型的ViewData对象:

public abstract class BaseViewData<TModel,TController> : ViewDataDictionary<TModel>

( TController is specified to optionally allow strongly-typed callbacks to the parent Controller ) (指定TController可选择允许对父Controller进行强类型回调)

This is so I can have compile-time verified members, like String PageTitle (in a site-wide base class) and per-page members - it works in tandem with the ViewModel: the BaseViewData -subclass contains one-way data, and the ViewModel -class contains two-way data. 这样我就可以拥有编译时验证过的成员,比如String PageTitle (在一个站点范围的基类中)和每页成员 - 它与ViewModel协同工作: BaseViewData -subclass包含单向数据,并且ViewModel -class包含双向数据。 This works great when you tweak the MSBuild system to precompile your views into the output assembly - no more .aspx or .cshtml files! 当您调整MSBuild系统以将视图预编译到输出程序集中时,这非常有用 - 不再需要.aspx.cshtml文件!

In ASP.NET MVC (using the WebForms view-engine) I have my own base ViewPage subclass: 在ASP.NET MVC中(使用WebForms视图引擎)我有自己的基础ViewPage子类:

public class ViewPage2<TViewModel,TViewData> : ViewPage<TModel> where TViewData : ViewDataDictionary<TModel> {

    private TViewData _data;

    public new TViewData ViewData {
        get {
            if( _data == null ) {
                _data = (TViewData)base.ViewData;
            }
            return _data;
        }
    }
}

I recently brought this over to Razor, easily done: 我最近把它带到了Razor,很容易做到:

public abstract class WebViewPage2<TViewModel,TViewData> : WebViewPage<TModel> where TData : ViewDataDictionary<TModel> {
    // same ViewData property code as above
}

In the .cshtml files you can manually specify the base-class with the @inherits razor keyword - which requires the fully-qualified concrete generic type name - but alternatively you can omit @inherits and instead specify the @model keyword, which Razor will pass as the TModel argument to WebViewPage<TModel> . .cshtml文件中,您可以使用@inherits razor关键字手动指定基类 - 这需要完全限定的具体泛型类型名称 - 但是您可以省略@inherits而是指定@model关键字,Razor将通过该关键字作为WebViewPage<TModel>TModel参数。

As my base-class adds a second generic type argument, I'd rather not have to type out this ins my .cshtml files: 当我的基类添加第二个泛型类型参数时,我宁愿不必输入我的.cshtml文件:

@inherits MyNamespace.WebViewPage2<MyOtherNameSpace.Views.FooViewModel,MyOtherNameSpace.Views.FooViewData>

...but instead do this: ......而是这样做:

Web.config Web.config文件

<system.web.webPages.razor>
    <pages pageBaseType="MyNamespace.WebViewPage2">
        ...

MyPage.cshtml MyPage.cshtml

@model FooViewModel
@data FooViewData

But this would require extending the Razor View-engine somehow - but this is non-obvious as it requires extending the Razor parser itself so it recognises @data TViewData and passes it as the second type argument. 但这需要以某种方式扩展Razor View引擎 - 但这是不明显的,因为它需要扩展Razor解析器本身,因此它识别@data TViewData并将其作为第二类型参数传递。

You can implement an inheriting ViewClass like this (be careful with the namespace, it must not be changed): 您可以像这样实现一个继承的ViewClass(注意命名空间,不能更改它):

namespace System.Web.Mvc {
     public abstract class WebViewPage<TViewModel, TModel> : WebViewPage<TModel> where TViewModel : class {
         private TViewModel _viewModel;

         public TViewModel ViewModel {
             get {
                 if (_viewModel == null) {
                    throw new InvalidOperationException("No ViewModel defined for this View.");
                 }
                 return _viewModel;
             }
             set { _viewModel = value; }
         }

         public override void InitHelpers() {
              base.InitHelpers();

              if (this.ViewBag.ViewModel == null) {
                 // No ViewModel defined => set null.
              }
              else if (!(this.ViewBag.ViewModel is TViewModel)) {
                 throw new InvalidOperationException(string.Format("The specified ViewModel value is of type '{0}' and must be of type '{1}'.", this.ViewBag.ViewModel.GetType(), typeof(TViewModel)));
             } else {
                _viewModel = this.ViewBag.ViewModel;
             }
        }
    }
}

Then you dont have to change the web.config or anything else and can instantiate the view like this: 然后你不必更改web.config或其他任何东西,并可以像这样实例化视图:

 @model ViewModelType, (Input?)ModelType

The typed ViewModel (Type would by ViewModelType) is then available in the view via @ViewModel . 然后,通过@ViewModel在视图中可以使用键入的ViewModel(View by ViewModelType类型)。 The Model of type (Input)ModelType is still available via @Model like it always was. 类型(输入)ModelType的模型仍然像@Model一样可用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM