ComboBox- SelectionChanged event has old value, not new value - c#

C#, .NET 4.0, VS2010.
New to WPF. I have a ComboBox on my MainWindow. I hooked the SelectionChanged event of said combo box. However, if I examine the value of the combo box in the event handler, it has the old value. This sounds more like a "SelectionChanging" event, than a SelectionChanged event.
How do I get the new value of the ComboBox after the selection has actually happend?
Currently:
this.MyComboBox.SelectionChanged += new SelectionChangedEventHandler(OnMyComboBoxChanged);
...
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
string text = this.MyComboBox.Text;
}
Note, I get the same behaviour if I use the object being passed in the event args, e.g. e.OriginalSource.

According to MSDN, e.AddedItems:
Gets a list that contains the items that were selected.
So you could use:
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
string text = (e.AddedItems[0] as ComboBoxItem).Content as string;
}
You could also use SelectedItem if you use string values for the Items from the sender:
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
string text = (sender as ComboBox).SelectedItem as string;
}
or
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
string text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
}
Since both Content and SelectedItem are objects, a safer approach would be to use .ToString() instead of as string

The correct value to check here is the SelectedItem property.
A ComboBox is a composite control with two of its parts being:
The Text Part: the value in the this part corresponds to the Text property of the ComboBox.
The Selector Part (i.e. the "drop-down" part): The selected item in this part corresponds to the SelectedItem property.
The image above was taken immediately after the ComboBox was expanded (i.e. before selecting a new value). At this point both Text and SelectedItem are "Info", assuming the ComboBox items were strings. If the ComboBox items were instead all the values of an Enum called "LogLevel", SelectedItem would currently be LogLevel.Info.
When an item in the drop-down is clicked on, the value of SelectedItem is changed and the SelectionChanged event is raised. The Text property isn't updated yet, though, as the Text Part isn't updated until after the SelectionChanged handler is finished. This can be observed by putting a breakpoint in the handler and looking at the control:
Since the Text Part hasn't been updated at this point, the Text property returns the previously selected value.

Use the DropDownClosed event instead of selectionChanged if you want the current value of the combo box.
private void comboBox_DropDownClosed(object sender, EventArgs e)
{
MessageBox.Show(comboBox.Text)
}
Is really that simple.

This worked for me:
private void AppName_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ComboBoxItem cbi = (ComboBoxItem)AppName.SelectedItem;
string selectedText = cbi.Content.ToString();
}

This worked for me:
private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
var text = ((sender as ComboBox).SelectedItem as ComboBoxItem).Content as string;
}

Following event is fired for any change of the text in the ComboBox (when the selected index is changed and when the text is changed by editing too).
<ComboBox IsEditable="True" TextBoxBase.TextChanged="cbx_TextChanged" />

private void OnMyComboBoxChanged(object sender, SelectionChangedEventArgs e)
{
string newItem = ((DataRowView) e.AddedItems[0]).Row.ItemArray[0].ToString();
}

The second option didn't work for me because the .Text element was out of scope (C# 4.0 VS2008). This was my solution...
string test = null;
foreach (ComboBoxItem item in e.AddedItems)
{
test = item.Content.ToString();
break;
}

If you really need the SelectionChanged event, then the best answer is SwDevMan81's answer. However, if you are starting with WPF, then you might want to learn how to do things the WPF way, which is different than the old Windows Forms days that used to rely on events like SelectionChanged, with WPF and Model View ViewModel pattern, you should use bindings. Here is a code example:
// 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"); }
}
}

private void indBoxProject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int NewProjID = (e.AddedItems[0] as kProject).ProjectID;
this.MyProject = new kProject(NewProjID);
LoadWorkPhase();
}
The use of the e.AddedItems[0] as kProject where kProject is a class that holds the data worked for me as it was defaulting to the RemovedItems[0] before I have made this explicit distinction. Thanks SwDevMan81 for the initial information that answered this question for me.

