2013-03-04 6 views
6

Sto creando dinamicamente un ListBox multi-selezione Winforms e aggiungendolo in un controllo del pannello di flusso. Associo un'origine dati da un oggetto che ho creato e verificato che il DataSource abbia effettivamente circa 14 elementi. Quando faccio un listBox.SetSelected(0, true) viene generato un errore System.ArgumentOutOfRangeException.La differenza tra la raccolta ListBox.DataSource rispetto a ListBox.Items?

Ho rilevato che il problema è che mentre il DataSource ha 14 elementi, la collection Item non ne ha nessuno (0) e quindi lancia l'eccezione. La mia domanda è perché questi due sono diversi l'uno dall'altro, e perché non dovrei semplicemente aggiungere un elemento foreach in datasource alla raccolta degli oggetti?

Il seguente è il codice che ho finora:

case InsertableItemParameter.ParameterType.ListBox: 
    //note: two-way bindings are not possible with multiple-select listboxes 
    Label lblListBox = new Label(); 
    lblListBox.Text = param.DisplayText; 
    ListBox listBox = new ListBox(); 
    listBox.DataSource = param.Values; 
    listBox.DisplayMember = "Value"; 
    listBox.SelectionMode = SelectionMode.MultiExtended; 
    listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100); 
    listBox.SetSelected(0, true); //will throw argument out of range exception here! 
    listBox.SetSelected(1, true); 
    flowPanel.Controls.Add(lblListBox); 
    flowPanel.Controls.Add(listBox); 
    flowPanel.SetFlowBreak(listBox, true); 
    break; 

Di seguito è una soluzione alternativa ho cercato e ho lavorato, ma ancora una volta perché dovrei usare DataSource contro insieme di elementi?

case InsertableItemParameter.ParameterType.ListBox: 
    //note: two-way bindings are not possible with multiple-select listboxes 
    Label lblListBox = new Label(); 
    lblListBox.Text = param.DisplayText; 
    ListBox listBox = new ListBox(); 
    //listBox.DataSource = param.Values; 
    listBox.DisplayMember = "Value"; 
    listBox.SelectionMode = SelectionMode.MultiExtended; 
    listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100); 
    listBox.BeginUpdate(); 
    foreach (String paramater in param.Values) 
    { 
     listBox.Items.Add(paramater); 
    } 
    listBox.EndUpdate(); 
    listBox.SetSelected(0, true); 
    listBox.SetSelected(1, true); 
    flowPanel.Controls.Add(lblListBox); 
    flowPanel.Controls.Add(listBox); 
    flowPanel.SetFlowBreak(listBox, true); 
    break; 

RISPOSTA: Grazie per tutte le risposte. Il problema qui è visibilità e rendering in forma di vincita. Sebbene la differenza tra le raccolte DataSource e Items non fosse realmente indirizzata a salvare poche persone, la vera fonte del mio problema è stata risolta chiamando il metodo SetSelected() dopo che il modulo è stato completato. Ciò causa molti problemi nella progettazione della mia applicazione che devo risolvere, ma questo era il problema. Vedi la risposta che ho contrassegnato come risposta.

+0

Da quello che ho capito del tuo post, il 'ListBox.DataSource' è _where_ i dati sta arrivando _from_ e il' ListBox.Item' è quali dati hai già. – Brian

+0

@Brian In realtà, DataSource è dove ho dati, e ListBox.Item è completamente vuoto. Quando ho tentato di aggiungere il mio DataSource alla mia raccolta di oggetti usando un semplice 'listBox.Items.Add (paramater);' Ho ricevuto un errore che indica che non posso aggiungere elementi alla raccolta Oggetti quando DataSource è impostato. – Magnum

+0

Potete per favore postare tutto il codice? – Brian

risposta

4

Il tuo problema risiede probabilmente altrove, perché questo codice funziona bene:

string[] ds = {"123","321"}; 
listBox1.DataSource = ds; 
listBox1.SetSelected(1, true); 
MessageBox.Show(listBox1.Items.Count.ToString()); //returns 2 

testato in un nuovo progetto di C# con un listBox1 inserire il modulo e il codice sopra riportato in .

EDIT: non mi rendevo conto che la creazione di un ListBox in runtime potrebbe fare la differenza, e soprattutto perché è importante quando per impostare gli elementi selezionati. Questo codice funziona:

string[] ds = { "123", "321" }; 
ListBox lst = new ListBox(); 
lst.DataSource = ds; 
lst.Size = new Size(100,100);    
this.Controls.Add(lst); 
//make sure to call SetSelected after adding the ListBox to the parent 
lst.SetSelected(1, true); 

Grazie a @Brad per indicarlo. Quindi, di nuovo sulla domanda iniziale, sostituire questo:

listBox.SetSelected(0, true); 
listBox.SetSelected(1, true); 
flowPanel.Controls.Add(lblListBox); 
flowPanel.Controls.Add(listBox); 

con questo:

flowPanel.Controls.Add(lblListBox); 
flowPanel.Controls.Add(listBox); 
listBox.SetSelected(0, true); 
listBox.SetSelected(1, true); 

e dovrebbe funzionare.

+2

La differenza tra questo codice e il suo è che hai messo la lista sul modulo in fase di progettazione, come OP l'ho messo lì in fase di runtime. – Brad

+1

