Question

Maintenant, je l'ai vu quelques questions comme celle-ci, mais ce n'est pas exactement ce que je veux demander, donc pour tous ceux qui sont en double crier, je présente mes excuses:)

.

Je l'ai à peine touché ASP.NET MVC, mais de ce que je comprends, il n'y a pas ViewState / ControlState ... bien. Donc, ma question est quelle est l'alternative au maintien de l'état d'un contrôle? Est-ce que nous revenons à la vieille école ASP où nous pourrions simuler ce ASP.NET ViewState / ControlState fait en créant des entrées de formulaire cachés avec l'état du contrôle, ou avec MVC, supposons-nous simplement AJAX toujours et retenons tout côté client état et faire AJAX appels à jour?

Cette question a des réponses, Le maintien de l'état d'affichage dans Asp.net mvc? , mais pas exactement ce que je cherche dans une réponse.

MISE À JOUR: Merci pour toutes les réponses à ce jour. Juste pour éclaircir ce que je ne suis pas à la recherche et ce que je suis à la recherche:

Vous ne cherchez pas:

  • solution de session
  • solution Cookie
  • ne cherche pas à imiter WebForms dans MVC

Ce que je suis / cherchait:

  • Une méthode qui ne retient que l'état lors de la publication si les données sont pas de rebond à un contrôle. Pensez WebForms avec le scénario de seulement lier une grille sur la charge de la page initiale, à savoir que reconsolidation les données en cas de besoin. Comme je l'ai mentionné, je ne cherche pas à imiter WebForms, me demandais quels mécanismes offres MVC.
Était-ce utile?

La solution

La convention est déjà disponible sans sauter à travers des cerceaux trop. L'astuce consiste à câbler les valeurs de base TextBox hors du modèle que vous passez dans la vue.

[AcceptVerbs(HttpVerbs.Get)]   
public ActionResult CreatePost()
{
  return View();
}

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(FormCollection formCollection)
{
  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(formCollection);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(formCollection);
  }
}

Qu'est-ce qui se passe ensuite est le ViewEngine prend la FormCollection et correspond aux clés de la collection avec les noms d'identification / valeurs que vous avez en vous, en utilisant les aides Html. Par exemple:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model["Title"], 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model["Body"]) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

Remarquez la zone de texte et textarea a les ID du titre et du corps? Maintenant, remarquez que je suis en train les valeurs de l'objet modèle de la vue? Depuis que vous avez passé dans un FormCollection (et vous devez définir la vue d'être fortement typé avec un FormCollection), vous pouvez désormais y accéder. Ou, sans fortement taper, vous pouvez simplement utiliser ViewData [ « titre »] (je pense).

POUF Votre ViewState magique. Ce concept est appelé convention sur la configuration.

Maintenant, le code ci-dessus est dans son plus simple, forme la plus brute à l'aide FormCollection. Les choses deviennent intéressantes lorsque vous commencez à utiliser ViewModels, au lieu du FormCollection. Vous pouvez commencer à ajouter votre propre validation de vos modèles / ViewModels et ont la bulle du contrôleur les erreurs de validation personnalisée automatiquement. C'est une réponse pour un autre jour cependant.

Je suggère d'utiliser un PostFormViewModel au lieu de l'objet Post, mais à chacun-son-propre. De toute façon, en exigeant un objet sur la méthode d'action, vous obtenez maintenant une méthode IsValid () vous pouvez appeler.

[AcceptVerbs(HttpVerbs.Post)]
public ActionResult CreatePost(Post post)
{

  // errors should already be in the collection here
  if (false == ModelState.IsValid())
    return View(post);

  try
  {
    // do your logic here

    // maybe u want to stop and return the form
    return View(post);
  }
  catch 
  {
    // this will pass the collection back to the ViewEngine
    return View(post);
  }
}

Et il faudrait être peaufiné votre point de vue fortement typées:

<div id="content">

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: <%= Html.TextBox("Title", Model.Title, 50) %><br />
  Enter the Post Body: <%= Html.TextArea("Body", Model.Body) %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

