Как реализовать навигацию по страницам типа мастера в приложении ASP.NET MVC 2? - PullRequest
2 голосов
/ 02 июля 2010

Я использую ASP.NET MVC 2 и .Net 3.5 с Visual Studio 2008.

Хорошо, то, что я имею в виду под «навигацией по страницам типа мастера», это сайт, на котором у вас есть списокэтапы данного процесса или рабочего процесса.Существует какое-то визуальное обозначение, указывающее, на какой части сцены вы находитесь.Я уже реализовал эту часть (хотя она пахнет как хак) с помощью следующего:

css класс current обозначает активную страницу.класс css notcurrent обозначает неактивную страницу (то есть страницу, на которой вы не находитесь)

Я объявил следующий метод в классе с именем NavigationTracker.

public static String getCss(String val, String currView)
{
    String result = String.Empty;
    String trimmedViewName = currView.Substring(currView.LastIndexOf("/") + 1).Replace(".aspx", "");
    if (val.ToLower().Equals(trimmedViewName.ToLower()))
        result = "current";
    else
        result = "notcurrent";

    return result;
}

У меня есть свои этапы в управлении, как это:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="TheProject.Models" %>

<link href="../../Content/custom.css" rel="stylesheet" type="text/css" />
<% 
   String currentView = ((WebFormView)ViewContext.View).ViewPath;
%>
<table width="100%">
    <tr>       
        <td class="<%= NavigationTracker.getCss("LogIn",currentView)%>"  style="width:18%;">Log In</td>
        <td class="<%= NavigationTracker.getCss("YearSelect",currentView)%>"  style="width:18%;">Year Section</td>
        <td class="<%= NavigationTracker.getCss("GoalEntry",currentView)%>"  style="width:18%;">Goals</td>
        <td class="<%= NavigationTracker.getCss("AssessmentEntry",currentView)%>"  style="width:18%;">Assessment</td>
        <td class="<%= NavigationTracker.getCss("SummaryEntry",currentView)%>"  style="width:18%;">Summary</td>                
    </tr>
</table>

******************* ЭТО ГДЕМне нужна помощь ***********

Чтобы дополнить этот процесс, я хотел бы создать пользовательский элемент управления, в котором есть только кнопки «Предыдущая» и «Следующая» для управления этим процессом.Пока что одна загвоздка, с которой я столкнулся, заключается в том, что этот элемент управления нельзя поместить на главную страницу, но его необходимо включить в каждое представление, прежде чем форма закроется.Я не против этого.Нажав кнопку «Предыдущий» или «Далее», отправьте содержащую форму для соответствующего действия;однако я не уверен, как сделать следующее:

1) Определить, была ли нажата кнопка «Предыдущий» или «Следующий». 2) Показать / скрыть логику кнопок «Предыдущий» и «Следующий» в начале и конце процесса соответственно..

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

Возможно, мне просто нужно поместить эту последнюю часть в новый вопрос.Мой главный вопрос здесь с управлением навигацией.Любые указатели или советы по работе с этой логикой и обнаружению нажатия Next или Previous будут наиболее полезными.

EDIT 1

У меня была мысль поставить скрытое полев элементе управления, который отображает кнопки «Предыдущий и следующий».В зависимости от того, какая кнопка была нажата, я бы использовал JavaScript для обновления значения скрытых полей.Теперь проблема заключается в том, что скрытое поле никогда не создается и не отправляется вместе с формой.Я изменил аргументы поста контроллера, чтобы принять дополнительное поле, но оно никогда не отправляется, как и в FormCollection.

Вот код для скрытого поля.Обратите внимание, что он генерируется в пользовательском элементе управления, который вызывается внутри формы в родительском представлении (надеюсь, это имеет смысл).

<% Html.Hidden("navDirection", navDirection); %>

Мысли?

РЕДАКТИРОВАТЬ 2

Я решил все эти проблемы.Я опубликую код подробно во вторник самое позднее.Решение, представленное ниже, вероятно, будет выбрано в качестве ответа, поскольку это привело меня к правильному мыслительному процессу.

Короче говоря, решение заключалось в том, чтобы иметь класс Navigation, подобный классу, предложенному с логикой для определения следующей или предыдущей страницы на основе текущего представления и списка строк всех представлений.Частичное представление / пользовательский элемент управления были созданы для отображения кнопок «Предыдущая / Следующая».Пользовательский элемент управления имеет 2 скрытых поля: 1) одно со значением текущего представления 2) поле, указывающее направление навигации (предыдущее или следующее).JavaScript использовался для обновления значения скрытого поля навигации в зависимости от того, какая кнопка была нажата.Логика в пользовательском элементе управления определяет, отображать или нет кнопки «Предыдущий» или «Следующий» в зависимости от первого и последнего представлений в мастере по сравнению с текущим представлением.

Все сказано, я довольнодоволен результатами.Я, вероятно, найду некоторые проблемы с запахом кода, когда вернусь к этому, но пока это работает.

Спасибо всем за вашу помощь!

РЕДАКТИРОВАТЬ 3 - РЕШЕНИЕ

Вот код для элемента управления, который я построил для отображения кнопок навигации «Далее» и «Предыдущий»:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl" %>
<%@ Import Namespace="Project.Models" %>
<link href="../../Content/custom.css" rel="stylesheet" type="text/css" />
<script type="text/javascript" >
    function setVal(val) {
        var nav = document.getElementById("NavigationDirection");
        nav.value = val;
    }
