Search code examples
c#razororchardcmsorchardcms-1.8

Pass an arbitrary value (such as an image width) with BuildDisplay to an alternate


We want to share the following logic among our Orchard views.

@helper CreateImgFromMediaPart(dynamic mediaPart, int width = 150)
{
    var imgSrc = mediaPart != null ? mediaPart.MediaUrl : string.Empty;
    var imgAlt = mediaPart != null ? mediaPart.AlternateText : string.Empty;
    <img alt="@imgAlt" src="@imgSrc" />
}

Toward that goal, we created an alternate called Media-Image.SizedThumbnail.cshtml that renders the Media_Image shape.

Media-Image.SizedThumbnail.cshtml - create a shared alternate

@using Orchard.ContentManagement
@using Orchard.MediaLibrary.Models
@using Orchard.Utility.Extensions
@model dynamic

    @{
        ContentItem contentItem = Model.ContentItem;
        var media = contentItem.As<MediaPart>();
        var image = contentItem.As<ImagePart>();
        var width = media.Width != null ? media.Width : 200; // get the width
    }

    <div>
        <img src="@Display.ResizeMediaUrl(
                       Width: width, 
                       Mode: "max", 
                       Alignment: "middlecenter", 
                       Path: media.MediaUrl)" />
    </div>

We can successfully call that alternate with Display(BuildDisplay(mediaPart, "ResizeThumbnail)). It almost works. The challenge is to pass the Width that we want the image to become.

MyView.cshtml - Try to pass the Width.

// Microsoft.CSharp.RuntimeBinder.RuntimeBinderException:
// 'Orchard.MediaLibrary.Models.MediaPart' does not contain a definition for 'Width'
// This is odd to me, because mediaPart is dynamic
mediaPart.Width = 200;
@Display(BuildDisplay(mediaPart, "SizedThumbnail")

// Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 
// The best overloaded method match for
// BuildDisplay(Orchard.ContentManagement.IContent, string, string)' 
// has some invalid arguments
var mediaPartExpando = MyFunctions.ToDynamic(mediaPart);
mediaPartExpando.Width = 200;
@Display(BuildDisplay(mediaPartExpando, "SizedThumbnail")

// System.NullReferenceException: Object reference not set to an instance of an object.
var mediaPartExpando = MyFunctions.ToDynamic(mediaPart);
mediaPartExpando.Width = 200;
var mediaPartAgain = mediaPartExpando as IContent;
@Display(BuildDisplay(mediaPartAgain, "SizedThumbnail")

I am clearly battling with the compiling and runtime. How can we pass a width through BuildDisplay to an alternate?


Solution

  • Firstly, it's not great that you would call BuildDisplay from a view. It would be better, if possible, if the driver or controller that is responsible for creating this MyView.cshtml did that.

    Secondly, what BuildDisplay returns is a shape, to which you can add properties dynamically. So you should be able to do this:

    @Display(BuildDisplay(mediaPart, "SizedThumbnail").Width(200))