I needed to solve this in VB.NET. Here's what I've got that seems to work:
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

It's weird that SelectedItem holds the fresh data, whereas SelectedValue doesn't. Sounds like a bug to me. If your items in the Combobox are objects other than ComboBoxItems, you will need something like this: (my ComboBox contains 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.SelectedItem can be null, whereas Visual Studio keeps telling me that a KeyValuePair can't be null. That's why I cast the SelectedItem to a nullable KeyValuePair<string, string>?. Then I check if selectedItem has a value other than null. This approach should be applicable to whatever type your selected item actually is.

Don't complicate things for no reason. Using SelectedValue property you can easily get a selected ComboBox value like this: YourComboBoxName.SelectedValue.ToString().
Behind the scene the SelectedValue property is defined as: SelectedValue{get; set;} this means you can use it to get or set the value of a ComboBox.
Using SelectedItem is not an efficient way to get a ComboBox value since it requires a lot of ramifications.

You can check SelectedIndex or SelectedValue or SelectedItem property in the SelectionChanged event of the Combobox control.

From SelectionChanged event of a combobox you can get the selected item text as follow:
private void myComboBox_SelectionChanged (object sender, SelectionChangedEventArgs e)
{
ComboBoxItem comboBoxItem = (ComboBoxItem) e.AddedItems[0];
string selectedItemText = comboBoxItem.Content.ToString();
}

clean and easy - TextChanged
private void ComboBox1_TextChanged(object sender, EventArgs e)
{
MessageBox.Show(ComboBox1.Text);
}

Following works for me to get current selection of ComboBox (c# / .net6):
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) {
string? text = ((ComboBoxItem)(sender as ComboBox).SelectedItem).Content as string;
if(text != null){
...
}
}

This should work for you ...
int myInt= ((data)(((object[])(e.AddedItems))[0])).kid;

I solved this by using the DropDownClosed event because this fires slightly after the value is changed.

Related

Set Default Value for ListBox

In my solution I have set the default value for list like below code
<ListBox x:Name="SelectorList"
ItemsSource="{Binding ViewStatusList}"
SelectedItem="{Binding SelectedDeviceItem,Mode=TwoWay}"
IsSynchronizedWithCurrentItem="True">
create the property for SelectedDeviceItem in my view model.
private Device _selecteddeviceitem;
public Device SelectedDeviceItem
{
get
{
return _selecteddeviceitem;
}
set
{
_selecteddeviceitem = value;
OnPropertyChanged("SelectedDeviceItem");
}
}
and passed SelectedDeviceItem = StatusList[0];
in the constructor.
But still my listbox will be shown like below.
But I need the result should be like below image
What have I missed in the this list box code?
I think this could achieve it:
Set the selected ListBoxItem to be focused.
private void ListBox_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var listbox = sender as ListBox;
var listboxItem =
listbox?.ItemContainerGenerator.ContainerFromItem(listbox.SelectedItem) as ListBoxItem;
listboxItem?.Focus();
}
Set focus when the ListBox loaded. This is because that the ListBoxItems may be selected before they are generated.
private void ListBox_Loaded(object sender, RoutedEventArgs e)
{
var listbox = sender as ListBox;
var listboxItem =
listbox?.ItemContainerGenerator.ContainerFromItem(listbox.SelectedItem) as ListBoxItem;
listboxItem?.Focus();
}
Note that the logic of making item being selected should not be achieved in the view model, it's just kind of a UI logic.
it seems ListboxItem not focused . Please Set ListBox to focus and item to focus
listBox.Focus();
var listBoxItem = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem);
listBoxItem.Focus();

Editable Combobox not updating when empty

