简体   繁体   English

MVC Razor 代码重用 - 可以重用此代码吗?

[英]MVC Razor Code Reuse - Can this code be reused?

I've got the following snippet of Razor code, that exists in probably 15 different pages, that I'd like to reuse, if possible:我有以下 Razor 代码片段,可能存在于 15 个不同的页面中,如果可能,我想重用这些代码:

    <div class="col-xs-12">
        @if (@Model.Rating == 0)
        {
            <img src="/Images/Rating/NoRating.jpg" alt="" width="125">
        }
        else if (@Model.Rating == 1)
        {
            <img src="/Images/Rating/One.jpg" alt="" width="125">
        }
        else if (@Model.Rating == 2)
        {
            <img src="/Images/Rating/Two.jpg" alt="" width="125">
        }
        else if (@Model.Rating == 3)
        {
            <img src="/Images/Rating/Three.jpg" alt="" width="125">
        }
        else if (@Model.Rating == 4)
        {
            <img src="/Images/Rating/Four.jpg" alt="" width="125">
        }
        else if (@Model.Rating == 5)
        {
            <img src="/Images/Rating/Five.jpg" alt="" width="125">
        }
    </div>

What I would love to be able to do is to call a method and have the method return this code where I have it in my Razor .cshtml file.我希望能够做的是调用一个方法并让该方法返回这个代码,我在我的 Razor .cshtml 文件中有它。 The method would also have to accept a parameter.该方法还必须接受一个参数。 In this case, the parameter would be a rating value of between 0 and 5. I would then replace all occurrences of @Model.Rating with the parameter value.在这种情况下,参数将是介于 0 和 5 之间的评级值。然后我会将所有出现的 @Model.Rating 替换为参数值。 Is it possible to do this?是否有可能做到这一点? I'd rather not have to resort to a partial view if possible.如果可能,我宁愿不必诉诸局部视图。

What I would love to be able to do is to call a method and have the method return this code where I have it in my Razor .cshtml file.我希望能够做的是调用一个方法并让该方法返回这个代码,我在我的 Razor .cshtml 文件中有它。 The method would also have to accept a parameter.该方法还必须接受一个参数。 In this case, the parameter would be a rating value of between 0 and 5. I would then replace all occurrences of @Model.Rating with the parameter value.在这种情况下,参数将是介于 0 和 5 之间的评级值。然后我会将所有出现的 @Model.Rating 替换为参数值。 Is it possible to do this?是否有可能做到这一点?

Solution 1:解决方案1:

You can create an extension method of HtmlHelper class like this :您可以像这样创建HtmlHelper类的扩展方法:

public static class RatingExtensions
{
    public static MvcHtmlString Rating(this HtmlHelper helper, short rating)
    {
        var imageSrc = "/Images/Rating/";
        switch (rating)
        {
            case 0:
                imageSrc += "NoRating.jpg";
                break;

            case 1:
                imageSrc += "One.jpg";
                break;


            // And so on....

            default:
                throw new IndexOutOfRangeException(string.Format("The following rating: {0} is not expected.",
                    rating));
        }

        return new MvcHtmlString(String.Format("<img src='{0}' alt='' width='125' />", imageSrc));
    }
}

In your view after importing the namespace of your extension method into the view, you call your extension method by writing this line:在将扩展方法的命名空间导入视图后,在视图中,通过编写以下行来调用扩展方法:

@Html.Rating(Model.Rating)

Solution 2:解决方案2:

Just create a partial view and put it into the Shared sub-folder of your Views folder.只需创建一个局部视图并将其放入 Views 文件夹的 Shared 子文件夹中。 Lets name it _Ratring.cshtml.让我们将其命名为 _Ratring.cshtml。 The content of this file muste be the following (Notice @model directive which is in short type):该文件的内容必须如下(注意@model 指令是short类型):

@model short
@{
    var imageSrc = "/Images/Rating/";
    switch (Model)
    {
        case 0:
            imageSrc += "NoRating.jpg";
            break;

        case 1:
            imageSrc += "One.jpg";
            break;

        // And so on....

        default:
            throw new IndexOutOfRangeException(string.Format("The following rating: {0} is not expected.",
                Model));
    }
}

<div class="col-xs-12">
    <img src="@imageSrc" alt="" width="125">
