根据模型中的属性显示不同的图像

时间:2013-02-12 09:29:54

标签: asp.net-mvc

我需要根据属性的具体价值显示不同的图像 这是我完成这项任务的方法。

我有模特:

public class DetailInfoViewModel
{
    public string Status {get; set;}
    public string StatusImageName {get; set;}
    ... other fields
}

在行动中:

var model = ...// create view model and fill properties    
model.StatusImageName = GetImageFileNameForStatus(model.Status.ToLower());

,主要方法:

private string GetImageFileNameForStatus(string status)
{
    if (status == "payed" || status == "approved")
        return "payed.png";

    if (status == "printed")
        return "not-pay.png";

    if (status == "closed")
        return "closed.png";

    if (status == "transfer")
        return "transfer.png";

    return string.Empty;
}

在视图中我有简单的html:

<div class="pull-right">
    <img src="@Url.Content("~/Images/" + Model.StatusImageName)"/>
</div>

但这种方式很难看。如果我重命名图像或进行印刷错误,则此代码将无法正常工作 还有更好的方法吗?

2 个答案:

答案 0 :(得分:1)

为了减少错误,请考虑将状态设为枚举

enum Status { Payed, Printed, Closed, Approved, Transfer}

并使用T4MVC生成与资源的强大链接:

private string GetImageFileNameForStatus(Status status)
{
    switch(status){
      case Payed:
      case Approved:
        // This is generated by T4MVC for you
        return Links.Content.Images.payed_png;
      case Printed:
        return Links.Content.Images.not_pay_png;          
      // ... etc.
      default:
        return Links.Content.Images.default_png;
    }
}

您可以将信息保存在Dictionary<Status, string>内,而不是switch语句,但这是一个实现细节。

然后您可以使用与此类似的内容:

<img src="@Model.StatusImageName" alt="@Model.Status"/>

注意:记得添加alt属性!

如果重命名图像或移动它们,编译现在将会中断。

对于大多数小型系统,此解决方案应该是可接受的。如果您对更复杂的纯粹OOP&#34;感兴趣,请继续阅读。解决方案(可能会受到过度工程的影响,具体取决于用例)。

从纯粹的OOP角度来看,这种转换 - 虽然相对简单 - 并不是最美丽的解决方案。您可以考虑State Pattern.NET implementation)。

interface IStatus{
    string InfoImage{get;}
}

class PayedStatus : IStatus {    
    public string InfoImage{get{return Links.Content.Images.payed_png;}}
}

class PrintedStatus : IStatus {    
    public string InfoImage{get{return Links.Content.Images.not_pay_png;}}
}

// etc.

你的模特:

public class DetailInfoViewModel
{
  ... 
  public IStatus Status{get;set;}
}

在您看来:

<img src="@Model.Status.InfoImage" alt="Status"/>

如果存在特定于给定状态的事物,则此方法甚至更好。您可以在相应的IStatus实现中整齐地封装与特定状态相关的所有内容。

同样,从面向对象的设计角度来看,UI细节(要显示的图像)成为模型的一部分感觉很奇怪。另一方面,它是一个视图模型,为什么不呢。如果你想要顽固的OOP以及系统的复杂性和要求,你可以考虑Visitor Pattern.NET implementation):

interface IStatusVisitor<T>{
   T VisitPayedStatus<T>(PayedStatus status);
   T PrintedStatus<T>(PrintedStatus status);
   // ...
}

interface IStatus{
    T Accept(IStatusVisitor<T> visitor);
}

class PayedStatus : IStatus {    
    public T Accept(IStatusVisitor<T> visitor){
        return visitor.VisitPayedStatus(this);
    }
}

class PrintedStatus : IStatus {    
    public T Accept(IStatusVisitor<T> visitor){
        return visitor.VisitPrintedStatus(this);
    }
}


class InfoImageVisitor : IStatusVisitor<string>{

  public string VisitPayedStatus(PayedStatus status){
    return Links.Content.Images.payed_png;
  }

  public string VisitPrintedStatus(PrintedStatus status){
    return Links.Content.Images.not_pay_png;
  }

}


<img src="@Model.Accept(new InfoImageVisitor())" alt="Status"/>

这样,您可以将有关信息图像的所有内容从状态类移到单独的类中。

但正如我所说,这已经被认为是一种过度工程的情况。这取决于您的系统的要求。

总的来说:它非常值得阅读设计模式。

答案 1 :(得分:0)

我不知道这是最好的方法,但你可以将图像名称定义为状态名称,我的意思是

status | statusImage |
----------------------
 payed |   payed.png |
closed |  closed.png |
   ... |         ... |

然后

<div class="pull-right">
    <img src="@Url.Content("~/Images/" + Model.Status) + ".png""/>
</div>