Rendu partiel à partir d'un dossier différent (non partagé)

256

Comment puis-je avoir une vue rendre un partiel (contrôle utilisateur) à partir d'un dossier différent? Avec l'aperçu 3, j'avais l'habitude d'appeler RenderUserControl avec le chemin complet, mais avec la mise à niveau vers l'aperçu 5, ce n'est plus possible. Au lieu de cela, nous avons obtenu la méthode RenderPartial, mais elle ne m'offre pas les fonctionnalités que je recherche.

Boris Callens
la source

Réponses:

443

Il suffit d'inclure le chemin d'accès à la vue, avec l'extension de fichier.

Le rasoir:

@Html.Partial("~/Views/AnotherFolder/Messages.cshtml", ViewData.Model.Successes)

Moteur ASP.NET:

<% Html.RenderPartial("~/Views/AnotherFolder/Messages.ascx", ViewData.Model.Successes); %>

Si ce n'est pas votre problème, pourriez-vous s'il vous plaît inclure votre code qui fonctionnait avec RenderUserControl?

Elijah Manor
la source
19
Je souhaite que nous puissions simplement dire / AnotherFolder / Messages
Simon_Weaver
4
@Simon_Weaver Vous pouvez y parvenir. Une façon serait de modifier ViewEngine et de remplacer sa FindPartialViewméthode avec quelque chose commeif(partialViewName.Contains"/")partialViewName="~/Views/"+partialViewName;
Arnis Lapsa
2
Fonctionne également dans le moteur MVC 3 Razor, mais comme ci-dessus, vous avez besoin de l'extension (.cshtml).
Chris
Si son sous différent, vous devrez donner le chemin "~ / Areas / TestArea / Views / Shared / _SomePartial.mobile.cshtml"
sandeep talabathula
Comment gérez-vous les différentes cultures de cette vue partielle (par exemple ~ / Views / AnotherFolder / Messages.fr.cshtml)?
jasdefer
29

Dans mon cas, j'utilisais MvcMailer (https://github.com/smsohan/MvcMailer) et je voulais accéder à une vue partielle à partir d'un autre dossier, qui n'était pas dans "Shared". Les solutions ci-dessus n'ont pas fonctionné, mais l'utilisation d'un chemin relatif l'a été.

@Html.Partial("../MyViewFolder/Partials/_PartialView", Model.MyObject)
Aaron Sherman
la source
De même @ Html.Partial ("../ Shared / _PartialView") pour utiliser le dossier partagé.
Curtis Yallop
11
Je trouve que cela ne fonctionne pas sans l'extension .cshtml à la fin.
Luke
28

Si vous utilisez cet autre chemin la plupart du temps, vous pouvez le corriger définitivement sans avoir à spécifier le chemin tout le temps. Par défaut, il recherche les vues partielles dans le dossier View et dans le dossier Shared. Mais dites que vous voulez en ajouter un.

Ajoutez une classe à votre dossier Modèles:

public class NewViewEngine : RazorViewEngine {

   private static readonly string[] NEW_PARTIAL_VIEW_FORMATS = new[] {
      "~/Views/Foo/{0}.cshtml",
      "~/Views/Shared/Bar/{0}.cshtml"
   };

   public NewViewEngine() {
      // Keep existing locations in sync
      base.PartialViewLocationFormats = base.PartialViewLocationFormats.Union(NEW_PARTIAL_VIEW_FORMATS).ToArray();
   }
}

Ensuite, dans votre fichier Global.asax.cs, ajoutez la ligne suivante:

ViewEngines.Engines.Add(new NewViewEngine());
Paul
la source
6
Bien sûr, je me rends compte que cette question a été posée il y a longtemps. Je pensais que j'y ajouterais pour les futurs Googlers et les futurs Bingers.
Paul
- Ne fonctionnera pas dans .Net Core 2.2, car RazorViewEngine.PartialViewLocationFormats n'existe pas.
Demian Berisford-Maynard
7

Pour un contrôle utilisateur nommé myPartial.ascx situé dans le dossier Views / Account, écrivez comme suit:

<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>
Rahatur
la source
5

J'ai créé une solution de contournement qui semble fonctionner assez bien. J'ai trouvé la nécessité de basculer vers le contexte d'un autre contrôleur pour la recherche de nom d'action, la recherche de vue, etc. Pour implémenter cela, j'ai créé une nouvelle méthode d'extension pour HtmlHelper:

public static IDisposable ControllerContextRegion(
    this HtmlHelper html, 
    string controllerName)
{
    return new ControllerContextRegion(html.ViewContext.RouteData, controllerName);
}

ControllerContextRegion est défini comme:

internal class ControllerContextRegion : IDisposable
{
    private readonly RouteData routeData;
    private readonly string previousControllerName;

    public ControllerContextRegion(RouteData routeData, string controllerName)
    {
        this.routeData = routeData;
        this.previousControllerName = routeData.GetRequiredString("controller");
        this.SetControllerName(controllerName);
    }

    public void Dispose()
    {
        this.SetControllerName(this.previousControllerName);
    }

    private void SetControllerName(string controllerName)
    {
        this.routeData.Values["controller"] = controllerName;
    }
}

La façon dont cela est utilisé dans une vue est la suivante:

@using (Html.ControllerContextRegion("Foo")) {
    // Html.Action, Html.Partial, etc. now looks things up as though
    // FooController was our controller.
}

Il peut y avoir des effets secondaires indésirables si votre code nécessite que le controllercomposant route ne change pas, mais dans notre code jusqu'à présent, il ne semble pas y avoir de points négatifs à cette approche.

Jacob
la source
4

Le VirtualPathProviderViewEngine, sur lequel le WebFormsViewEngine est basé, est censé prendre en charge les caractères "~" et "/" à l'avant du chemin afin que vos exemples ci-dessus devraient fonctionner.

J'ai remarqué que vos exemples utilisent le chemin "~ / Account / myPartial.ascx", mais vous avez mentionné que votre contrôle utilisateur se trouve dans le dossier Views / Account. As-tu essayé

<%Html.RenderPartial("~/Views/Account/myPartial.ascx");%>

ou est-ce juste une faute de frappe dans votre question?

Andrew Stanton-Nurse
la source
0

vous devriez essayer ceci

~/Views/Shared/parts/UMFview.ascx

placez ~/Views/devant votre code

mounir
la source
0

Créez un moteur de vue personnalisé et disposez d'une méthode qui renvoie un ViewEngineResult Dans cet exemple, vous venez de remplacer le _options.ViewLocationFormatset d'ajouter votre répertoire de dossiers:

public ViewEngineResult FindView(ActionContext context, string viewName, bool isMainPage)
        {
            var controllerName = context.GetNormalizedRouteValue(CONTROLLER_KEY);
            var areaName = context.GetNormalizedRouteValue(AREA_KEY);

            var checkedLocations = new List<string>();
            foreach (var location in _options.ViewLocationFormats)
            {
                var view = string.Format(location, viewName, controllerName);
                if (File.Exists(view))
                {
                    return ViewEngineResult.Found("Default", new View(view, _ViewRendering));
                }
                checkedLocations.Add(view);
            }

            return ViewEngineResult.NotFound(viewName, checkedLocations);
        }

Exemple: https://github.com/AspNetMonsters/pugzor

Demian Berisford-Maynard
la source
-5

Essayez d'utiliser RenderAction("myPartial","Account");

Siva Kandaraj
la source
3
Veuillez lire la question pendant que l'utilisateur pose une question sur l'affichage dans un dossier différent où se trouve le dossier dans votre code?
Pamma