2010-06-02 52 views
70

C#, .NET 4.0, VS2010.ComboBox- Sự kiện SelectionChanged có giá trị cũ, không phải giá trị mới

Mới đối với WPF. Tôi có một ComboBox trên MainWindow của tôi. Tôi nối sự kiện SelectionChanged của hộp kết hợp đã nói. Tuy nhiên, nếu tôi kiểm tra giá trị của hộp combo trong trình xử lý sự kiện, nó có giá trị cũ. Điều này nghe có vẻ giống như một sự kiện "SelectionChanging" hơn là một sự kiện SelectionChanged.

Làm cách nào để có được giá trị mới của ComboBox sau khi lựa chọn thực sự xảy ra?

Hiện tại:

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

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

Lưu ý, tôi nhận được hành vi tương tự nếu tôi sử dụng các đối tượng được thông qua trong args sự kiện, ví dụ e.OriginalSource.

+2

Tôi vừa vấp phải cùng một vấn đề - cảm ơn! Đó thực sự là một lỗi, và nó nên được đặt tên * 'SelectionChanging' * ngay từ đầu? – Jan

Trả lời

83

Theo MSDN, e.AddedItems:

Gets một danh sách có chứa các vật phẩm đã được lựa chọn.

Vì vậy, bạn có thể sử dụng:

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

Bạn cũng có thể sử dụng SelectedItem nếu bạn sử dụng string giá trị cho các Items từ sender:

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

hoặc

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

Bởi vì cả ContentSelectedItem là những vật thể, một cách tiếp cận an toàn hơn sẽ được sử dụng thay vì .ToString()as string

+10

thú vị ... nó có giá trị mới. Và RemovedItems có cũ. Tên sự kiện đó là một chút nếu một tên nhầm lẫn, ít nhất là IMHO. Khi tôi thấy SelectionChanged, tôi mong đợi trạng thái của đối tượng, tốt, đã thay đổi. Tôi có thể thấy làm thế nào điều này mang lại cho chúng ta nhiều thông tin hơn mặc dù. – Matt

+0

Vâng, tôi nghĩ rằng nó bởi vì sự thay đổi đã xảy ra, nhưng chưa được cam kết? Thats chỉ là một đoán. Bạn có thể nhận được văn bản của mục đã chọn, xem chỉnh sửa của tôi. – SwDevMan81

+0

Cả hai công việc, cảm ơn !! – Matt

1

Lựa chọn thứ hai không làm việc cho tôi bởi vì các yếu tố .text là ra khỏi phạm vi (C# 4.0 VS2008). Đây là giải pháp của tôi ...

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

này đã làm việc cho tôi:

private void AppName_SelectionChanged(object sender, SelectionChangedEventArgs e) 
{ 
    ComboBoxItem cbi = (ComboBoxItem)AppName.SelectedItem; 
    string selectedText = cbi.Content.ToString(); 
} 
+0

bằng cách nào đó chỉ SelectedItem được điền với mục mới, không phải SelectedValue. – mauris

0

tôi cần thiết để giải quyết việc này trong VB.NET. Đây là những gì tôi đã có điều đó dường như làm việc:

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 
0
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e) 
{ 
    string newItem = ((DataRowView) e.AddedItems[0]).Row.ItemArray[0].ToString(); 
} 
+3

Vui lòng không cung cấp câu trả lời chỉ có mã. Vui lòng giải thích tại sao giải pháp của bạn là câu trả lời. –

40

Sử dụng sự kiện DropDownClosed thay vì SelectionChanged nếu bạn muốn giá trị hiện tại của combo box.

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

Thực sự đơn giản.

+0

Cảm ơn bạn đời, làm việc như một say mê. –

+10

@jvelez Tôi nghĩ rằng nó sẽ không cháy khi sử dụng bàn phím. – NoviceProgrammer

+0

hút. NoviceProgrammer biết ...! – hidden

-2

này nên làm việc cho bạn ...

int myInt= ((data)(((object[])(e.AddedItems))[0])).kid; 
+1

Bạn có thể giải thích cách này trả lời câu hỏi không? –

0

