.NET WinForms ComboBox, itens idênticos, eo evento SelectedIndexChanged

votos
5

Parece que quando você tem um aplicativo WinForms NET, e uma caixa de combinação (definido para o estilo DropDown), e que ComboBox tem vários itens nele que são idênticos, coisas estranhas acontecem. Especificamente, o índice do item selecionado pode mudar sem disparar o evento SelectedIndexChanged.

Claro, isso causa confusão em massa e estranhas, erros obscuros, que é o que eu tenho de puxar meu cabelo para fora sobre recentemente.

Aqui está um exemplo simples que você pode usar para ver o que eu estou falando:

  • Faça um novo projeto WinForms (eu uso VB.NET, mas fique à vontade para traduzir - é bastante simples).
  • Deixar cair uma caixa de combinação, um botão e uma caixa de texto (definida MultiLine = True) para o formulário.
  • Use o seguinte código para carregar a caixa de combinação com 3 itens idênticos e imprimir algumas mensagens de status quando os fogos evento SelectedIndexChanged, e ver o que o índice selecionado é (através de um botão):
Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        TextBox1.Text = TextBox1.Text & vbNewLine & ComboBox SelectedIndexChanged event fired. & vbNewLine & _
            SelectedIndex is:  & ComboBox1.SelectedIndex
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        ComboBox1.Items.Add(John Doe)
        ComboBox1.Items.Add(John Doe)
        ComboBox1.Items.Add(John Doe)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        TextBox1.Text = TextBox1.Text & vbNewLine & _
        Button clicked. & vbNewLine & _
        SelectedIndex is:  & ComboBox1.SelectedIndex
    End Sub

Execute o projeto e selecione um item da ComboBox (digamos, o do meio). Em seguida, clique na seta drop-down da caixa de combinação, mas não selecione nada. Clique no botão (Button1 por padrão) e ver o que ele diz.

A menos que eu perdi minha mente, aqui está o que você deve ver:

evento ComboBox SelectedIndexChanged demitido.
SelectedIndex é: 1
Botão clicado.
SelectedIndex é: 0

Em outras palavras, o índice selecionado mudou, mas sem o acionamento do evento SelectedIndexChanged!

Isso só acontece quando os itens na caixa de combinação são idênticos. Se eles são diferentes, isso não acontece. (Ele também não acontece se o estilo DropDown da caixa de combinação é definido como DropDownList.)

Eu suspeito que isso pode ser um bug no próprio framework .NET e não algo que eu possa corrigir, mas na chance que alguém tem alguma idéia sobre o que fazer aqui (ou o que eu poderia estar fazendo errado!), Por favor, gritei ! Eu estou em uma perda para explicar este comportamento ou contornar isso (espero que o SelectedIndex para permanecer o mesmo, a menos que, você sabe, você realmente mudar-lo selecionando outra coisa!)

Publicado 09/12/2008 em 23:04
fonte usuário
Em outras línguas...                            


4 respostas

votos
17

O .NET Framework realmente não acompanhar o índice selecionado de queda da caixa de combinação lista para baixo; isso é tratado internamente pela API do Windows. Como consequência disto, .NET é dependente da API do Windows para notificá-lo quando o índice selecionado mudanças por meio de uma mensagem de notificação enviada para identificador de janela da caixa de combinação, para que ele possa, por sua vez aciona o evento SelectedIndexChanged.

Infelizmente, verifica-se que a mensagem de notificação especial, que .NET relógios para ( CBN_SELCHANGEpara ser exato) não cobre todos os cenários possíveis em que o índice selecionado pode mudar. Especificamente, CBN_SELCHANGEsó é enviado pela API do Windows se o usuário clica em, ou seleciona usando as teclas de seta, um item na lista suspensa. No entanto, em uma caixa de combinação estilo DropDown, o ato de abrir a caixa de combinação faz com que o Windows a olhar para o texto na parte de edição da caixa de combinação, procure a lista de itens para um jogo, e se for encontrada uma correspondência, automaticamente selecione o item correspondente (ou o primeiro item correspondente, se houver vários itens correspondentes). Isso pode alterar o índice selecionado, mas não envia uma CBN_SELCHANGEmensagem de notificação, de modo .NET perde o fato de que ele mudou e não dispara o evento SelectedIndexChanged.

Windows faz tudo isso em uma caixa de combinação estilo DropDown porque o usuário não tem que escolher algo na lista suspensa; eles podem escrever o que quiserem. Assim, cada vez que você abrir a caixa de combinação ele assume que o usuário pode ter alterado o texto e tenta re-sincronização com o que está na lista se ele pode.

No seu caso, quando você abre a caixa de combinação para o segundo tempo, é re-sincronização e selecionando a primeira partida para o texto na parte de edição, que é "John Doe" # 0, e alterando o índice selecionado para 0 sem .NET estar consciente.

Por isso, basicamente, é um bug no .NET Framework. Infelizmente, não há solução perfeita - você não pode obter o Windows para não fazer o re-sync, e não há nenhum evento que dispara logo após a re-sincronização ocorre no qual você pode obter o novo índice selecionado. (O evento DropDown realmente dispara direita antes de ocorrer o re-sync, por isso não irá ver o novo índice.) Sobre o melhor que você pode fazer é manipular o evento DropDownClosed, assuma que o índice poderia ter mudado nesse ponto, e agir em conformidade .

