WPF C# NULL exception on combobox selection change - c#

This is selection changed event :
private void cbUsers_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SelectedUser = (sender as ComboBox).SelectedItem.ToString();
GetUserInformation();
}
GetUserInformation is just selecting password from database. Users are deleted from the database and then the following refreshes the ComboBox items:
public void FillComboBox()
{
cbUsers.ItemsSource = null;
HProDataContext db = new HProDataContext();
var _UserName = (from d in db.users select d.username).ToList();
cbUsers.ItemsSource = _UserName;
}
HProDataContext db = new HProDataContext();
var _UserID = (from d in db.users where d.username == cbUsers.Text select d.id).SingleOrDefault();
user u = db.users.Single(p => p.id == _UserID);
db.users.DeleteOnSubmit(u);
db.SubmitChanges();
cbUsers.ItemsSource = null;
cbUsers.Text = null;
FillComboBox();
When using this last method it gives such error:
Object reference not set to an instance of an object.
The error falls on this line of the FillComboBox method:
SelectedUser = (sender as ComboBox).SelectedItem.ToString();
Does anyone have an idea as to what is wrong?

I'd guess that SelectedItem is null and therefore you're calling ToString on nothing.
Consider trying this:
if ((sender as ComboBox).SelectedItem != null)
{
SelectedUser = (sender as ComboBox).SelectedItem.ToString();
}
However, doesn't your ComboBox have an identifier? This can allow you to refrain from unnecessary conversions with as:
if (myComboBox.SelectedItem != null)
{
SelectedUser = myComboBox.SelectedItem.ToString();
}

Your event handler is probably getting called when there is no SelectedItem.
I would write this as:
private void cbUsers_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var usersComboBox = (ComboBox)sender;
if (usersComboBox.SelectedItem == null) return;
SelectedUser = usersComboBox.SelectedItem.ToString();
GetUserInformation();
}
Here you are expecting that sender is always a ComboBox, so I would use a cast instead of as. The exception will let you know if your assumption is wrong.
This will just skip your code if the event handler is called without a selected item.

One possibility is that sender might not be a ComboBox.
A problem of using an as operator without a null check is you get a NullReferenceException instead of a InvalidCastException which is more appropriate
Use an explicit cast instead e.g. ((ComboBox)sender).SelectedItem.ToString(); if you are sure sender is a ComboBox; otherwise check for null before usage.

Related

ComboBox Selection Change keeps looping

I am currently developing a WPF app in which there are multiple forms to manage a database. One of these forms is a "Add form". This form contains a combobox with some values. Though if the user's wanted value is not in the combobox list, it can be added by selecting the last option which will display a new form for entering the wanted value. If the form is submitted, the last option in the combobox will be changed to this value. The code below describes how this works:
private void BrandBoxSelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (BrandBox.SelectedItem != null &&
BrandBox.SelectedIndex < BrandBox.Items.Count - 1)
{
InitSubCategoryBox(subCatArray[BrandBox.SelectedIndex]);
}
else if (BrandBox.SelectedItem != null &&
BrandBox.SelectedIndex >= BrandBox.Items.Count - 1)
{
OtherInputWindow newInputForm = new OtherInputWindow("brand", BrandBox.SelectedItem.ToString());
if (newInputForm.ShowDialog() == true)
{
BrandBox.Items[BrandBox.Items.Count - 1] = newInputForm.returnValue;
BrandBox.SelectedIndex = BrandBox.Items.Count - 1;
}
}
}
The last code line will set the submitted value as selected item. I know this does not work. This last line of code will create a SelectionChanged event and that is exactly what this method is. The result is that it will keep looping and there is no way out. I'm searching for the right way to do this for a long time but I wasn't able yet to find the answer. Hopefully I will find the answer here. Is there someone who can help me solving this problem?
I would suggest to not change the SelectedItem from the SelecetionChanged event handler. Instead handle the UIElement.PreviewMouseLeftButtonUp event from the ComboBox:
<ComboBox PreviewMouseLeftButtonUp="OnComboBoxItemPreviewMouseLeftButtonUp" />
private void OnComboBoxItemPreviewMouseLeftButtonUp(object sender, RoutedEventArgs e)
{
var selector = sender as Selector;
var clickedItemContainer = Selector.ContainerFromElement(selector, e.OriginalSource as DependencyObject);
bool isClickTargetItemContainer = clickedItemContainer is not null;
if (!isClickTargetItemContainer)
{
return;
}
int selectedIndex = selector.ItemContainerGenerator.IndexFromContainer(clickedItemContainer);
int lastIndex = selector.Items.Count - 1;
if (selector.SelectedIndex == lastIndex)
{
var newInputForm = new OtherInputWindow("brand", selectedItem.ToString());
if (newInputForm.ShowDialog() == true)
{
selector.Items[lastIndex] = newInputForm.returnValue;
selector.SelectedIndex = lastIndex;
}
}
else
{
InitSubCategoryBox(subCatArray[selector.SelectedIndex]);
}
}

