PROBLEMAS COM COMBOBOX
ao usar Combo não recomento usar a propriedade Text para passar dados, pois na realidade você está associando um ID + Texto do banco ao controle, sendo que ele usa internamente um Index do combo para localização dos dados carregados. Quando trabalho com combo só uso o ID do dado e mando ele exibir o texto. para facilitar tudo criei um método público para localizar um item dentro de qualquer combo, passando o próprio combo e ID para localizar é uma mão na roda, fica assim:
Minha classe pública fica numa DLL incorporada ao projeto principal assim:
public static void CarregaCombo(ComboBox myCbo, string mySituacao, int myID) //-> myID é necessário apenas para informar uma Empresa EspecÃfica)
{
switch (myCbo.Name)
{
case [Ô]cboInformatica[Ô]:
InformaticaBLL objInformatica = new InformaticaBLL();
myCbo.DisplayMember = [Ô]Software[Ô];
myCbo.ValueMember = [Ô]IDSoftware[Ô];
myCbo.DataSource = objInformatica.CarregaCombo(myID, mySituacao);
myCbo.SelectedIndex = -1;
myCbo.Refresh();
break;
case [Ô]cboCargos[Ô]:
CargoBLL objCargo = new CargoBLL();
myCbo.DisplayMember = [Ô]NOME[Ô];
myCbo.ValueMember = [Ô]IDCargo[Ô];
myCbo.DataSource = objCargo.CarregaCombo(myID, mySituacao);
myCbo.SelectedIndex = -1;
myCbo.Refresh();
break;
// etc.....
}
}
public static void LocalizaItemCombo(ComboBox myCbo, int myID)
{
//-> aqui percorro o List do DataSource associado ao combo, para identificar o item com mesmo ID e setar o combo nele
switch (myCbo.Name)
{
case [Ô]cboInformatica[Ô]:
foreach (InformaticaModelo info in myCbo.Items)
{
if (info.IDSoftware == myID)
{
myCbo.SelectedItem = info; //achou item então seleciona ele
return;
}
else
{
myCbo.SelectedIndex = -1; // não achou então não seleciona nenhum index = -1
}
}
break;
// etc....
}
}
Load do form carrega os combos
ClasseAcoesForms.CarregaCombo(cboInformatica, [Ô]Ativos[Ô], VariaveisAmbiente.ParametroNaoUsado.Zero);
Ao clicar num grid uso o seguinte código
ClasseAcoesForms.LocalizaItemCombo(cboInformatica, Convert.ToInt32(gridInformatica.CurrentRow.Cells[[Ô]IDSoftware[Ô]].Value.ToString()));
Pronto assim fica tudo automatizado, reaproveita código, reduz trabalho e o item é localizado pelo ID, pois se houver alteração no texto de um registro (edição) e tentar localizar por ele não o encontrará. Pelo ID isso nunca acontece.
essa aqui
ClasseAcoesForms.CarregaCombo(cboInformatica, [Ô]Ativos[Ô], [txt-color=#e80000]VariaveisAmbiente.ParametroNaoUsado.Zero[/txt-color]);
foreach ([txt-color=#e80000]InformaticaModelo[/txt-color] info in myCbo.Items)
{
if (info.[txt-color=#e80000]IDSoftware[/txt-color] == myID)
{
myCbo.SelectedItem = info; //achou item então seleciona ele
return;
}
else
{
myCbo.SelectedIndex = -1; // não achou então não seleciona nenhum index = -1
}
}
as partes de vermelho foi as que fiquei mais em duvida, sou novo em matéria de programação
Public Sub LocalizaItemCombo(ByVal myCBO As ComboBox, ByVal myID As Integer)
Select Case myCBO.Name
Case [Ô]ComboBox1[Ô] [ô]seu nome do combo
For Each info As DataRowView In myCBO.Items
If info.Item([Ô]cep[Ô]) = myID Then [ô]item tem q ser o id ou campo atrelado ao valuemember
myCBO.SelectedItem = info
End If
Next
End Select
End Sub
uma rotina simples de preencher combo q vc pode adaptar incluindo o combo a ser preenchido e passando a consulta
Dim con = New OleDbConnection([Ô]Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\cep2014.MDB[Ô])
con.Open()
Dim sql As String = [Ô]select log_nome,cep,ufe_sg FROM log_logradouro where ufe_sg=[ô]AC[ô][Ô]
Dim CD As New OleDbCommand()
CD.Connection = con
CD.CommandText = sql
CD.ExecuteNonQuery()
With dtAdapter
.SelectCommand = CD
.Fill(dsDataSet)
End With
ComboBox1.DisplayMember = [Ô]log_nome[Ô]
ComboBox1.ValueMember = [Ô]cep[Ô]
ComboBox1.DataSource = dsDataSet.Tables(0)
ComboBox1.SelectedIndex = -1
em vez da query estar ali dentro vc envia como parâmetro, assim como o combo de destino e dados do connection....(pode ter certeza qnd o projeto crescer vai te ajudar muito essas mudanças.....aqui criei 2 telinhas so pra teste, imagina vc ter 200 telas e ir uma a uma alterando todas as chamadas ao banco de dados.....qnt mais rotinas vc criar desassociada a uma tela, mais genéricas elas forem melhor sera seu projeto....passando todos os parâmetros possÃveis, vc cria uma rotina q usa em todas as telas do seu projeto, reduz linhas e esforço no momento de alterações....
achei muito show, e pratica dessa forma, vou estar usando assim agora nos projetos...
Imports System.Data.OleDb
Public Class Class1
Public Function Conecta() As OleDbConnection
Dim con = New OleDbConnection([Ô]Provider=Microsoft.Jet.OLEDB.4.0;Data Source=c:\cep2014.MDB[Ô])
con.Open()
Return con
End Function
Public Sub LocalizaItemCombo(ByVal myCBO As ComboBox, ByVal myID As Integer, ByVal item As String)
Select Case myCBO.Name
Case [Ô]ComboBox1[Ô]
For Each info As DataRowView In myCBO.Items
If info.Item(item) = myID Then
myCBO.SelectedItem = info
End If
Next
End Select
End Sub
Public Sub PreencheCombo(ByVal myCBO As ComboBox, ByVal Query As String, ByVal VM As String, ByVal DM As String)
Dim con As OleDbConnection = Conecta()
Dim sql As String = Query
Dim CD As New OleDbCommand()
Dim dtAdapter As New OleDbDataAdapter
Dim dsDataSet As New DataSet
CD.Connection = con
CD.CommandText = sql
CD.ExecuteNonQuery()
With dtAdapter
.SelectCommand = CD
.Fill(dsDataSet)
End With
myCBO.DisplayMember = DM
myCBO.ValueMember = VM
myCBO.DataSource = dsDataSet.Tables(0)
myCBO.SelectedIndex = -1
myCBO.Refresh()
End Sub
End Class
pense no seu form onde esta o grid
Private Sub DataGridView1_CellDoubleClick(sender As Object, e As System.Windows.Forms.DataGridViewCellEventArgs) Handles DataGridView1.CellDoubleClick
Dim tela As New Form2
tela.Show()
Dim busca As New Class1
busca.LocalizaItemCombo(tela.ComboBox1, CInt(DataGridView1.CurrentRow.Cells([Ô]cep[Ô]).Value.ToString), [Ô]CEP[Ô]) [ô]vc ta enviando dados do combo q sofre acao, no caso o valor a buscar, e o nome do campo desse valor
End Sub
e o form onde o combo esta
Public Class Form2
Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim enche As New Class1
enche.PreencheCombo(Me.ComboBox1, [Ô]select log_nome,cep,ufe_sg FROM log_logradouro where ufe_sg=[ô]AC[ô][Ô], [Ô]CEP[Ô], [Ô]log_nome[Ô])[ô]vc passa tudo q precisa pro combo ser preenchido corretamente, o combo, a query, o valuemember e o displaymember, viu como tornou completamente livre pra ser usado em qq tela e combo do projeto
End Sub
End Class
Citação::
Só não entendi a parte onde localiza o item para aparecer no combobox.
essa aqui
ClasseAcoesForms.CarregaCombo(cboInformatica, [Ô]Ativos[Ô], [txt-color=#e80000]VariaveisAmbiente.ParametroNaoUsado.Zero[/txt-color]);
foreach ([txt-color=#e80000]InformaticaModelo[/txt-color] info in myCbo.Items)
{
if (info.[txt-color=#e80000]IDSoftware[/txt-color] == myID)
{
myCbo.SelectedItem = info; //achou item então seleciona ele
return;
}
else
{
myCbo.SelectedIndex = -1; // não achou então não seleciona nenhum index = -1
}
}
as partes de vermelho foi as que fiquei mais em duvida, sou novo em matéria de programação
Felipe é o seguinte, meu projeto é em 4 camadas (UI, negócios BLL, Dados DAL e Entidade Modelo.
O método
ClasseAcoesForms.CarregaCombo(cboInformatica, [Ô]Ativos[Ô], VariaveisAmbiente.ParametroNaoUsado.Zero);
que está na DLL, usa os parâmetros:
cboInformatica = nome do objeto combo a ser carregado
[Ô]Ativos[Ô] = string para carregar só os ativos, no meu caso pode ser ainda [Ô]Inativos[Ô] ou [Ô]Todos[Ô] (ambos). Isso porque nenhum registro em meu sistema é excluÃdo, apenas inativas se não for mais utilizado, por rastreabilidade.
VariaveisAmbiente.ParametroNaoUsado.Zero = é uma structure para documentação dos valores, este parâmetro é o ID da empresa, quando os dados forem agrupados por unidades de negócio, filiais por exemplo. Se não for usa 0. Sendo assim usei essa variável da Structure para documentação apenas e não um simples 0.
Nota: esses parâmetros são por necessidade do meu projeto e não precisam existir, só o nome do combo mesmo.
Já o objeto InformaticaModelo é uma entidade usada para receber os dados, uma classe modelo com todos os campos necessários dessa camada Entidade, que corresponde a estrutura do banco, entendeu?
Na minha opinião o local mais indicado para carregar estas listas de opções (ComboBox, ListBox, etc) é no construtor do Form e não no Evento Load.
Usem um List<T> como datasource e basta setar o item na propriedade SelectedItem e pronto.
Um exemplo (em C#, é só adaptar para VB)
public class Opcao
{
public Opcao(int id, string texto)
{
this.ID = id;
this.Texto = texto;
}
public int ID { get; private set; }
public string Text { get; private set; }
public override bool Equals(object obj)
{
if ((obj == null) || !(obj is Opcao))
return false;
else
return this.ID == ((Opcao)obj).ID;
}
public override int GetHashCode()
{
return this.ID;
}
}
Cria as opções numa lista genérica
List<MyClass> listaOpcoes = new List<MyClass>();
listaOpcoes.Add(new MyClass(1, [Ô]opção 1[Ô]));
listaOpcoes.Add(new MyClass(2, [Ô]opção 2[Ô]));
listaOpcoes.Add(new MyClass(3, [Ô]opção 3[Ô]));
Altere o construtor do form
public SeuForm(List<Opcao> opcoes)
{
InitializeComponent();
// aqui você preenche a lista
comboBox1.Items.AddRange(opcoes.ToArray());
}
public void SelecionaOpecao(Opcao minhaOpcao)
{
comboBox1.SelectedItem = minhaOpcao;
}
Para chamar o Form e selecionar uma opção
var wnd = new SeuForm(listaOpcoes);
wnd.SelecionaOpcao(listaOpcoes[0]); // lembre-se que o Ãndice começa em zero
wnd.Show(); // Pode-se usar também ShowDialog();
Caso você queira deixar a lista sem seleção basta passar um null no parâmetro
wnd.SelecionaOpcao(null);
Pronto acho que é isso.
Public Sub LocalizaItemCombo(ByVal myCBO As ComboBox, ByVal myID As Integer)
Select Case myCBO.Name
Case [Ô]ComboBox1[Ô] [ô]seu nome do combo
For Each info As DataRowView In myCBO.Items
If info.Item([Ô]cep[Ô]) = myID Then [ô]item tem q ser o id ou campo atrelado ao valuemember
myCBO.SelectedItem = info
End If
Next
End Select
End Sub
se o problema estava so em entender algumas coisas, creio ter ficado muito simples e totalmente funcional....
o erro é não pode converter string para inteiro.
daà mudei e não passou nada para o form de cadastro, não sei oque fazer mais
apenas queria que passasse o texto da coluna do datagridview para o combobox do form cadastro
ficou assim
Public Sub LocalizaItemCombo(ByVal myCBO As ComboBox, ByVal myID As Integer, ByVal item As String)
Select Case myCBO.Name
Case [Ô]cmbModelo[Ô]
For Each info As DataRowView In myCBO.Items
If info.Item([Ô]nome[Ô]) = myID Then [ô]item tem q ser o id ou campo atrelado ao valuemember
myCBO.SelectedItem = info
End If
Next
Case [Ô]cmbLocalidade[Ô]
For Each info As DataRowView In myCBO.Items
If info.Item([Ô]nome[Ô]) = myID Then [ô]item tem q ser o id ou campo atrelado ao valuemember
myCBO.SelectedItem = info
End If
Next
End Select
End Sub
no form de consulta ficou assim
Dim cls As New Cls_Combo
cls.LocalizaItemCombo(Frm_Cad_Equip.cmbModelo, CInt(dgvPesquisa.CurrentRow.Cells([Ô]nome[Ô]).Value.ToString), [Ô]nome[Ô])
mais dá erro, ha algo de errado? desculpem ser chato, mais é porque estou aprendendo.
acontecendo este erro.
Adiciona seu projeto.
Vc tem q usar o campo do id o campo numerico, se vc preenche seu combo c display nome e valuemember id, o info tem q apontar ao id, veja o comentario q deixei, campo atrelado ao valuemember do combo
O display do combo é o q aparece para nos, o value em geral seria um identificador unico no banco de dados, um valor invisivel ao usuario, pra clarear, pense numa tabela de produtos, nada impede q vc tenha mais de um produto c o mesmo nome (display), porem o campo identificador (value) sera diferente pra todos, m campo q nunca se repete, entra na questao do banco de dados trabalhar c chaves primarias identidade essas coisas....
Se ficou confuso posta o codigo q preenche o combo, e se realmente o erro esta na linha q comentei q o pessoal da uma força
veja na parte q preenche o combo q postei
ComboBox1.DisplayMember = [Ô]log_nome[Ô]
ComboBox1.ValueMember = [Ô]cep[Ô]
ComboBox1.DataSource = dsDataSet.Tables(0)
ComboBox1.SelectedIndex = -1
minha tabela é de ceps e endereços, então sabemos q cep seria um campo único q não repete, por isso na hora da pesquisa uso o cep, o cep é o valor passado do outro form onde tem o grid, por isso meu item.info([Ô]cep[Ô])= a variável q veio do outro form
experimente usar break points pra entender, pra ver o q esta sendo lido nas variáveis, ajuda muito, as vezes até colocar messagebox com a variável pra vc ver o q esta sendo realmente trabalhado...
reparando vi mais coisas
cls.LocalizaItemCombo(Frm_Cad_Equip.cmbModelo, CInt(dgvPesquisa.CurrentRow.Cells([Ô]nome[Ô]).Value.ToString), [Ô]nome[Ô])
veja o q esta acontecendo, vc esta pegando a linha atual, tentando converter o conteúdo da linha x coluna(nome), essa coluna por acaso tem um texto(string)? não tem como vc fazer a conversão de texto para inteiro, q é o q o comando cint tenta, aponte para coluna do código único do produto, e aponte novamente para esse campo na rotina de pesquisa no combo....
eu vi vc enviar o nome como ultimo parâmetro pra função, mas da forma q usou a função Item.info([Ô]nome[Ô]) vc já apontou o item dentro de parentes, então não existe a necessidade do mesmo nem na função, nem na hora de chama-la, vc passou o parâmetro, mas ele não foi usado.....