Pergunta

Eu sou novo para MVC, mas eu estive em todo este, leia toda a documentação e todas as perguntas e todos os posts que pode encontrar, e tudo que eu estou fazendo está ficando completamente enrolada em torno do eixo.

Eu estou tentando fazer um "criar" Ação e View. Minha entrada de dados é relativamente simples e comum: Eu tenho uma lista suspensa e uma caixa de texto. No meu caso, eu estou criando um canal de contato do usuário, e no menu suspenso escolhe caixa entre e-mail e textmsg, ea caixa de texto, em seguida, insere as informações relevantes de contato, um endereço de e-mail bem formado, ou um número de telemóvel.

Aqui está uma (forma ligeiramente simplificada) minha página Ver:

 <tr>
     <td><%= Html.DropDownList("ChannelDescription", Model.ChannelDescription, "Select a Channel", new { id = "ChannelDDL", onchange="ChannelDDLChanged()" })%>
         <br />
         <%= Html.ValidationMessage("ChannelDescription", "Please Select a Channel") %>
      </td>
      <td>
           <%= Html.TextBox("SubscriberNotificationAddr") %> <br />
           <%= Html.ValidationMessage("SubscriberNotificationAddr", "Please enter a contact address or number") %>
       </td>
  </tr>

Eu estou usando um modelo ViewData fortemente tipado, ao invés de usar o ViewDataDictionary. O elemento ChannelDescription é um SelectList, que é inicializada com a lista de opções e nenhuma seleção.

O visor inicial da forma, a entrada de dados na forma, e a extracção dos dados a partir da forma pelo controlador vai fina.

O meu problema é se os dados contém um erro, como um endereço de e-mail mal-formados ou número de telefone celular, e eu tenho que voltar para a vista, eu não tenho sido bem sucedido em obter o drop down seleção da lista exibida novamente. O elemento ChannelDescription é recriado no controlador com a escolha do usuário como o item selecionado. Eu definir pontos de interrupção na linha do View, e verificou-se que o elemento selecionado da lista de itens tem o conjunto propriedade Selected de verdade, mas ainda exibe o padrão "Selecione um Channel".

Isto parece que seria uma situação muito comum, e não deve ser tão difícil. O que estou fazendo de errado?

FYI, isso é com MVC 1.0 (Release), Windows 7, e VS 2008, funcionando sob Firefox 3.5.2.

Foi útil?

Solução 2

Eu tive algumas discussões com Brad Wilson, da equipe MVC, e ele me explicou que eu estava mal-entendido como o método auxiliar DropDownList deve ser utilizado (um mal-entendido que eu acho que pode ser bastante comum, pelo que eu li já ).

Basicamente, SEJA dar-lhe a SelectList no parâmetro chamado do ViewModel, e deixá-lo construir a lista suspensa de que, com os itens apropriados selecionados, ou dá-lo a SelectList como um parâmetro separado e deixar o parâmetro nomeado da viewmodel ser apenas as cordas de valor para o item selecionado (s). Se você dá um parâmetro SelectList, em seguida, ele espera que o valor nomeado para ser uma string ou lista de strings, não um SelectList.

Então, agora o seu ViewModel acaba por ter dois elementos para um item conceitual na vista (na lista suspensa). Assim, você pode ter um modelo que tem

string SelectedValue {get; set;}
SelectList DropDownElements { get; set;}

Em seguida, você pode preencher previamente os DropDownElements com as escolhas, mas na ligação a sua visão do modelo, você só precisa lidar com o elemento SelectedValue. Parece que funciona muito bem para mim quando eu fazê-lo dessa forma.

Outras dicas

Depois de ver a resposta acima, eu queria vê-la, porque todos os exemplos que eu tinha visto tinha, de fato, usado ViewDataDictionary, em vez de um tipo forte ViewDataModel.

Então eu fiz algumas experiências. Eu construí uma visão muito simples que usou um ViewDataDictionary planície, e passou valores por chaves nomeadas. Ele persistiu o item selecionado apenas multa. Em seguida, corte I e colado que Vista (e controlador) para outro, mudando apenas o que era necessário mudar para um ViewData Modelo fortemente tipado. Lo e eis que também persistiu o item selecionado.

