Das ComboBox-SelectionChanged-Ereignis hat einen alten Wert, keinen neuen Wert

89

C #, .NET 4.0, VS2010.

Neu bei WPF. Ich habe eine ComboBox in meinem MainWindow. Ich habe das SelectionChanged-Ereignis dieses Kombinationsfelds verknüpft. Wenn ich jedoch den Wert des Kombinationsfelds im Ereignishandler untersuche, hat es den alten Wert. Dies klingt eher nach einem "SelectionChanging" -Ereignis als nach einem SelectionChanged-Ereignis.

Wie erhalte ich den neuen Wert der ComboBox, nachdem die Auswahl tatsächlich erfolgt ist?

Zur Zeit:

this.MyComboBox.SelectionChanged += new SelectionChangedEventHandler(OnMyComboBoxChanged);

...
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string text = this.MyComboBox.Text;
}

Beachten Sie, dass ich das gleiche Verhalten erhalte, wenn ich das Objekt verwende, das in den Ereignisargumenten egeOriginalSource übergeben wird.

Matt
quelle
2
Ich bin gerade über das gleiche Problem gestolpert - danke! Ist das eigentlich ein Fehler, und er hätte eigentlich benannt werden sollen SelectionChanging?
Jan

Antworten:

109

Laut MSDN e.AddedItems:

Ruft eine Liste ab, die die ausgewählten Elemente enthält.

Sie könnten also verwenden:

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string text = (e.AddedItems[0] as ComboBoxItem).Content as string;
}

Sie können auch verwenden , SelectedItemwenn Sie verwenden stringWerte für die Itemsvon der sender:

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string text = (sender as ComboBox).SelectedItem as string;
}

oder

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
}

Da beide Contentund SelectedItemsind Objekte, wäre ein sicherer Ansatz zu verwenden , .ToString()stattas string

SwDevMan81
quelle
11
interessant ... es hat den neuen Wert. Und RemovedItems hat das alte. Dieser Ereignisname ist ein bisschen falsch, zumindest meiner Meinung nach. Wenn ich SelectionChanged sehe, erwarte ich, dass sich der Status des Objekts geändert hat. Ich kann sehen, wie dies uns etwas mehr Informationen gibt.
Matt
1
Ja, ich denke, es liegt daran, dass die Änderung stattgefunden hat, aber nicht begangen wurde? Das ist nur eine Vermutung. Möglicherweise können Sie den Text des ausgewählten Elements abrufen, siehe meine Bearbeitung.
SwDevMan81
3
ComboBox.SelectedItemhat keine Eigenschaft namens Text, aber Sie können tun ComboBox.SelectedItem as string(obwohl dies möglicherweise nur funktioniert, wenn Sie stringfür die Items- nichts anderes getestet)
musefan
Nur Zeichenfolge text = (Zeichenfolge) e.AddedItems [0];
Igor Semin
Komplizieren Sie die Dinge nicht ohne Grund. Mit der SelectedValue-Eigenschaft können Sie auf einfache Weise einen ausgewählten ComboBox-Wert wie folgt abrufen: YourComboBoxName.SelectedValue.ToString (). Hinter den Kulissen ist die SelectedValue-Eigenschaft wie folgt definiert: SelectedValue {get; set;} Dies bedeutet, dass Sie damit den Wert einer ComboBox abrufen oder festlegen können. Die Verwendung von SelectedItem ist kein effizienter Weg, um einen ComboBox-Wert zu erhalten, da viele Konsequenzen erforderlich sind.
Sam Tomashi
59

Der richtige Wert, der hier überprüft werden muss, ist die SelectedItem- Eigenschaft.

Eine ComboBox ist ein zusammengesetztes Steuerelement, dessen zwei Teile sind:

  1. Der Textteil : Der Wert in diesem Teil entspricht der Text- Eigenschaft der ComboBox.
  2. Der Auswahlteil (dh der "Dropdown" -Teil): Das ausgewählte Element in diesem Teil entspricht der SelectedItem- Eigenschaft.

Erweiterte ComboBox-Teile

Das obige Bild wurde unmittelbar nach dem Erweitern der ComboBox (dh vor der Auswahl eines neuen Werts) aufgenommen. Zu diesem Zeitpunkt sind sowohl Text als auch SelectedItem "Info", vorausgesetzt, die ComboBox-Elemente waren Zeichenfolgen. Wenn die ComboBox-Elemente stattdessen alle Werte einer Aufzählung mit dem Namen "LogLevel" wären , wäre SelectedItem derzeit LogLevel.Info .