I have an editable combobox here:
<ComboBox IsEditable="True"
Text="{Binding Model.TNumber}" SelectedItem="{Binding SelectedT}" ItemsSource="{Binding TList}"
IsEnabled="{Binding EnableTComboBox}"/>
The combobox works, except when you backspace it and have it empty.The box will default to the first value in the list. If I backspace it and leave the combobox empty, the variable TNumber will still contain the previously entered number.
Is there a way to have the variable to be empty?
TNumber is a short.
I'm not sure at which point you are checking the value of TNumber, but what you could do is set it's value in a SelectionChanged event handler:
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
TNumber = (sender as ComboBox).SelectedItem as short?;
}
But this requires that you define TNumber as a nullable short (short?).
Alternatively, if you didn't want to allow a nullable short, you could use:
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var newValue = (sender as ComboBox).SelectedItem;
if (newValue == null)
TNumber = 0;
else
TNumber = (short)newValue;
}
Which first checks whether the new value is equal to null. If it is, then we set TNumber to 0 (or whatever value you need it to be).
While testing for this, I noticed that TNumber seems to be updated after the SelectioinChanged event fires, meaning that whenever you check the value of TNumber inside the event, it will contain the previous value.
One way of working around this is by adding this line to the top of the event handler:
comboBox.Items.Refresh();
Which sets TNumber to the new value. However this does not work when deleting the value from the ComboBox! (In this case, TNumber is again only updated after the SelectionChanged event handler).
I have no idea why this is, but I also tested it when working with TNumber as a short? with the same result.
private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
comboBox.Items.Refresh();
var value = (sender as ComboBox).SelectedItem; // Tested using short? with same result
var x = TNumber;
}
Perhaps someone else could shed som light on why this happens, or at which point exactly the TNumber value is updated from the binding.

Add selected item from a bound listbox to a unbound listbox

i want to add selected item from a data bounded listbox (listbox1) to another listbox (listbox2)
Here is the code on a click event of a button.
private void btnrgt_Click(object sender, EventArgs e)
{
string x = listBox1.SelectedItem.ToString();
listBox2.Items.Add(x.ToString());
txttestno.Text = listBox2.Items.Count.ToString();
}
When i run this code System.data.datarowview get displayed in the listbox2.
Kindly help.
thank you in advance.
When you bind a ListBox datasource to a DataTable every item inside the ListBox is a DataRowView, not a simple string. In the ListBox you see a string displayed because you set the DisplayMember property of the ListBox with the name of a column in that DataRowView.
So, taking the current SelectedItem doesn't return a string but a DataRowView and calling ToString() for a DataRowView returns the full qualified name of the class (System.Data.DataRowView).
You need something like this
private void btnrgt_Click(object sender, EventArgs e)
{
DataRowView x = listBox1.SelectedItem as DataRowView;
if ( x != null)
{
listBox2.Items.Add(x["NameOfTheColumnDisplayed"].ToString());
txttestno.Text = listBox2.Items.Count.ToString();
}
}
EDIT
It is not clear what is the source of the error stated in your comment below, however you could try to avoid adding an item from the first listbox to the second one if that item exists in the second listbox with code like this
private void btnrgt_Click(object sender, EventArgs e)
{
DataRowView x = listBox1.SelectedItem as DataRowView;
if ( x != null)
{
string source = x"NameOfTheColumnDisplayed".ToString();
if(!listbox2.Items.Cast<string>().Any(x => x == source))
{
listbox2.Items.Add(source);
txttestno.Text = listBox2.Items.Count.ToString();
}
}
}
This solutions works if your second listbox is really populated adding simple strings to its Items collection.
On click button use below code.
protected void btnGo_Click(object sender,EventArgs e) {
string x = ListBox1.SelectedItem.Text;
ListBox2.Items.Add(x);
}

Update DataGrid's ItemsSource on SelectionChanged event of a ComboBox