Dal momento che avete putted il controllo sul controllo padre in fase di progettazione rende il vostro controllo visibile al momento della regolazione del DataSource quindi funziona, OP imposta il controllo padre dopo che lui tenta di accedere l'insieme di elementi. –

+0

Quindi è un problema di rendering. Il problema è che non posso impostare un oggetto un oggetto selezionato fino a dopo il completamento del sorteggio che è molto sfortunato. Ho bisogno di ottenere intorno a questo altrimenti avrei dovuto tenere traccia di tutti gli elementi listbox creati per legano in seguito a questi valori :( – Magnum

1

elementi dal MSDN

Questa proprietà consente di ottenere un riferimento alla lista di elementi che sono attualmente memorizzati nel ListBox. Con questo riferimento, è possibile aggiungere articoli, rimuovere elementi e ottenere un conteggio degli articoli nella raccolta. Per ulteriori informazioni sulle attività che è possibile eseguire con la raccolta di elementi, vedere gli argomenti di riferimento della classe ListBox.ObjectCollection.

Datasource Da MSDN

Un oggetto che implementa le interfacce IList o IListSource, come un DataSet o un array. Il valore predefinito è nullo

Non sono un esperto in materia, ma da quello che ho letto sembra che Articoli consente di aggiungere/modificare i contenuti nell'elenco mentre Datasource recupera e imposta il contenuto.

1

Hai due opzioni su come ottenere i dati per essere disponibili in un ListBox. È possibile impostare DataSource oppure è possibile aggiungere gli articoli manualmente tramite listBox.Items.Add(paramater). Non si può fare entrambe le cose, perché farà un passo sulla vicenda, quindi, il vostro errore

...cannot add items to the Item collection when DataSource is set. 
+0

Sì, l'ho scoperto. Ho aggiunto un po 'di codice aggiuntivo sotto la linea orizzontale che ho aggiunto per dimostrare la disabilitazione dell'oggetto .DataSource e utilizzando solo la raccolta di elementi. Tuttavia, se si guarda un'altra risposta scritta di seguito da Neolisk, si può vedere che l'impostazione di DataSource e l'utilizzo di SetSelected funziona per lui. Sto cercando di capire perché ora – Magnum

1

Non sono sicuro del motivo per cui esistono due raccolte diverse. La proprietà Items sembra più semplice.

ho trovato il motivo per l'eccezione: a quanto pare si hanno a che fare le cose in un ordine specifico, in questo modo:

//init the listbox 
    var listBox1 = new ListBox(); 
    listBox1.Location = new System.Drawing.Point(122, 61); 
    listBox1.Size = new System.Drawing.Size(205, 147); 
    listBox1.SelectionMode = SelectionMode.MultiExtended; 
    Controls.Add(listBox1); //<-- point of interest 

    //then set the DataSource 
    listBox1.DataSource = lst; 
    listBox1.DisplayMember = "Name"; 
    listBox1.ValueMember = "Age"; 

    //then set the selected values 
    listBox1.SetSelected(0, true); 
    listBox1.SetSelected(1, true); 

mio aspetto Test classe come questa:

public class Test 
{ 
    private static Random r = new Random(); 
    public Test (string name) 
    { 
     Name = name; 
     Age = r.Next(16, 45); 
    } 

    public string Name { get; set; } 

    public int Age{ get; set; } 
} 

E lst è dichiarato in questo modo:

var lst = new List<Test>() 
        { 
         new Test("jens"), 
         new Test("Tom"), 
         new Test("John"), 
         new Test("Don"), 
         new Test("Jenny"), 
        }; 
+0

Ho cercato il suo suggerimento per aggiungere la casella di riepilogo al controllo flowpanel prima di fare il setSelected. Sto cominciando a sospettare che sia un Problema di rendering di Winforms in cui le raccolte non vengono aggiornate fino a un certo punto dell'estrazione? Sto lavorando per verificare questo sospetto. – Magnum

+0

@Magnum Sono d'accordo. Forse con alcuni posizionati a destra 'BeginEdit'() e' EndEdit() ' –

+0

@Magnum ma hai provato a impostare 'DataSource' * dopo * l''listBox' è stato aggiunto a' flowPanel'? –

1

La raccolta Articoli viene popolata da DataSource solo quando il Controllo è visibile. poiché si crea il controllo dinamicamente, non viene aggiunto al controllo genitore e quindi non visibile. Pertanto è necessario prima avere un controllo visibile sullo schermo. Nel codice si imposta DataSource e quindi si imposta gli elementi selezionati prima che lo Control sia visibile su FlowChart poiché non viene aggiunto al controllo Parent. Dovresti cambiare la sequenza delle affermazioni. È necessario aggiungere lo listBox allo FlowPanel che popolerà la raccolta di articoli da DataSource su cui è possibile eseguire il metodo SetSelected(). Prova questo e notare l'ordine mutato l'esecuzione del codice iniziale:

ListBox listBox = new ListBox(); 
listBox.DataSource = param.Values; 
listBox.DisplayMember = "Value"; 
listBox.SelectionMode = SelectionMode.MultiExtended; 
listBox.Size = new System.Drawing.Size(flowPanel.Size.Width - lblListBox.Size.Width - 10, 100); 
flowPanel.Controls.Add(lblListBox); 
flowPanel.Controls.Add(listBox); //notice that you first add the listBox to the flowChart 
listBox.SetSelected(0, true); //and then you have items in the Items collection which you can select 
listBox.SetSelected(1, true); 
Problemi correlati