2010-11-29 3 views
2

Я пытаюсь отобразить частичный вид в виде строки, чтобы он мог быть возвращен как HTML для вызова jQuery ajax. После многих поисков я нашел этот код.Предоставление искрового обзора строки

public string RenderAsString(string viewName, string modelName, object model) 
{ 
    // Set up your spark engine goodness. 
    var settings = new SparkSettings().SetPageBaseType(typeof(SparkView)); 
    var templates = new FileSystemViewFolder(Server.MapPath("~/Views")); 
    var engine = new SparkViewEngine(settings) { ViewFolder = templates }; 


    // "Describe" the view (the template, it is a template after all), and its details. 
    var descriptor = new SparkViewDescriptor().AddTemplate(@"Shared\" + viewName + ".spark"); 

    // Create a spark view engine instance 
    var view = (SparkView)engine.CreateInstance(descriptor); 

    // Add the model to the view data for the view to use. 
    view.ViewData[modelName] = model; 

    // Render the view to a text writer. 
    var writer = new StringWriter(); view.RenderView(writer); 

    // Convert to string 
    return writer.ToString(); 
} 

Но когда следующая строка выполняет:

var view = (SparkView)engine.CreateInstance(descriptor); 

Я получаю следующее сообщение об ошибке:

Dynamic view compilation failed. An object reference is required for the non-static field, method, or property 'DomainModel.Entities.Region.Id.get.

Это мой частичный вид:

<ViewData Model="Region" /> 

<div id="${ Region.Id }" class="active-translation-region-widget" > 
    <label>${Region.RegionName}</label> 
     ${ Html.CheckBox("Active") } 
</div> 

Это Безразлично» t, похоже, распознает модель.

P.S. Когда я вызываю вид из родительского вида, например,

<for each="var region in Model"> 
    <ActiveTranslationRegion Region="region" if="region.Active==true"></ActiveTranslationRegion> 
</for> 

Он отлично выглядит. Что я делаю не так?

ответ

2

Просто глядя на него, я думаю, что следующая строка является проблемой:

<ViewData Model="Region" /> 

Вместо этого следует читать:

<viewata model="Region" /> 

Обратите внимание на нижнем регистр «модель». Это связано с тем, что model - это особый случай, поскольку за кулисами он выполняет бросок на строго типизированную модель. Верхний будет определять переменную с именем Model в сгенерированном классе вида и присвоить ей значение Region. Используя нижеследующий вариант ниже, на самом деле создайте переменную Model, но также добавьте ее к строго типизированному экземпляру Region, который исходит из словаря ViewData.

Примечание При использовании Model в коде, хотя, как вы делали в цикле for each, она должна быть в верхнем регистре, который является правильным в вашем случае. Еще раз, это единственный частный случай, потому что он тянет строго типизированную модель из словаря ViewData.

Еще одна вещь - <viewata model="Region" /> должна быть объявлена ​​в родительском представлении и может быть определена только один раз на странице, поэтому вы не можете переопределить ее в частичном представлении. Если это частичное представление, вы должны использовать его, передав часть модели, как это было сделано во втором примере выше.

Причина для исключения выше, потому что он пытается получить Id собственности в качестве статического элемента от RegionТипа, а не запрашивая Id собственности на ваш например из Region как часть вашего ViewModel.

В качестве примечания стороны, код, чтобы добраться, где вы хотите, немного искалечен. Вы можете найти более аккуратные способы сделать то, что хотите, проверив некоторые из Direct Usage Samples, но я понимаю, что это, вероятно, просто всплеск, чтобы увидеть, как он работает ...:)

Update в ответ на ваш follow up question/answer

Я совершенно уверен, что проблема с принятием Region в следующий вызов:

... снова вниз именование. Да, вы можете иметь только один model за просмотр, как я уже говорил, так что вам нужно сделать, это удалить следующие из верхней части вашей парциальное:

<viewdata model="Region" /> 

Это то, что вызывает проблему. Я бы переименовать пункт вдаваясь в ваш частичный так:

<ActiveTranslationRegion ActiveRegion="region" if="region.Active==true"> 

и тогда ваш парциальное будет выглядеть следующим образом:

<form action="/Translation/DeactivateRegion" class="ui-widget-content active-translation-region-widget"> 
    <input type="hidden" name="Id" value="${ActiveRegion.Id}" />   
    <label class="region-name">${ ActiveRegion.RegionName }</label> 
    <input class="deactivate-region-button" type="image" src=${Url.Content("~/Content/Images/Deactivate.png")} alt="Deactivate" /> 
</form> 

Примечание Я использую ActiveRegion, потому что в Спарк анализаторе ActiveRegion получает объявленную переменную и присваивает значение region в текущей области действия при прохождении через for loop. Не нужно придерживаться религиозно до model - потому что вы ушли и прошли в куске model теперь, когда вы объявили как ActiveRegion. О, и вы можете придерживаться имени Region, если вы действительно этого хотите, я просто изменил его, чтобы сделать точку, и потому что у вас есть Type под названием Region в вашем коде, и я не большой поклонник причудливых проблем, используя одно и то же имя для переменной, как тип может привести. Плюс это делает его немного яснее.