Vous pouvez prendre un peu plus loin et afficher les erreurs aussi bien dans la vue, directement à partir du ModelState que vous définissez dans le contrôleur.

<div id="content">

  <%= Html.ValidationSummary() %>

  <% using (Html.BeginForm()) { %>

  Enter the Post Title: 
    <%= Html.TextBox("Title", Model.Title, 50) %>
    <%= Html.ValidationMessage("Title") %><br />

  Enter the Post Body: 
    <%= Html.TextArea("Body", Model.Body) %>
    <%= Html.ValidationMessage("Body") %><br />

  <%= Html.SubmitButton() %>

  <% } %>

</div>

Ce qui est intéressant avec cette approche est que vous remarquerez que je ne déclenchaient pas le résumé de validation, ni les messages de validation individuels dans la vue. J'aime pratiquer les concepts DDD, ce qui signifie que mes messages de validation (et résumés) sont contrôlés dans mon domaine et sont transmis sous la forme d'une collection. Puis, je boucle throught il collection (si des erreurs existent) et les ajouter à la collection ModelState.AddErrors actuelle. Le reste est automatique lorsque vous revenez View (post).

Beaucoup de lots de convention est dehors. Quelques livres que je recommande fortement que la couverture de ces modèles dans beaucoup plus de détails sont les suivants:

Et dans cet ordre le premier couvre les noix brutes et les boulons de l'ensemble du cadre MVC. Ce dernier couvre les techniques de pointe en dehors du Relm officiel Microsoft, avec plusieurs outils externes pour vous rendre la vie beaucoup plus facile (le château de Windsor, Moq, etc).

Autres conseils

