2010-08-25 6 views
5

Aggiornamento: ho controllato la risposta prima che il test completo continuasse a non funzionare. Ho aggiornato il codice di seguito, quindi dovresti essere in grado di incollare in un progetto WinForms vuoto e dovrebbe essere compilato.ComboBox non aggiornerà l'elenco di visualizzazione a meno che non si modificino prima le selezioni

AGGIORNAMENTO: Ho scoperto che se cambio l'elemento selezionato sul ComboBox su qualsiasi altro elemento, ora si comporta come previsto (nel mio codice qui sotto passerei da test1 a test2). Poiché non ho ancora ricevuto alcuna risposta, cambio la domanda a questo.

Perché devo passare a un elemento diverso nella casella combinata prima che mostri le modifiche apportate alla sorgente dati sottostante?

Ecco un breve test di verifica di ciò che sta accadendo.

  1. Change test1 a test1asdf testo in txtBroken
  2. click off per commettere il cambiamento
  3. testo nella casella combinata non aggiorna.
  4. Change casella combinata per test2
  5. cambiamento test2-test2asdf testo in txtBroken
  6. clicca off per commettere il cambiamento
  7. testo nella casella combinata mostra subito 'test2asdf' mostra ancora test1 per il primo oggetto nella discesa
  8. modifica test1
  9. casella combinata visualizza test1 casella di testo visualizza test1asdf
  10. aggiornamento del testo b bue per test1asd
  11. casella combinata visualizza immediatamente test1asd

Altro che dietro le quinte che cambiano la voce selezionata del carico e che cambiano di nuovo (questa sembra una tale hack) come posso risolvere questo problema?


Ho una casella combinata databound ad un BindingSource legato ad un List<Holder> ha Holder.Name come valore di visualizzazione. Ho anche una casella di testo legata a Holder.Name ma se cambio il testo nella casella di testo non cambierà ciò che viene visualizzato nella casella combinata. La modifica degli elementi selezionati e la modifica mostreranno il testo aggiornato nella casella di testo, ma conserveranno il vecchio valore visualizzato nella casella combinata. Come posso rendere l'articolo nella casella combinata aggiornare?

using System; 
using System.ComponentModel; 
using System.Windows.Forms; 

namespace Sandbox_Form 
{ 
    public class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      lstBroken = new BindingList<Holder>(); 
      lstBroken.Add(new Holder("test1")); 
      lstBroken.Add(new Holder("test2")); 
      bsBroken = new BindingSource(lstBroken, null); 
      cmbBroken.DataSource = bsBroken; 
      cmbBroken.DisplayMember = "Name"; 
      cmbBroken.SelectedIndex = 0; 
      txtBroken.DataBindings.Add("Text", bsBroken, "Name"); 
      txtBroken.TextChanged += new EventHandler(txtBroken_TextChanged); 

     } 

     [STAThread] 
     static void Main() 
     { 
      Application.EnableVisualStyles(); 
      Application.SetCompatibleTextRenderingDefault(false); 
      Application.Run(new Form1()); 
     } 

     void txtBroken_TextChanged(object sender, EventArgs e) 
     { 
      ((Control)sender).FindForm().Validate(); 
     } 
     private BindingSource bsBroken; 
     private BindingList<Holder> lstBroken; 
     private ComboBox cmbBroken; 
     private TextBox txtBroken; 
     private Label label1; 
     /// <summary> 
     /// Required designer variable. 
     /// </summary> 
     private System.ComponentModel.IContainer components = null; 

     /// <summary> 
     /// Clean up any resources being used. 
     /// </summary> 
     /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> 
     protected override void Dispose(bool disposing) 
     { 
      if (disposing && (components != null)) 
      { 
       components.Dispose(); 
      } 
      base.Dispose(disposing); 
     } 

     #region Windows Form Designer generated code 

     /// <summary> 
     /// Required method for Designer support - do not modify 
     /// the contents of this method with the code editor. 
     /// </summary> 
     private void InitializeComponent() 
     { 
      this.cmbBroken = new System.Windows.Forms.ComboBox(); 
      this.txtBroken = new System.Windows.Forms.TextBox(); 
      this.label1 = new System.Windows.Forms.Label(); 
      this.SuspendLayout(); 
      // 
      // cmbBroken 
      // 
      this.cmbBroken.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; 
      this.cmbBroken.FormattingEnabled = true; 
      this.cmbBroken.Location = new System.Drawing.Point(12, 32); 
      this.cmbBroken.Name = "cmbBroken"; 
      this.cmbBroken.Size = new System.Drawing.Size(94, 21); 
      this.cmbBroken.TabIndex = 0; 
      // 
      // txtBroken 
      // 
      this.txtBroken.Location = new System.Drawing.Point(13, 60); 
      this.txtBroken.Name = "txtBroken"; 
      this.txtBroken.Size = new System.Drawing.Size(93, 20); 
      this.txtBroken.TabIndex = 1; 
      // 
      // label1 
      // 
      this.label1.AutoSize = true; 
      this.label1.Location = new System.Drawing.Point(13, 13); 
      this.label1.Name = "label1"; 
      this.label1.Size = new System.Drawing.Size(41, 13); 
      this.label1.TabIndex = 2; 
      this.label1.Text = "Broken"; 
      // 
      // Form1 
      // 
      this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); 
      this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; 
      this.ClientSize = new System.Drawing.Size(284, 262); 
      this.Controls.Add(this.label1); 
      this.Controls.Add(this.txtBroken); 
      this.Controls.Add(this.cmbBroken); 
      this.Name = "Form1"; 
      this.Text = "Form1"; 
      this.ResumeLayout(false); 
      this.PerformLayout(); 

     } 

     #endregion 

     private void cmbWorks_SelectedIndexChanged(object sender, EventArgs e) 
     { 

     } 
    } 
    public class Holder 
    { 
     public Holder(string name) 
     { 
      Name = name; 
     } 
     private string _Name; 
     public string Name 
     { 
      get { return _Name; } 
      set 
      { 
       _Name = value; 
      } 
     } 
    } 
} 

