Question

J'utilise MVC 3 dans mon projet, et je vois un comportement très étrange.

Je suis en train de créer un champ caché pour une valeur particulière sur mon modèle, le problème est que, pour une raison quelconque l'ensemble de la valeur sur le terrain ne correspond pas à la valeur dans le modèle.

par exemple.

J'ai ce code, tout comme un test:

<%:Html.Hidden("Step2", Model.Step) %>
<%:Html.HiddenFor(m => m.Step) %>

Je pense que les deux champs cachés auraient la même valeur. Ce que je fais est, définissez la valeur à 1 la première fois que j'afficher la vue, puis après la présentation, j'augmenter la valeur du champ modèle par 1.

Alors, la première fois que je rends la page deux commandes ont la valeur 1, mais la deuxième fois les valeurs rendues sont les suivants:

<input id="Step2" name="Step2" type="hidden" value="2" />
<input id="Step" name="Step" type="hidden" value="1" />

Comme vous pouvez le voir, la première valeur est correcte, mais la deuxième valeur semble être la même que la première fois que j'afficher la vue.

Qu'est-ce que je manque? Sont les * Pour les aides Html mise en cache des valeurs d'une certaine façon? Si oui, comment puis-je désactiver cette mise en cache?.

Merci pour votre aide.

Était-ce utile?

La solution

C'est normal et il est comment le travail des aides HTML. Ils utilisent d'abord la valeur de la requête POST et après que la valeur dans le modèle. Cela signifie que même si vous modifiez la valeur du modèle dans votre action de contrôleur s'il y a la même variable dans la demande POST votre modification sera ignorée et la valeur POSTé sera utilisée.

Une solution possible est de supprimer cette valeur de l'état de modèle dans l'action du contrôleur qui tente de modifier la valeur:

// remove the Step variable from the model state 
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

Une autre possibilité est d'écrire une aide HTML personnalisée qui utilise toujours la valeur du modèle et ne pas tenir compte des valeurs POST.

Et encore une autre possibilité:

<input type="hidden" name="Step" value="<%: Model.Step %>" />

Autres conseils

Je rencontre le même problème lors de l'écriture d'un assistant qui montre différentes parties d'un plus grand modèle à chaque étape.
Données et / ou erreurs de « Étape 1 » deviendraient mélangés avec « Step 2 », etc., jusqu'à ce que je compris que ModelState était de « blâme ».

C'était ma solution simple:

if (oldPageIndex != newPageIndex)
{
    ModelState.Clear(); // <-- solution
}

return View(model[newPageIndex]);

Ce code ne fonctionnera pas

// remove the Step variable from the model state
// if you want the changes in the model to be
// taken into account
ModelState.Remove("Step");
model.Step = 2;

... parce que HiddenFor toujours (!) Lit de ModelState pas le modèle lui-même. Et si elle ne trouve pas la clé « Step » elle produira la valeur par défaut pour ce type de variable qui sera 0 dans ce cas

Voici la solution. Je l'ai écrit pour moi, mais ne me dérange pas partager parce que je vois beaucoup de gens sont aux prises avec cette aide de HiddenFor méchant.

public static class CustomExtensions
{
    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, object htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    public static MvcHtmlString HiddenFor2<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
    {
        ReplacePropertyState(htmlHelper, expression);
        return htmlHelper.HiddenFor(expression, htmlAttributes);
    }

    private static void ReplacePropertyState<TModel, TProperty>(HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression)
    {
        string text = ExpressionHelper.GetExpressionText(expression);
        string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(text);
        ModelStateDictionary modelState = htmlHelper.ViewContext.ViewData.ModelState;
        ModelMetadata metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        if (modelState.ContainsKey(fullName))
        {                
            ValueProviderResult currentValue = modelState[fullName].Value;
            modelState[fullName].Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), currentValue.Culture);
        }
        else
        {
            modelState[fullName] = new ModelState
            {
                Value = new ValueProviderResult(metadata.Model, Convert.ToString(metadata.Model), CultureInfo.CurrentUICulture)
            };
        }
    }
}

Ensuite, vous venez de l'utiliser comme d'habitude à partir de vous voir:

@Html.HiddenFor2(m => m.Id)

Il vaut la peine de mentionner cela fonctionne avec des collections aussi.

Je me bats aussi avec la même situation, je pense, où j'utilise le même état de modèle entre les appels, et quand je modifie une propriété de modèle sur backend. Cependant, il n'a pas d'importance pour moi, si j'utilise textboxfor ou hiddenfor.

Je viens de contourner la situation en utilisant des scripts de page pour stocker la valeur de modèle comme une variable js, parce que je dois le HiddenField à cet effet au début.

Je ne sais pas si cela aide, mais simplement considérer ..

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