Đó là lạ mà SelectedItem giữ dữ liệu mới, trong khi SelectedValue không. Nghe có vẻ như một lỗi đối với tôi.Nếu mặt hàng bạn trong Combobox là những vật thể khác hơn ComboBoxItems, bạn sẽ cần một cái gì đó như thế này: (tôi ComboBox chứa KeyValuePair s)

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.SelectedItem có thể được null, trong khi Visual Studio giữ nói với tôi rằng một KeyValuePair không thể không có giá trị. Đó là lý do tại sao tôi bỏ số SelectedItem vào giá trị rỗng KeyValuePair<string, string>?. Sau đó, tôi kiểm tra xem selectedItem có một giá trị khác không phải là null. Cách tiếp cận này nên được áp dụng cho bất kỳ loại mục bạn đã chọn thực sự là.

-3

Tôi đã giải quyết vấn đề này bằng cách sử dụng sự kiện DropDownClosed vì sự kiện này sẽ xảy ra sau khi thay đổi giá trị.

0

Nếu bạn thực sự cần sự kiện SelectionChanged, thì câu trả lời hay nhất là câu trả lời của SwDevMan81. Tuy nhiên, nếu bạn đang bắt đầu với WPF, thì bạn có thể muốn tìm hiểu cách làm việc theo cách WPF, khác với ngày Windows Forms cũ sử dụng để dựa vào các sự kiện như SelectionChanged, với WPF và mô hình ViewModel Model View, bạn nên sử dụng các ràng buộc. Dưới đây là một ví dụ mã:

// 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"); } 
    } 

} 
32

Các giá trị chính xác để kiểm tra ở đây là SelectedItem tài sản.

Một ComboBox là một điều khiển tổng hợp với hai bộ phận của nó là:

  1. Text Phần: giá trị trong phần này tương ứng với chữ tài sản của ComboBox.
  2. Bộ phận chọn (ví dụ: phần "thả xuống"): Mục được chọn trong phần này tương ứng với thuộc tính SelectedItem.

Expanded ComboBox Parts

Những hình ảnh trên được chụp ngay sau khi ComboBox được mở rộng (ví dụ: trước khi lựa chọn một giá trị mới). Tại thời điểm này cả hai Văn bảnSelectedItem là "Thông tin", giả sử các mục ComboBox là chuỗi. Nếu các mục ComboBox thay vào đó tất cả các giá trị của một Enum được gọi là "LogLevel", SelectedItem hiện tại sẽ là LogLevel.Info.

Khi một mục trong trình đơn thả xuống được nhấp trên, giá trị của SelectedItem được thay đổi và SelectionChanged Sự kiện này được nâng lên. Các chữ bất động sản không được cập nhật bài viết nào, tuy nhiên, như chữ Phần không được cập nhật cho đến sau khi SelectionChanged xử lý xong.Điều này có thể được quan sát bằng cách đặt một breakpoint trong xử lý và xem xét các điều khiển:

ComboBox at breakpoint in SelectionChanged handler

Kể từ khi chữ Phần chưa được cập nhật tại thời điểm này, chữ tài sản trả về đã chọn trước đó giá trị.

+1

Hoàn thành expanation và nó đã giúp nhận ra ràng buộc của tôi là trên tài sản văn bản thay vì SelectedItem chính xác. – cmousset

4

này đã làm việc cho tôi:

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

Điều này rất quan trọng. Câu trả lời được chấp nhận không hiển thị rõ ràng rằng 'người gửi' chứa đúng' SelectedItem'. – Jess

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

Việc sử dụng các e.AddedItems[0] as kProject nơi kProject là một lớp chứa dữ liệu làm việc cho tôi như nó đã được mặc định cho các RemovedItems [0] trước khi tôi đã thực hiện sự phân biệt rõ ràng này. Cảm ơn SwDevMan81 vì những thông tin ban đầu đã trả lời câu hỏi này cho tôi.

1

Sự kiện sau được kích hoạt cho bất kỳ thay đổi nào của văn bản trong ComboBox (khi chỉ mục đã chọn được thay đổi và khi văn bản được thay đổi bằng cách chỉnh sửa quá).

<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />