Domanda

Sto usando MVC 3 nel mio progetto, e sto vedendo un comportamento molto strano.

Sto cercando di creare un campo nascosto per un particolare valore sul mio modello, il problema è che per qualche motivo il valore impostato sul campo non corrisponde al valore del Modello.

per es.

Ho questo codice, proprio come un test:

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

Vorrei pensare che entrambi i campi nascosti avrebbero lo stesso valore. Quello che faccio è, impostare il valore a 1 la prima volta che visualizzare la vista, e poi, dopo la presentazione ho aumentare il valore del campo Modello di 1.

Quindi, la prima volta che il rendering della pagina entrambi i controlli hanno il valore 1, ma la seconda volta i valori resi sono queste:

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

Come si può vedere, il primo valore è corretto, ma il secondo valore sembra essere la stessa della prima volta che ho visualizzare la vista.

Che cosa mi manca? Sono l'* Per aiutanti HTML caching dei valori in qualche modo? Se sì, come posso disattivare questa la cache?.

Grazie per il vostro aiuto.

È stato utile?

Soluzione

Questo è normale ed è come il lavoro aiutanti HTML. In primo luogo hanno utilizzano il valore della richiesta POST e dopo che il valore nel modello. Questo significa che anche se si modifica il valore del modello nella vostra azione di controllo se non v'è la stessa variabile nel Inserisci richiesta la vostra modifica verrà ignorata e verrà utilizzato il valore di iscrizione.

Una possibile soluzione è rimuovere questo valore dallo stato modello nell'azione controllore che cerca di modificare il valore:

// 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;

Un'altra possibilità è quella di scrivere un personalizzato HTML helper che sarà sempre utilizzare il valore del modello e ignorare i valori POST.

E ancora un'altra possibilità:

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

Altri suggerimenti

ho incontrato lo stesso problema quando si scrive una procedura guidata che mostra diverse parti di un modello più grande ad ogni passo.
Dati e / o errori da "Fase 1" diventerebbe confusa con "Step 2", ecc, fino a quando ho finalmente capito che ModelState è stato quello di 'colpa'.

Questa è stata la mia soluzione semplice:

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

return View(model[newPageIndex]);

Questo codice non funziona

// 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;

... perché HiddenFor sempre (!) Legge non dal ModelState il modello stesso. E se non trova il tasto "Step" produrrà il default per quel tipo di variabile che sarà 0 in questo caso

Ecco la soluzione. L'ho scritto per me, ma non mi dispiace la condivisione causa Vedo molte persone stanno lottando con questo helper HiddenFor cattivo.

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)
            };
        }
    }
}

Poi basta usarlo come al solito dall'interno di visualizzare:

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

Si distingue in funziona con le collezioni troppo.

Sono troppo alle prese con la stessa situazione credo, dove io uso lo stesso modello di stato tra le chiamate, e quando ho modificare una proprietà modello sul back-end. Anche se, non importa per me, se io uso textboxfor o hiddenfor.

Ho appena bypass la situazione utilizzando gli script di pagina per memorizzare il valore del modello come variabile js, perché ho bisogno del HiddenField a tal fine in principio.

Non sono sicuro se questo aiuta, ma basti pensare ..

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top