Bad enum field value in asp.net

I am creating a little ASP.NET app and have a problem with one field value.
I have defined my enum in a class:
class Column
{
public enum Type {
Undefined = 0,
Integer = 1,
ShortDate = 2,
Etc = 3 }
// some other stuff
}
The app contains some controls to enter properties of a column, namely a dropdownlist for choosing the column type and some unimportant others. And when all properties are properly entered, SaveButton in enabled to save the column type info into a listbox. My Default.aspx.cs contains:
private Column.Type selectedType;
protected void Page_Load(object sender, EventArgs e)
{
// fill the ColumnTypeDropDownList (from the Column.Type enum)
if (!IsPostBack)
{
foreach (Column.Type ct in Enum.GetValues(typeof(Column.Type)))
{
ColumnTypeDropDownList.Items.Add(new ListItem(ct.ToString()));
}
}
}
protected void ColumnTypeDropDownList_SelectedIndexChanged(object sender, EventArgs e)
{
PrepareToSave();
}
// also called from other controls events, therefore in a separate method
private void PrepareToSave()
{
// control if all needed properties are entered and set the field
if ((ColumnNameTextBox.Text != "") && (ColumnTypeDropDownList.SelectedValue != Column.Type.Undefined.ToString()))
{
foreach (Column.Type ct in Enum.GetValues(typeof(Column.Type)))
{
if (ct.ToString() == ColumnTypeDropDownList.SelectedValue) selectedType = ct;
}
SaveButton.Enabled = true;
}
}
protected void SaveButton_Click(object sender, EventArgs e)
{
ColumnsListBox.Items.Add(selectedType.ToString()); // always writes "Undefined"
}
The problem is that it always writes "Undefined" into the listbox, even though another type was selected from the dropdownlist. I tried to add the item into the listbox inside the PrepareToSave() method and that works correctly, but I need it outside. On the other hand, the condition controlling if any other value than Undefined is selected from the dropdownlist works well. It seems that the field selectedType has the correct selected value only inside the PrepareToSave() method.
AutoPostBack of all the controls is enabled.
Am I missing something about the enums or do you have any tips how to fix it? Thanks.
Your problem is in the line...
ColumnTypeDropDownList.Items.Add(new ListItem(ct.ToString()));
..namely in new ListItem(ct.ToString()). When you use this constructor of the ListItem class, you create an item with Value set to null. Later you compare against the value:
if (ct.ToString() == ColumnTypeDropDownList.SelectedValue) selectedType = ct;
Since Value of each of the items is null, ColumnTypeDropDownList.SelectedValue is also null and your comparison fails. That should be also easily figured out in a debugger.
The correct list item constructor for you is
ListItem listItem = new ListItem(ct.ToString(), ct.ToString());
As an additional issue, you have to call PrepareToSave in SaveButton_Click, since the selectedType field will have lost its value across requests. PrepareToSave will rebuild that value.
That's most probably because of your if condition as pointed below
if ((ColumnNameTextBox.Text != "") && (ColumnTypeDropDownList.SelectedValue != Column.Type.Undefined.ToString()))
{
Instead of ColumnNameTextBox.Text != "" use !string.IsNullOrEmpty(ColumnNameTextBox.Text)
Just another tip:
Use GetNames instead of GetValues in your foreach loop:
foreach (var ct in Enum.GetNames(typeof(Column.Type)))
{
//do your stuff.
}
If you want to use AutoPostBack ...
Add a hidden control to your page.
In your PrepareToSave(); method you just can add the selectetType like yourControlName.Text = ct;
And change your save handler to this ....
protected void SaveButton_Click(object sender, EventArgs e)
{
// Read the value of the hidden control
ColumnsListBox.Items.Add(yourControlName.Text);
}

How to set binding property to null if DatePickerTextBox is left empty

My DatePickerTextBox is binded to a property of type DateTime? (which allows null)
I would like to set this property to null if the DatePickerTextBox is left empty.
My current approach:
private void TextChanged_Handler(object sender, TextChangedEventArgs e)
{
var dateTimePickerTextBox = (DatePickerTextBox)sender;
if (dateTimePickerTextBox.Text == string.Empty)
this.MyBindingObj.MyDate = null;
}
This works, but it has the disadvantage that the DatePickerTextBox UI is marked as red (error), because the binding between the text and DateTime was not successful. Although behind the scenes everything works fine.
I wonder if there is a cleaner way to do this.
I found a workaround, by simply adding dateTimePickerTextBox.Text = null; to the previous code:
private void TextChanged_Handler(object sender, TextChangedEventArgs e)
{
var dateTimePickerTextBox = (DatePickerTextBox)sender;
if (dateTimePickerTextBox.Text == string.Empty)
{
this.MyBindingObj.MyDate = null;
// Added this to avoid validation error:
dateTimePickerTextBox.Text = null;
}
}

Object reference not set to an instance of an object c#

I have a listbox and i'm trying to select an item to display a label. My code is as follows:
private void listBox2_MouseDown(object sender, MouseButtonEventArgs e)
{
ListBox lb = (ListBox)sender;
var selected = lb.SelectedValue.ToString();
//string selected = listBox2.SelectedItem.ToString();
label5.Visibility = Visibility.Visible;
if (selected.ToString() == "Study Date")
{
label5.Content = "Format:YYYYMMDD";
}
if (selected.ToString() == "Patient's Name") label5.Content = "Enter name in string format.";
}
But when i click on an item, i get an error as: Object reference not set to instance of an object. I cannot enter the code in the Selection changed event, so please tell me how I can go about this. Thanks!
You have a potential issue here:
var selected = lb.SelectedValue.ToString();
You are calling ToString() even though SelectedValue can be null
Before you call ToString() make sure SelectedValue is not null
IIRC the MouseDown() event fires before the selection is registered. Wouldn't you be better off using the SelectionChanged() event?

Comboboxes only load when selecting the second items and below

This is really strange. I want to select a State and load Cities from that State in another combobox.
It's working EXCEPT when selecting the first item in the combobox:
Here's my entire class. The if statement in the selectedIndexChanged is to make sure that something is selected. The problem is that if I set that to cmbState.SelectedIndex >= 0 then an exception is raised because on initial load the comboBox doesn't has a .State variable there and not a .Value.
I don't know if this makes any sense.
private void MainForm_Load(object sender, EventArgs e)
{
LoadDepartmentsToComboBox();
}
private void LoadCitiesToComboBox(long StateID)
{
cmbCity.DataSource = null;
CityRepository cityRepo = new CityRepository();
cmbCity.DataSource = cityRepo.FindAllCities().Where(c => c.IDState == StateID);
cmbCity.DisplayMember = "Name";
cmbCity.ValueMember = "ID";
}
private void LoadDepartmentsToComboBox()
{
cmbState.DataSource = null;
StateRepository stateRepo = new StateRepository();
cmbState.DataSource = stateRepo.FindAllStates();
cmbState.DisplayMember = "Name";
cmbState.ValueMember = "ID";
}
private void cmbState_SelectedIndexChanged(object sender, EventArgs e)
{
if (cmbState.SelectedIndex > 0)
{
LoadCitiesToComboBox(Convert.ToInt64(cmbState.SelectedValue));
}
}
If I do use cmbState.SelectedIndex >= 0 then I receive this exception:
Unable to cast object of type
'DocumentScannerDanyly.State' to type
'System.IConvertible'.'System.IConvertible'.
When I don't use the SelectedIndex >= 0 and use plain old >0 then everything works except when selected the first item, which does nothing; understandably because it doesn't take the first item into account.
Thanks a lot for the help.
Don't assign the Display member & the Value member in each load, just assign them once in constructor for example.
add ToList() to the result which will assign to DataSource,
Complex DataBinding accepts as a data source either an IList or an IListSource.
check this.

Categories

Resources