Respondeu 10/12/2008 em 04:29
fonte usuário

votos
2

A resposta de Eric foi muito profundo, mas fiquei surpreso ao ver que ele não terminou com "... mas realmente, você deve se perguntar por que você está preenchendo uma caixa de combinação com itens duplicados." O quadro bug .Net, sem dúvida, foi permitido a existir, porque quando você usar o controle como se pretendia, para permitir que o usuário escolha um item de uma lista, você não executar para esse bug.

Como é que o usuário vai para diferenciar entre as entradas idênticas? Por que eles iriam escolher um sobre o outro? Existe um significado diferente para os diferentes itens? Se assim for, então ter entradas duplicadas é ambígua, que é sempre mau design usabilidade. Se não, então você não deve ter itens duplicados.

O único cenário que eu posso pensar de onde isso pode fazer sentido é quando você tem uma lista grande que consiste de vários grupos de itens relacionados, onde um ou mais itens se encaixa logicamente em mais de um grupo assim que você quer exibi-lo em ambas as seções.

Eu estou supondo que seu projeto não conta para o fato de que pode haver múltiplas entradas idênticas e que essa omissão terá outras repercussões de usabilidade que são mais significativas do que este problema. Claro, eu entendo que você pode estar fazendo algo que eu não tenha pensado em que faz totalmente sentido fazer o que está fazendo, caso em que você pode se sentir livre para ignorar meus comentários.

Respondeu 30/03/2009 em 07:54
fonte usuário

votos
1

Há casos em que ter itens duplicados na lista é não só válida, mas desejável. Considere a caixa de combinação OpenFileDialog que você vê no Visual Studio quando você pressiona o botão Abrir Arquivo. Isso mostra uma caixa de combinação com itens como 'Meu Computador', 'desktop', 'Meus Documentos', etc. Para nomes de pasta, apenas o nome curto está na lista. O caminho completo não é exibido. E por isso é muito possível que a pasta tem o mesmo nome (curto) como um de seus descendentes.

Então, imagine a seguinte estrutura de pasta:

C:\
C:\A
C:\A\B
C:\A\B\A

Uma estrutura perfeitamente válida. Na minha aplicação eu definir a propriedade DataSource para um BindingList de objetos. O ValueMember do objeto é o nome completo do arquivo, eo DisplayMember é o nome de arquivo curto. A caixa de combinação deve exibir:

C:\
    A
        B
            A

design perfeitamente boa UI. O recuo sugere a nidificação das pastas.

Mas quando eu definir SelectedValue da caixa de combinação para "C: \ A \ B \ A" o item errado é selecionado. O item que deve ser escolhido é o último (4º item) na lista, mas em vez disso o 2º item (índice 1) é selecionado. E definindo SelectedIndex = 3 não se comportar conforme o esperado. Mais uma vez, o segundo item é selecionado, não o último.

O que parece estar acontecendo aqui é que ao definir SelectedValue ou SelectedIndex, o valor está sendo convertido utilizando a propriedade DisplayMember, eo controle está à procura do começo ao fim para um jogo. Deve-se pesquisar usando a propriedade ValueMember. Exemplo de código é abaixo. Apreciado se alguém pode confirmar isso é um bug, ou algo que eu tenho feito de errado.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace ComboBoxTest
{
   public partial class Form1 : Form
   {
      public Form1()
      {
         InitializeComponent();
      }

      private void Form1_Load(object sender, EventArgs e)
      {
         if (DesignMode)
            return;

         BindingList<CBItem> items = new BindingList<CBItem>();
         items.Add(new CBItem("A", @"C:\A"));
         items.Add(new CBItem("B", @"C:\A\B"));
         items.Add(new CBItem("A", @"C:\A\B\A"));

         comboBox.DisplayMember = "DisplayValue";
         comboBox.ValueMember = "RealValue";
         comboBox.DataSource = items;

         comboBox.SelectedValue = @"C:\A\B\A";
      }
   }

   class CBItem
   {
      public CBItem(string displayValue, string realValue)
      {
         _displayValue = displayValue;
         _realValue = realValue;
      }

      private readonly string _displayValue, _realValue;

      public string DisplayValue { get { return _displayValue; } }
      public string RealValue { get { return _realValue; } }
   }
}
Respondeu 28/05/2009 em 21:38
fonte usuário

votos
0

Um problema semelhante ocorre sem itens idênticos se você digitar um texto livre, o que não corresponde exatamente, mas os primeiros caracteres. Se o utilizador não abrir o suspensa não re-sincronização e acontecer o índice é seleccionado -1 como esperado. (Não selecionando um dos itens é o que o usuário pretende fazer) Agora o usuário fecha a janela e abri-lo novamente. Você, como o programador, restaurar o combobox com o texto que o usuário entrou eo texto é automaticamente preenchido para a correspondência parcial item sem disparar o evento. Se o usuário fecha a janela do texto mudou sem aviso prévio. Este problema não ocorre se o texto não corresponde a nenhum item.

Respondeu 28/06/2009 em 11:15
fonte usuário

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more