</script>

<% 
   String currentView = ((WebFormView)ViewContext.View).ViewPath;    
   String navDirection = "empty";
   currentView = NavigationTracker.getShortViewName(currentView);
%>

<input type="hidden" value="<%= currentView %>" name="CurrentView" id="CurrentView" />
<input type="hidden" value="<%= navDirection %>" name="NavigationDirection" id="NavigationDirection" />

<% if( currentView != NavigationTracker.FirstPage) {  %>
    <div style="float:left;">        
        <input type="submit" value="Previous" onclick="setVal('previous')" />      <!-- On click set navDirection = "previous" -->
    </div>
<% } %>

<% if (currentView != NavigationTracker.LastPage)
   {  %>
<div style="float:right;">
    <input type="submit" value="Next" onclick="setVal('next')"  />              <!-- On click set navDirection = "next" -->
</div>    
<% } %>

Оттуда вы визуализируете элемент управления непосредственно перед закрывающим тегом формы в представлениях, которые вам нужны, например:

<% Html.RenderPartial("BottomNavControl"); %>
    <% } %>

Теперь я не могу опубликовать весь код NavigationTracker, но суть того, как он работает, может быть выведена из выбранного ответа и следующего фрагмента, который возвращает имя представления на основе текущего представления и направления. (предыдущий или следующий).

public String NextView
{
    get
    {
        if (String.IsNullOrEmpty(this.NavigationDirection)) return string.Empty;
        int index = this.MyViews.IndexOf(this.CurrentView);
        String result = string.Empty;
        if (this.NavigationDirection.Equals("next") && (index + 1 < MyViews.Count ))
        {
            result = this.MyViews[index + 1];
        }
        else if (this.NavigationDirection.Equals("previous") && (index > 0))
        {
            result = this.MyViews[index - 1];
        }
        return result;
    }
}

Теперь выполнение всего этого имеет несколько побочных эффектов, которые можно легко считать запахом кода. Во-первых, мне нужно изменить все методы контроллера, помеченные [HTTPPOST], чтобы они принимали объект NavigationTracker в качестве параметра. Этот объект содержит вспомогательные методы и свойства CurrentView & NavigationDirection. Как только это будет сделано, я могу получить следующий вид одинаково во всех моих действиях:

return RedirectToAction(nav.NextView);

где nav имеет тип NavigationTracker.

Еще одно замечание: свойства FirstPage и LastPage в NavigationTracker являются статическими, поэтому я фактически использую NavigationTracker.FirstPage в моем файле global.asax.cs для своей маршрутизации. Это означает, что я могу перейти к своему классу NavigationTracker и изменить поток в одном месте для всего приложения.

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

Надеюсь, это поможет.

Ответы [ 3 ]

3 голосов
/ 02 июля 2010

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

public class WizardView
{
     public List<string> Steps { get; set; }
     public int CurrentStepNumber {get;set;}

     public bool ShowNextButton
     {
         get
         {
             return CurrentStepNumber < this.Steps.Count-1;
         }
     }  

     public bool ShowPreviousButton
     {
         get
         {
             return CurrentStepNumber > 0;
         }
     }  
}

И ваш контроль:

<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<WizardView>" %>


    <table width="100%">
       <tr>    

         <% 
            int index=0;
            foreach(string step in Model.Steps)
            {
            %>   
                <td class='<%=Model.CurrentStep==index?"current":"notcurrent" %> style="width:18%;">
                       <%= step %>
               </td>
           <%
                index++;  
             } %>
        </tr>
</table>

В вашем контроллере

public ActionResult MyAction(int step)
{
    return View (new WizardControl {
       Steps = Myrepository.getSteps();
       CurrentStep = step
     });
}

}

1 голос
/ 02 июля 2010

это может быть не совсем то, что вы ищете, но что если вы используете jQuery, чтобы скрывать и показывать теги DIV.Затем пользователь получит опыт работы с мастером, пока весь контент находится внутри одного представления.Тогда все это может быть легко обработано с помощью одного контроллера

Другой вариант может заключаться в создании отдельного «шага» представления для каждого шага мастера

http://example.com/page/step/1

Затем выможет создать объект класса, содержащий ВСЕ поля, и добавить его при навигации по мастеру, добавив в объект сеанса

(Custom.Class.Obj)Session["myWizard"]

Таким образом, он позволяет создавать стандартные представления изагрузить имеющуюся у вас информацию из объекта сеанса.

0 голосов
/ 03 июля 2010

Вот еще один путь - расширение подхода WizardView. То, что вы описываете, является механизмом состояний - чем-то, осведомленным о состояниях, переходах, поведении и триггерах, связанных с каждым.

Если вы ознакомитесь с реализацией, например, без сохранения состояния (http://code.google.com/p/stateless/),), вы увидите, что вы можете описать состояния (шаги в подходе вида мастера) и триггеры, связанные с каждым. На основании вашего описания вы могли бы либо сохраните эту информацию в своем состоянии, либо подключитесь к ней, либо, возможно, полностью игнорируйте ее, потому что двигатель обрабатывает все переходы дискретно.

Чтобы продвинуться дальше, ваш обзорный провод теперь может стать довольно общим. Не нужно, чтобы представление осознавало полноту операций, полагаясь только на саму модель представления.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...