Le point de vue est censé être muet dans le modèle MVC, juste afficher ce que le contrôleur donne (évidemment, nous finissons souvent avec une il logique mais le principe est pour qu'il ne soit pas) en conséquence, les contrôles aren » t responsable de leur état, il viendra du contrôleur à chaque fois.

Je ne peux pas recommander le livre de Steven Sanderson Pro ASP.NET MVC par Apress assez pour obtenir aux prises avec ce modèle et cette mise en œuvre de celui-ci.

Dans les formulaires Web, les valeurs de contrôle sont maintenues dans le viewstate afin que vous (théoriquement) ne pas besoin de ré-initialiser et comme à chaque publication. Les valeurs sont (encore une fois théoriquement) maintenus par le cadre.

Dans ASP.NET MVC, si vous suivez le paradigme, vous n'avez pas besoin de maintenir l'état des éléments de formulaire. Les valeurs des éléments de formulaire sont disponibles sur poste où votre contrôleur peut agir sur eux (validation, mises à jour de bases de données, etc.). Pour tous les éléments de formulaire qui apparaissent une fois que le poste est traitée, vous (le développeur) sont responsables de leur initialisation - le cadre ne fait pas automatiquement pour vous

.

Cela dit, je l'ai lu sur un mécanisme appelé TempData qui permet à votre contrôleur pour transmettre des données à un autre contrôleur suivant une redirection. Il est en fait une variable de session (ou cookie si vous configurez comme tel), mais il est nettoyé automatiquement après la requête suivante.

La réponse dépend vraiment des types de contrôles que vous essayez de maintenir l'état pour. Pour les contrôles de base, alors il Html est très facile de maintenir l'état avec vos modèles, pour ce faire, vous devez créer une vue fortement typé.

Donc, si nous avions un modèle utilisateur avec les propriétés: Nom d'utilisateur, FullName, E-mail, nous pouvons faire ce qui suit dans la vue:

<%= Html.ValidationSummary() %>

<% using (Html.BeginForm()) { %>
  <fieldset>
    <legend>User details</legend>
    <%= Html.AntiForgeryToken() %>

    <p>
      <label for="Username">Username:</label>
      <%= Html.Textbox("Username", Model.Username, "*") %>
    </p>
    <p>
      <label for="FullName">FullName:</label>
      <%= Html.Textbox("FullName", Model.FullName, "*") %>
    </p>
    <p>
      <label for="Email">Email:</label>
      <%= Html.Textbox("Email", Model.Email, "*") %>
    </p>
    <p>
       <input type+"submit" value="Save user" />
    </p>
  </fieldset>
<% } %>

Nous aurions alors deux actions de contrôleur qui affichent ce point de vue, l'un pour get et un autre pour message:

[AcceptVerbs(HttpVerbs.Get)]
public ActionResult User()
{
  return View(new User())
}

[AcceptVerbs(HttpVerbs.Post)]
[ValidateAntiForgeryToken]
public ActionResult User([Bind(Include = "Username,FullName,Email")]User user)
{
   if (!ModelState.IsValid()) return View(user);

   try
   {
     user.save()
     // return the view again or redirect the user to another page
   }
   catch(Exception e)
   {
     ViewData["Message"] = e.Message;
     return View(user)
   }
}

Est-ce que vous cherchez? Ou voulez-vous maintenir l'état des modèles qui ne sont pas affichés sous une forme entre les demandes?

L'essentiel à retenir est que votre code est exécuté sur le serveur pour la durée de la demande et se termine, la seule information que vous pouvez passer entre vos demandes sont des données de formulaire HTML de base, des paramètres d'URL et les informations de session.

Comme d'autres l'ont mentionné, je recommande fortement Pro Framework ASP.NET MVC Steve Sandersan pour une compréhension complète de travail avec le framework MVC.

  • champs cachés, comme:

    <% using (Html.BeginForm<SomeController>(c=>c.SomeAction(null))) {%>
      <%= Html.Hidden("SomeField", Model.SomeField)%>
      <%= Html.Hidden("AnotherField", Model.AnotherField)%>
    
  • réglage du modèle spécifique et ne pas avoir de champs explicites (u donne des champs cachés). Dans l'exemple ci-dessous, le modèle est rempli par le contrôleur avec des valeurs reçues du dernier message, donc cela permet une option sans js dans la page qui peut filtrer en fonction d'un statut:

    Some Filter: <% using( Html.BeginForm<SomeController>(
            c => c.SomeAction(model.SomeField, model.AnotherField, model.YetAnotherField, null, model.SomeOtherField)
            )) { %>
                <%= Html.DropDownList("status", Model.StatusSelectList)%>
                <input type="submit" value="Filter" class="button" />
                <% } %>
    
  • l'utilisation des méthodes d'extension pour créer des champs, si tu veux juste les champs à remplir avec les valeurs affichées lorsque vous u montrent des messages de validation ayant échoué sur le formulaire soumis
  • sur asp.net mvc 2 ils ont introduit un moyen de sauver une instance dans un champ caché ... codé + (je pense) signé
  • TempData si tout le ne fait pas au-dessus (passe par session - nettoyé à la demande suivante)
  • as u-dessus, lorsqu'on utilise l'état Ajax est déjà dans les champs préalablement chargés dans le site du client. Si u l8r sur le besoin de faire un article complet, mettez à jour tous les domaines u pourrait avoir besoin avec votre js.

Le ci-dessus sont toutes différentes options indépendantes pour y parvenir qui peuvent être utilisés dans différents scénarios. Il y a plus d'options que je n'ai pas parlé, à savoir les cookies session, des trucs de magasin dans db (comme pour un assistant de plusieurs étapes resumable), les paramètres passés à une action. Il n'y a pas 1 seul mécanisme pour les gouverner tous, et il ne devrait pas être.

La meilleure façon de le faire, je pense, est de sérialisation votre modèle d'origine à un champ caché, puis désérialiser et mettre à jour le modèle sur le poteau. Ceci est un peu similair à l'approche viewstate, que vous devez implémenter vous-même. J'utilise ceci:

Je dois d'abord des méthodes qui rendent les choses plus faciles:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Mvc;
using LuvDaSun.Extensions;
using System.Web.UI;

namespace LuvDaSun.Web.Mvc
{
    public static class HtmlHelperExtensions
    {
        static LosFormatter _losFormatter = new LosFormatter();
        public static string Serialize(this HtmlHelper helper, object objectInstance)
        {
            var sb = new StringBuilder();
            using (var writer = new System.IO.StringWriter(sb))
            {
                _losFormatter.Serialize(writer, objectInstance);
            }
            return sb.ToString();
        }


    }

    [AttributeUsage(AttributeTargets.Parameter)]
    public class DeserializeAttribute : CustomModelBinderAttribute
    {
        public override IModelBinder GetBinder()
        {
            return new DeserializeModelBinder();
        }
    }

    public class DeserializeModelBinder : IModelBinder
    {
        static LosFormatter _losFormatter = new LosFormatter();

        public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType.IsArray)
            {
                var type = bindingContext.ModelType.GetElementType();
                var serializedObjects = (string[])bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string[]));
                var deserializedObjects = Array.CreateInstance(bindingContext.ModelType.GetElementType(), serializedObjects.Length);

                for (var index = 0; index < serializedObjects.Length; index++)
                {
                    var serializedObject = serializedObjects[index];
                    var deserializedObject = _losFormatter.Deserialize(serializedObject);

                    deserializedObjects.SetValue(deserializedObject, index);
                }

                return deserializedObjects;
            }
            else
            {
                var serializedObject = (string)bindingContext.ValueProvider.GetValue(bindingContext.ModelName).ConvertTo(typeof(string));
                var deserializedObject = _losFormatter.Deserialize(serializedObject);

                return deserializedObject;
            }
        }
    }

}