Wenn Sie auf ein Element in der Dropdown-Liste klicken, wird der Wert von SelectedItem geändert und das SelectionChanged- Ereignis ausgelöst. Der Text Eigenschaft ist noch nicht aktualisiert, obwohl, wie der Text Teil aktualisiert wird erst nach dem Selectionhandler beendet ist. Dies kann beobachtet werden, indem ein Haltepunkt in den Handler gesetzt und die Steuerung betrachtet wird:

ComboBox am Haltepunkt im SelectionChanged-Handler

Da der Text Teil nicht an dieser Stelle aktualisiert hat, der Text gibt Eigenschaft den zuvor ausgewählten Wert.

Dave Kidder
quelle
2
Vollständige Erweiterung und es half zu erkennen, dass sich meine Bindung in der Text-Eigenschaft anstelle des korrekten SelectedItem befand.
cmousset
1
@ DaveKidder Tolles Beispiel! +1
Ryan Wilson
46

Verwenden Sie das DropDownClosed-Ereignis anstelle von selectionChanged, wenn Sie den aktuellen Wert des Kombinationsfelds anzeigen möchten.

private void comboBox_DropDownClosed(object sender, EventArgs e)
{
   MessageBox.Show(comboBox.Text) 
}

Ist wirklich so einfach.

versteckt
quelle
10
@jvelez Ich denke, es wird nicht ausgelöst, wenn eine Tastatur verwendet wird.
NoviceProgrammer
das ist Scheiße. NoviceProgrammer, der wusste ...!
versteckt
10

Das hat bei mir funktioniert:

private void AppName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
   ComboBoxItem cbi = (ComboBoxItem)AppName.SelectedItem;
   string selectedText = cbi.Content.ToString();
}
Ramon
quelle
Irgendwie wird nur SelectedItem mit dem neuen Element gefüllt, nicht SelectedValue.
Mauris
7

Das hat bei mir funktioniert:

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;            
}
Бранко Пејић
quelle
Dies ist sehr wichtig. Die akzeptierte Antwort zeigt nicht explizit, dass sie senderdie richtige enthält SelectedItem.
Jess
3

Das folgende Ereignis wird für jede Änderung des Texts in der ComboBox ausgelöst (wenn der ausgewählte Index geändert wird und wenn der Text auch durch Bearbeiten geändert wird).

<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />
Petr Voborník
quelle
1
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
    string newItem = ((DataRowView) e.AddedItems[0]).Row.ItemArray[0].ToString();
}
Buratino
quelle
4
Bitte geben Sie keine Nur-Code-Antworten an. Bitte erläutern Sie, warum Ihre Lösung die Antwort ist.
Lee Taylor
1