Se mi legano ad un List<String> utilizzando invece Holder.Name funziona come previsto (questo è solo un semplice mock-up, la vera classe ha più di un nome così una lista di stringhe non funziona). Penso che questo sia un indizio di ciò che è sbagliato, ma non so cosa sia. Usare un Osservabile invece di un elenco non fa differenza.

+0

Impostare in realtà txtBackupName datacontext sull'elemento selezionato di cboJobSelector e quindi eseguire il bind alla proprietà Name, in quanto attualmente si associa solo alla proprietà text della casella combinata. Per quanto ne so, la casella combinata non aggiornerà la fonte originale se cambi la sua proprietà di testo corrente. –

+0

@LnDCobra Come faccio? –

+0

@Scott Non sono sicuro di come farlo esattamente nel codice, so come farlo xaml, ma posso chiederti perché stai usando l'associazione con winforms? e non solo usare WPF? –

risposta

18

Utilizzare un BindingList invece di un List. È stato progettato per affrontare tali problemi. Dinesh Chandnani, un membro del.NET squadra Cliente, dichiara quanto segue in un blog post:

BindingList<T> è la nuova implementazione generica di IBindingList che incendi ListChanged evento quando gli elementi vengono aggiunti /rimosso/inserita/etc. dalla lista . bindingSource si aggancia a questi eventi ed è quindi "a conoscenza" di queste modifiche e può notificare i controlli associati thos questa BindingSource.

Sono riuscito a riprodurre il problema descritto nella voce aggiornata, ma non ho riprodotto il problema originale senza modificare leggermente il codice.

Utilizzando un BindingList<Holder> sono riuscito a ottenere una risposta immediata quando il focus lasciato la casella di testo. È possibile ottenere aggiornamenti istantanei utilizzando un metodo sovraccarico quando si aggiunge una nuova associazione dati. Ho anche impostato direttamente poiché l'utilizzo di nulldataMember nel costruttore con overload non stava producendo il comportamento previsto.

Ecco il codice ho finito con base al largo il vostro codice di esempio:

public partial class Form1 : Form 
{ 
    private BindingSource bs; 
    private BindingList<Holder> bList; 

    public Form1() 
    { 
     InitializeComponent(); 

     bList = new BindingList<Holder>(); 
     bList.Add(new Holder("test1")); 
     bList.Add(new Holder("test2")); 

     bs = new BindingSource(); 
     bs.DataSource = bList; 

     cmb.DataSource = bs; 
     cmb.DisplayMember = "Name"; 
     cmb.ValueMember = "Name"; 

     // updates when focus leaves the textbox 
     txt.DataBindings.Add("Text", bs, "Name"); 

     // updates when the property changes 
     //txt.DataBindings.Add("Text", bs, "Name", false, DataSourceUpdateMode.OnPropertyChanged); 
    } 
} 

Commento fuori la prima txt vincolante e rimuovere quella qui sotto per vedere la DataSourceUpdateMode.OnPropertyChanged in azione.

Ecco alcuni BindingList risorse:

1) Sostituire bsBroken = new BindingSource(lstBroken, null); con:

bsBroken = new BindingSource(); 
bsBroken.DataSource = lstBroken; 

O in una sola riga: bsBroken = new BindingSource() { DataSource = lstBroken };

Ciò produce il comportamento atteso con una risposta immediata ai cambiamenti (ho anche detto questo prima). Do non utilizzare il sovraccarico che accetta un dataMember e impostarlo su null. In questo modo viene fornito il comportamento buggy che stai riscontrando.

2) Dopo aver fatto quanto sopra, non vedo la necessità per l'evento txtBroken_TextChanged. Commentare l'assegnazione del gestore eventi da testare, ma dovresti riuscire a rimuoverlo completamente.

+0

Ti ho dato il merito senza testarlo completamente. si comporta ancora allo stesso modo con la lista vincolante. Incollerò un campione di codice completamente funzionante nel mio soggetto. –

+0

@Scott Ho aggiornato il mio post (vedere il ** EDIT ** sopra) ed è stato in grado di risolvere il problema. Aggiorna l'assegnazione 'BindingSource.DataSource' e dovresti essere pronto. –

+0

Ho dato la risposta accettata a voi. Comunque terrò l'evento TextChanged perché in questo modo aggiornerà il testo nella casella combinata durante la digitazione invece di fare clic su off prima dell'aggiornamento e preferisco lo stile visivo in attesa che tu faccia clic. –