I subscribed to a SelectionChangedEvent on a ComboBox in a DataGrid with the following code:
public static DataGridTemplateColumn CreateComboboxColumn(string colName, Binding textBinding, SelectionChangedEventHandler selChangedHandler = null)
{
var cboColumn = new DataGridTemplateColumn {Header = colName};
...
if (selChangedHandler != null)
cboFactory.AddHandler(Selector.SelectionChangedEvent, selChangedHandler);
...
return cboColumn;
}
The handler I actually register contains:
private void ComboBoxSelectionChangedHandler(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine(#"selectHandler");
var cboBox = sender as ComboBox;
if (cboBox == null)
return;
if (cboBox.IsDropDownOpen) // a selection in combobox was made
{
CommitEdit();
}
else // trigger the combobox to show its list
cboBox.IsDropDownOpen = true;
}
... and is located in my custom DataGrid class.
If I select an item in the ComboBox, e.AddedItems and cboBox.SelectedItem contains the selected value, but nothing is changed on CommitEdit().
What I want is to force a commit to directly update the DataGrid's ItemsSource, when the user selects an item in the drop-down-list. Normally this is raised if the control looses focus...
The link in the solution found in this thread is not available any more and I don't know how to use this code.
I created a tricky, but working, solution for my problem. Here's the modified handler from above:
private void ComboBoxSelectionChangedHandler(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine(#"selectHandler");
var cboBox = sender as ComboBox;
if (cboBox == null)
return;
if (cboBox.IsDropDownOpen) // a selection in combobox was made
{
cboBox.Text = cboBox.SelectedValue as string;
cboBox.MoveFocus(new TraversalRequest(FocusNavigationDirection.Right));
}
else // user wants to open the combobox
cboBox.IsDropDownOpen = true;
}
Because my ComboBoxColumn is a custom DataGridTemplateColumn I force it to show its list, when the user first selects the cell.
To change the bound items value I manually overwrite the displayed text with recently selected item and force the UI to select another item (in this case the control to the right) to make an implicit call to CellEditEnding event, which (in my case) commits the whole row:
private bool _isManualEditCommit = false;
private void _CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
// commit a manual edit
// this if-clause prevents double execution of the EditEnding event
if (!_isManualEditCommit)
{
Console.WriteLine(#"_CellEditEnding() manualeditcommit");
_isManualEditCommit = true;
CommitEdit(DataGridEditingUnit.Row, true);
_isManualEditCommit = false;
checkRow(e.Row);
}
}
Maybe I could help somebody with this "dirty" solution ;-)

C#: Convert a string to an object reference

Basically a button's tag property is the name of an existing combobox which I need to dynamically reference. It's a generic function to handle multiple buttons. Help
private void SQLButton(object sender, EventArgs e)
{
magic(((Button)sender).Tag.ToString());
}
private void magic(string currentcombo)
{
string CurrentText = (ComboBox).(currentcombo).Text;
}
You can set the Tag property to the actual ComboBox and avoid your problem altogether.
//code when defining your button...
{
sqlButton.Tag = comboBoxA; //instead of comboBoxA.Name
}
private void SQLButton(object sender, EventArgs e)
{
Button button = sender as Button;
ComboBox comboBox = button.Tag as ComboBox;
if (comboBox == null )
{...}
else
{
magic(comboBox);
}
}
private void magic(ComboBox currentcombo)
{
string CurrentText = currentcombo.Text;
}
I think I understand what you're after -
You'll want to change your "magic" routine to something like:
private void magic(string currentCombo) {
ComboBox box = this.Controls.Find(currentCombo) as ComboBox;
if(box != null) {
// You can do your "work" here...
string currentText = box.Text;
}
}
If you have the string id value of a control then you can use FindControl to get a reference to the control.
Something like ...
Button btn = (Button)FindControl("some_id");
I don't know if its winforms or asp.net. I am assuming it to be winforms
You could use this.Controls(theNameofTheControl) instead of magic.
Have a look at the Controls.Find Method, to get the instance of the Control using the name.
If currentcombo paramter in magic function is the identifier for the control you are going to change then use Page's function FindControl:
string CurrentText = ((ComboBox)FindControl(currentcombo)).Text;
Page.FindControl() method searches the page naming container for a server control with the specified identifier.

Categories