Недостаток вызова метода Html.RenderPartial не сразу очевиден. Одна вещь, которую вы теряете, - это рендеринг с тремя проходами, который предлагает Spark. Если вы используете синтаксис тега (что предпочтительнее), вы сможете укладывать частичные части в частичных до нескольких уровней вниз, передавая переменные, которые кормят каждую частичную, что им нужно, по стеку. Он получает действительно мощный - начните анализировать структуры сетки данных, где строки и ячейки являются отдельными частицами, которые получают переменные, которые им нужны из модели, все они красивы и чисты в отдельных управляемых файлах просмотра. Не останавливайтесь на этом, начинайте думать о таргетинге на базу содержимого заголовка и нижнего колонтитула на переменные или три макета столбцов, которые создают панель мониторинга, которая делает все виды на индивидуально уложенных частицах на многие уровни глубокими.

Вы теряете всю эту гибкость при использовании стандартного метода ASP.NET MVC Helper для болота Html.RenderPartial(). Будьте осторожны, это более чем вероятно решение, подобное выше.

Позвольте мне знать, если это работает ...
Все лучшее
Rob G

+0

Роберт, спасибо за Ваш ответ. Вы правильно относились к случаю ключевого слова модели в частичном представлении. В конце концов, с помощью коллеги, у которого больше опыта с Spark, чем у меня, я довольно много рефакторинг кода. Дополнительную информацию см. В моем ответе ниже. – 2010-12-01 09:36:04

+0

Спасибо за обновление, я обновил свой ответ в ответ на ваше обновление. – 2010-12-03 10:03:33

0

Я переработан код и вид совсем немного. В конце концов, все, что я действительно пытаюсь сделать, - иметь родительский вид (не показан) итерации по IEnumerable и для каждой итерации - частичное представление (ActiveTranslationRegion), которое отображает некоторый Html для представления модели региона.

Я также хочу быть способным вызвать метод действия с помощью вызова ajax для визуализации частичного представления ActiveTranslationRegion, передавая ему модель отдельного региона. Я обработал код соответствующим образом.

Частичный вид (_ActiveTranslationRegion.spark)

<viewdata model="Region" /> 

<form action="/Translation/DeactivateRegion" class="ui-widget-content active-translation-region-widget"> 
    <input type="hidden" name="Id" value="${Model.Id}" />   
    <label class="region-name">${ Model.RegionName }</label> 
    <input class="deactivate-region-button" type="image" src=${Url.Content("~/Content/Images/Deactivate.png")} alt="Deactivate" /> 
</form> 

Уведомление помощью я могу сослаться на модели в представлении, как предложено RobertTheGrey (см. Выше)

Я удалил весь код, чтобы вернуть вид в виде строки и просто создал метод метод действия, возвращающего partialViewResult:

[UnitOfWork] 
public PartialViewResult ActivateRegion(int id) 
{ 
    var region = _repos.Get(id); 
    if (region != null) 
    {  
     region.Active = true; 
     _repos.SaveOrUpdate(region); 
    } 

    return PartialView("_ActiveTranslationRegion", region); 
} 

Одна вещь, которую я должен был сделать изменить мой родительский вид выглядеть вот так :

<div id="inactive-translation-regions-panel"> 
    <h3 class="ui-widget-header">Inactive Regions</h3> 
    <for each="var region in Model"> 
     <span if="region.Active==false"> 
       # Html.RenderPartial("_InActiveTranslationRegion", region); 
     </span> 
    </for> 
</div> 

Если раньше у меня было следующее:

<div id="inactive-translation-regions-panel"> 
    <for each="var region in Model"> 
      <ActiveTranslationRegion Region="region" if="region.Active==true"></ActiveTranslationRegion> 
    </for> 
</div> 

Примечание. Мне нужно вызвать Html.RenderPartial, а не использовать этот элемент. Если я пытаюсь использовать элемент (который я предпочел бы сделать), я получаю следующее сообщение об ошибке:

Only one viewdata model can be declared. IEnumerable<Region> != Region 

Есть ли способ обойти эту проблему?

Update:

Я попробовал вашу рекомендацию, но не повезло. Чтобы воспроизвести проблему, я хочу использовать частичное в двух разных ситуациях. В первом случае у меня есть родительское представление, которое использует модель IEnumerable<Region>, частичная просто использует Region в качестве своей модели. Поэтому в родительском я перебираю по IEnumerable и передаю Region частичным. Во втором случае я хочу позвонить PartialView("_ActiveTranslationRegion", region) из метода действия. Если я удалю <viewdata model="Region" /> из части, я получаю сообщение об ошибке, касающейся модели. Лучший способ обойти эту проблему, я нашел это добавить привязку к файлу bindings.xml:

<element name="partial"># Html.RenderPartial("@name", @model);</element> 

(Примечание: Это, кажется, очень важно сохранить эту запись в файл привязок все на той же строке тэ)

Этот способ я все же могу назвать частичным из метода действий, как описано выше, и передать ему регион как модель, но я также могу заменить свой вызов на Html.RenderPartial в родительском представлении с более «html», подобный тег:

<partial name="_ActiveTranslationRegion" model="region" /> 

Так что мой родитель вид теперь выглядит примерно так:

<div id="inactive-translation-regions-panel"> 
    <h3 class="ui-widget-header">Inactive Regions</h3> 
    <for each="var region in Model"> 
     <span if="region.Active==false"> 
       <partial name="_ActiveTranslationRegion" model="region" /> 
     </span> 
    </for> 
</div> 

Конечно под капотом его еще делает вызов

# Html.RenderPartial("_ActiveTranslationRegion", region); 

Но его лучшее решение, которое мы могли бы придумать.

С уважением, Саймон

Смежные вопросы