puis dans mon contrôleur j'ai quelque chose comme ceci (mettre à jour un produit)

    public ActionResult Update(string productKey)
    {
        var model = _shopping.RetrieveProduct(productKey);

        return View(model);
    }
    [AcceptVerbs(HttpVerbs.Post)]
    public ActionResult Update([Deserialize]Shopping.IProduct _model, FormCollection collection)
    {
        UpdateModel(model);

        model.Save();

        return RedirectAfterPost();
    }

et je besoin d'un champ caché qui contient l'objet sérialisé sous la forme:

    <% 
        using (Html.BeginRouteForm("Product", FormMethod.Post, new { id = UniqueID, }))
        {
    %>
<%= Html.Hidden("Model", Html.Serialize(Model)) %>
    <h1>
        Product bewerken</h1>
    <p>
        <label for="<%=UniqueID %>_Name">
            Naam:</label>
        <input id="<%=UniqueID %>_Name" name="Name" type="text" value="<%= Html.AttributeEncode(Model.Name) %>"
            class="required" />
        <br />
    </p>
    <p>
        Omschrijving:<br />
        <textarea id="<%= UniqueID %>_Description" name="Description" cols="40" rows="8"><%= Html.Encode(Model.Description) %></textarea>
        <br />
    </p>
    <p>
        <label for="<%=UniqueID %>_Price">
            Prijs:</label>
        <input id="<%= UniqueID %>_Price" name="Price" type="text" value="<%= Model.Price.ToString("0.00") %>"
            class="required" />
        <br />
    </p>
    <ul class="Commands">
        <li><a href="" class="ClosePopup">Annuleren</a></li>
        <li>
            <input type="submit" value="Opslaan" /></li>
    </ul>
    <% 
        } 
    %>

    <script type="text/javascript">

        jQuery('#<%= UniqueID %>').validate();

    </script>

comme vous pouvez le voir, un champ caché (Model) est ajouté à la forme. Il contient les informations de sérialisation de l'objet d'origine. Lorsque le formulaire est affiché, le champ caché est également affiché (ofcourse) et le contenu sont désérialisée par le ModelBinder personnalisé à l'objet original qui est ensuite mis à jour et enregistré par le contrôleur.

Ne notez que l'objet que vous sérialisation a besoin d'être décoré de l'attribut Serializable ou doit avoir un TypeConverter qui peut convertir l'objet en une chaîne.

La LosFormatter (Limited objet sérialisation) est utilisé par le viewstate dans webforms. Il offre également encryptionn des données de sérialisation.

... accueille

appelle AJAX est ce que nous faisons. Si vous parlez des grilles en général, consultez jqGrid et comment ils recommandent la mise en œuvre AJAX.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top