</div>

You use this solution in your view by call Html.RenderPartial method liek this :您可以通过调用Html.RenderPartial方法在您的视图中使用此解决方案:

@{
    Html.RenderPartial("_Rating", Model.Rating);
}

Solution 1 is better because you can move the extension method in its own assembly project and use it accross multiple projects.解决方案 1更好,因为您可以将扩展方法移动到它自己的装配项目中,并在多个项目中使用它。

Option 1选项1

You may create a custom Html helper method.您可以创建自定义 Html 帮助程序方法。 I would prefer to rename the image name from One.jpg to 1.jpg so that you do not need to write much code from the number passed into the string representation of that.我更愿意将图像名称从One.jpg重命名为1.jpg这样您就不需要从传递到该字符串表示的数字中编写大量代码。 You can simply relate your Model.Rating value to the image name as they directly match.您可以简单地将 Model.Rating 值与直接匹配的图像名称相关联。

But if you still want to keep the image names as the string way, You may need to write a switch statement inside your method to convert the integer value to the string value (1 to One, 2 to Two etc..).但是如果您仍然希望将图像名称保留为字符串方式,您可能需要在方法中编写一个 switch 语句来将整数值转换为字符串值(1 到 1、2 到 2 等)。 The problem with this approach is, If you ever add a new rating like 12 or 13, you need to go to this file and update your switch statements again !这种方法的问题是,如果你添加了一个新的评级,比如 12 或 13,你需要去这个文件并再次更新你的 switch 语句! So i prefer the first approach of renaming the image names to match with the numeric representation of Model.Rating value所以我更喜欢重命名图像名称以与Model.Rating值的数字表示相匹配的第一种方法

public static class MyCustomImageExtensions
{
    public static MvcHtmlString RatingImage(this HtmlHelper helper, int imageId,
                                                                      string alt,int width)
    {
        var path = "Images/Rating/NoRating.jpg";
        if (imageId > 0)
        {
            path = string.Format("Images/Rating/{0}.jpg", imageId);
        }
        return new MvcHtmlString(string.Format("<img src='{0}' alt='{1}' width='{2}'>"
                                                                  , path, alt, width));

    }
}

You may call it in your razor view like您可以在剃刀视图中调用它,例如

@Html.RatingImage(Model.Rating,"alt test",250)

You may add the Alternate text property and width to your model so that you do not need to hard code it in your main view.您可以将 Alternate text 属性和宽度添加到您的模型中,这样您就不需要在主视图中对其进行硬编码。

Option 2选项 2

Since you are not doing much logic inside the helper method, you may simply use partial view where you will have the markup you want to use and pass the model properties to that.由于您没有在 helper 方法中做太多逻辑,您可以简单地使用部分视图,在那里您将拥有要使用的标记并将模型属性传递给它。

I would change a lot, but it's really worth it.我会改变很多,但这真的很值得。 Create your own ModelMetadataProvider .创建您自己的ModelMetadataProvider

public class MyModelMetaDataProvider : DataAnnotationsModelMetadataProvider
{
    public override ModelMetadata GetMetadataForProperty(Func<object> modelAccessor, Type containerType, string propertyName)
    {
        var result = base.GetMetadataForProperty(modelAccessor, containerType, propertyName);

        if (string.IsNullOrEmpty(result.TemplateHint)
            && typeof(Enum).IsAssignableFrom(result.ModelType))
        {
            result.TemplateHint = result.ModelType.ToString();
        }

        return result;
    }
}

Register it in the global.asax在 global.asax 中注册

ModelMetadataProviders.Current = new MyModelMetaDataProvider();

Create an Enum:创建一个枚举:

public enum StarRating
{
    NoRating = 0,
    One = 1,
    Two = 2,
    Three = 3,
    Four = 4,
    Five = 5
}

Update your model更新您的模型

public class SomeMethodViewModel
{
  public StarRating Rating { get; set; }
}

Create a Display template创建显示模板

/Views/Shared/DisplayTemplates/StarRating.cshtml /Views/Shared/DisplayTemplates/StarRating.cshtml

@model StarRating

<img src="/Images/Rating/@(Model.ToString()).jpg" alt="" width="125">

In your view:在您看来:

@Html.DisplayFor(m => m.Rating)

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

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