Então, o que mais foi diferente entre meu teste simples e minha aplicação? No meu teste, eu tinha usado simplesmente "Html.DropDownList (" name " "optionLabel")". No entanto, na minha aplicação, eu precisava para adicionar atributos HTML, e as únicas sobrecargas disponíveis que htmlAttributes incluídos também incluem o selecione Lista.

Acontece que a sobrecarga DropDownList com um seleto parâmetro lista é quebrou! Olhando para o código-fonte MVC baixado, quando DropDownList é chamado com apenas um nome ou um nome e um optionLabel, acaba por recuperar a lista de seleção de destino da ViewData, e depois invocar o método SelectInternal privada pela seguinte chamada:

    return SelectInternal(htmlHelper, optionLabel, name, selectList, true /* usedViewData */, false /* allowMultiple */, (IDictionary<string, object>)null /* htmlAttributes */);

No entanto, se ele é chamado com um parâmetro selectList, ele acaba com o seguinte:

   return SelectInternal(htmlHelper, optionLabel, name, selectList, false /* usedViewData */, false /* allowMultiple */, htmlAttributes);

A diferença é que no primeiro (que irá funcionar correctamente) o parâmetro "usedViewData" é verdade, enquanto no segundo, ela é falsa. Que é realmente bom, mas expõe um defeito interno na rotina SelectInternal.

Se usedViewData é falso, torna-se uma variável de objeto "defaultValue" do modelo ViewData. No entanto, defaultValue é usado como se fosse uma string ou uma matriz de strings, quando, na verdade o que é retornado do ViewData é um SelectList. (IEnumerable<SelectListItem>).

Se usedViewData é verdade, então defaultValue será nulo ou uma string.

Então, se defaultValue não é nulo, ele acaba de entrar em um bloco de código que contém o seguinte:

        foreach (SelectListItem item in selectList) {
            item.Selected = (item.Value != null) ? selectedValues.Contains(item.Value) : selectedValues.Contains(item.Text);
            newSelectList.Add(item);

selectList é o selectList original que foi passada, de modo que o item é um SelectListItem (string texto, corda valor e, bool selecionado). Mas selectedValues ??foi derivado do defaultValue, e torna-se uma lista de SelectLists, não uma lista de strings. Assim, para cada um dos itens, está definindo o sinalizador selecionados com base em se a lista selectedValues ??"Contém" o item.Value. Bem, uma lista de SelectLists nunca vai "conter" uma string, então o item.Selected nunca fica set. (Correcção: Na verdade, depois de mais de rastreamento com o depurador, descobri que selectedValues ??é derivado da defaultValue por um "ToString ()" chamada para que ele realmente é uma lista de strings, mas em vez de conter os valores que queremos,-lo. contém "System.Web.Mvc.SelectList." - o resultado da aplicação "ToString ()" para objeto complexo como um SelectList o resultado ainda é o mesmo - nós não estamos indo para encontrar o valor que está procurando em que lista.)

Em seguida, ele substitui o recém-construído "newSelectList" para o "selectList" original, e prossegue para construir o HTML a partir dele.

Como Cagdas (Peço desculpas para massacrar o seu nome, mas eu não sei como fazer esses personagens no meu teclado dos EUA) disse acima, eu acho que eu vou ter que construir o meu próprio método para uso no lugar do DropDownList HtmlHelper. Eu acho que uma vez que esta versão 1 e Release2 está em Beta 2, não podemos realmente esperar quaisquer correções de bugs, a menos que fazê-lo nós mesmos certo?

BTW, se você me seguiu até aqui, esse código é em src \ SystemWebMvc \ Mvc \ Html \ SelectExtensions.cs, em torno de linha de 116-136

Sim, eu também tinha tantos problemas recebendo DropDownList a respeitar o item selecionado Eu dei a ele.

Verifique minha responder nesta questão . Tanto quanto me lembro, essa era a única maneira que eu poderia fazê-lo funcionar. Ao passar a lista via ViewData.

FYI, eu parei de usar esse método HtmlHelper. Eu estou agora simplesmente produzir os <select> e <option> Tag-me com um laço e definindo a propriedade selected da tag option, verificando-lo eu mesmo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top