Die zweite Option hat bei mir nicht funktioniert, da das .Text-Element außerhalb des Gültigkeitsbereichs lag (C # 4.0 VS2008). Das war meine Lösung ...

string test = null;
foreach (ComboBoxItem item in e.AddedItems)
{
   test = item.Content.ToString();
   break;
}
Josh
quelle
0

Ich musste dies in VB.NET lösen. Folgendes scheint zu funktionieren:

Private Sub ComboBox1_SelectionChanged(ByVal sender As System.Object, ByVal e As System.Windows.Controls.SelectionChangedEventArgs) Handles ComboBox_AllSites.SelectionChanged
   Dim cr As System.Windows.Controls.ComboBoxItem = ComboBox1.SelectedValue
   Dim currentText = cr.Content
   MessageBox.Show(currentText)
End Sub
zzMzz
quelle
0

Es ist seltsam, dass SelectedItem die frischen Daten enthält, SelectedValue jedoch nicht. Klingt für mich nach einem Fehler. Wenn Ihre Elemente in der Combobox andere Objekte als ComboBoxItems sind, benötigen Sie Folgendes: (my ComboBoxenthält KeyValuePairs)

var selectedItem = (KeyValuePair<string, string>?)(sender as ComboBox).SelectedItem;
if (!selectedItem.HasValue)
    return;

string selectedValue = selectedItem.Value.Value;  // first .Value gets ref to KVPair

ComboBox.SelectedItemkann null sein, während Visual Studio mir immer wieder sagt, dass a KeyValuePairnicht null sein kann. Deshalb habe ich das SelectedItemauf nullable gesetzt KeyValuePair<string, string>?. Dann überprüfe ich, ob selectedItemes einen anderen Wert als hat null. Dieser Ansatz sollte auf jeden Typ Ihres ausgewählten Elements anwendbar sein.

sorrymissjackson
quelle
0

Wenn Sie das SelectionChangedEreignis wirklich brauchen , ist die beste Antwort die Antwort von SwDevMan81. Wenn Sie jedoch mit WPF beginnen, möchten Sie möglicherweise lernen, wie Sie Dinge auf WPF-Weise tun. Dies unterscheidet sich von den alten Windows Forms-Tagen, in denen Ereignisse wie SelectionChangedWPF und Model View ViewModel verwendet wurden Verwenden Sie Bindungen. Hier ist ein Codebeispiel:

// In the Views folder: /Views/MyWindow.xaml:
// ...
<ComboBox ItemsSource="{Binding MyViewModel.MyProperties, RelativeSource={RelativeSource AncestorType=Window}}"
         SelectedItem="{Binding MyViewModel.MyProperty  , RelativeSource={RelativeSource AncestorType=Window}}" />
// ...



// In the Views folder: /Views/MyWindow.xaml.cs:
public partial class MyWindow : Window
{
    public  MyViewModelClass MyViewModel {
        get { return _viewModel; }
        private set { _viewModel = value;}
    }

    public MyWindow()
    {
        MyViewModel.PropertyChanged += MyViewModel_PropertyChanged;

    }

    void MyViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "MyProperty")
        {
            // Do Work
            // Put your logic here!
        }
    }
}

using System.ComponentModel;

// In your ViewModel folder: /ViewModels/MyViewModelClass.cs:
public class MyViewModelClass : INotifyPropertyChanged
{
    // INotifyPropertyChanged implementation:
    private void NotifyPropertyChanged(string propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } }
    public event PropertyChangedEventHandler PropertyChanged;

    // Selected option:
    private string _myProperty;
    public  string  MyProperty {
        get { return _myProperty; }
        set { _myProperty = value; NotifyPropertyChanged("MyProperty"); }
    }

    // Available options:
    private List<string> _myProperties;
    public  List<string>  MyProperties {
        get { return _myProperties; }
        set { _myProperties = value; NotifyPropertyChanged("MyProperties"); }
    }

}
Lazaro
quelle
0
private void indBoxProject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int NewProjID = (e.AddedItems[0] as kProject).ProjectID;
    this.MyProject = new kProject(NewProjID);
    LoadWorkPhase();
}

Die Verwendung von e.AddedItems[0] as kProjectwhere kProject ist eine Klasse, die die für mich bearbeiteten Daten enthält, da standardmäßig RemovedItems [0] verwendet wurde, bevor ich diese explizite Unterscheidung getroffen habe. Vielen Dank an SwDevMan81 für die ersten Informationen, die diese Frage für mich beantwortet haben.

Kyjote
quelle
0

Komplizieren Sie die Dinge nicht ohne Grund. Mit der SelectedValue-Eigenschaft können Sie auf einfache Weise einen ausgewählten ComboBox-Wert wie folgt abrufen: YourComboBoxName.SelectedValue.ToString ().

Hinter den Kulissen ist die SelectedValue-Eigenschaft wie folgt definiert: SelectedValue {get; set;} Dies bedeutet, dass Sie damit den Wert einer ComboBox abrufen oder festlegen können.

Die Verwendung von SelectedItem ist kein effizienter Weg, um einen ComboBox-Wert zu erhalten, da viele Konsequenzen erforderlich sind.

Sam Tomashi
quelle
0

Sie können die SelectedIndex- oder SelectedValue- oder SelectedItem-Eigenschaft im SelectionChanged-Ereignis des Combobox-Steuerelements überprüfen.

user7347514
quelle
-2

Das sollte für Sie funktionieren ...

int myInt= ((data)(((object[])(e.AddedItems))[0])).kid;
Seelenausgang
quelle
2
Können Sie erklären, wie dies die Frage beantwortet?
Nathan Tuggy
-3

Ich habe dieses Problem mithilfe des DropDownClosed-Ereignisses gelöst, da es nach dem Ändern des Werts leicht ausgelöst wird.

user5028920
quelle