which event handler would you use to catch a change to item in a bound combo box - keyboard-events

I have a bound combo box with a list of customer names. I tried the key_down which fires when I change which name is in the combo box. What I want is the event handler that will fire because that name is changing (like the spelling) not necessarily to a different name in the list. I am thinking that I will need to write a block of code to test for a change in spelling. Is there an event handler that will do the job?
I am working in Visual Studio using C# on a Windows form and SQL Server 2008
public Customer_Info_Form()
{
InitializeComponent();
button_Add_Customer.Visible = true;
button_Add_Location.Visible = true;
button_Save_Customer.Visible = false;
button_Cancel_Customer_Add.Visible = false;
}
private void Customer_Info_Form_Load(object sender, EventArgs e)
{
try
{
this.customerTableAdapter.Fill(this.customer_Info_DataSet.Customer);
this.customer_ShipTableAdapter.Fill(this.customer_Info_DataSet.Customer_Ship);
this.termsTableAdapter.Fill(this.terms_DataSet.Terms);
}
catch (Exception err)
{
MessageBox.Show(err.Message);
}
}
private void text_Changed(object sender, EventArgs e)
{
button_Add_Customer.Visible = false;
button_Add_Location.Visible = false;
button_Save_Customer.Visible = true;
button_Cancel_Customer_Add.Visible = true;
}
the "text_Changed" event fires on form load. it shouldn't fire until text is actually changed. I choose "Cancel", the buttons are reset and as soon as I choose a different customer name the event fires again. I haven't actually changed any of the text. how do I keep the "text_Changed" event from firing until text is actually changed?

You can use the TextChanged event
It will be fired whenever the value of the ComboBox changes.

when I tried the TextChanged event, it would fire as soon as the form would load and when I would select a different name in the bound combobox it would also fire rather then when the text actually changed.
in order to catch the change to the text of any selected item in the combobox I used the KeyDown event to catch a change to a name or any of the controls on the form.

Related

Closing a Windows Form, using the Close Window button, when a Validation Message is showing

I have a Windows form that has a validation event on a textBox so that if the value of that TextBox is a value that already exists it triggers a validation error.
private void txtUsername_Validating(object sender, CancelEventArgs e)
{
var alreadyExists = _logic.UserIdExists(txtUsername.Text.Trim());
if(alreadyExists)
{
errorProvider1.SetError(txtUsername, "This Userid already exists, please choose an alternative");
e.Cancel = true;
}
}
private void txtUsername_Validated(object sender, EventArgs e)
{
errorProvider1.SetError(txtUsername, "");
}
this.txtUsername.Validating += new System.ComponentModel.CancelEventHandler(this.txtUsername_Validating);
this.txtUsername.Validated += new System.EventHandler(this.txtUsername_Validated);
This results in an error image appearing next to that textBox along with a tooltip error message.
If I try and close the application, using the Close button at the top of the window, at this time I cannot as the above Event keeps firing even when I try and close the window (due to me taking focus away from the Text box).
Is there a way of closing the window, without resorting to creating an additional Close button on the form?
Based on your description, you want to maintain the default auto-validation behavior yet allow the Form to be closed using the title bar close button. I have observed that the Form.Closing event is raised in such a circumstance, however its argument Cancel property is preset to true. A simple solution is to handle this event and set e.Cancel = false. Implement any logic in the handler that you deem necessary.
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason == CloseReason.UserClosing) e.Cancel = false;
}

WPF Datagrid OnPropertyChanged causes SelectionChanged event

I have a WPF Datagrid that is bound to a model.
Inside the model I have a property defined as
public String status
{
get
{
return m_status;
}
set
{
m_status = value;
OnPropertyChanged("status");
}
}
This property informs the grid of changes via OnPropertyChanged.
I also handle the SelectionChanged event to trigger different activities.
SelectionChanged="gridSongs_SelectionChanged"
private void gridSongs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
Console.WriteLine("gridSongs_SelectionChanged " + sender.ToString());
}
During testing this I have noticed that every time I change the property "status" in code the grid updates automatically (which is what I want) but also fires the SelectionChanged Event as well.
Is there any way I can stop the event from firing when I change the model from code but let it go through when user clicks an item in the grid ?
Maybe I could use a different event for the manual selection of items in the grid ?
thanks a lot in advance.
Is there any way I can stop the event from firing when I change the model from code but let it go through when user clicks an item in the grid?
No, but there is a simple workaround. Add a private bool isLocal variable and set it to true before you make any changes and back to false afterwards:
isLocal = true;
status = "Some Value";
isLocal = false;
Then, in your SelectionChanged handler, check this variable and only react if it is false:
private void gridSongs_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!isLocal ) Console.WriteLine("gridSongs_SelectionChanged " + sender.ToString());
}

Silverlight AutoCompleteBox NotifyPropertyChanged does not update screen

It seems a few people are having problems with updating text AutoCompleteBox in Silverlight and sadly I've joined the ranks.
I've an derived class called EditableCombo like this;
public class EditableCombo : AutoCompleteBox
{
ToggleButton _toggle;
Path _btnPath;
TextBox _textBox;
...animation and toggle button stuff...
public override void OnApplyTemplate()
{
...animation and toggle button stuff...
//required to overcome issue in AutoCompleteBox that prevents the text being updated in some instances
//http://stackoverflow.com/questions/8488968/silverlight-5-autocompletebox-bug?rq=1
_textBox = GetTemplateChild("Text") as TextBox;
if (_textBox == null)
throw new NullReferenceException();
if (_textBox != null)
_textBox.TextChanged += TextBoxChanged;
base.OnApplyTemplate();
}
void TextBoxChanged(object sender, TextChangedEventArgs e)
{
Debug.WriteLine("text box changed fired new value: " + _textBox.Text);
Text = _textBox.Text;
OnTextChanged(new RoutedEventArgs());
}
...animation and toggle button stuff...
}
that enables users to click a togglebutton and select from the drop down list to choose an option or type in a new value like a standard combobox control.
My view has an EditableCombo control bound to a viewmodel containing a Gender property;
public string Gender
{
get
{
Debug.WriteLine("Gender get executed - Model.Gender = " + Model.Gender);
return Model.Gender;
}
set
{
if (Model.Gender == value) return;
MonitoredNotificationObject.RaisePropertyChanged(() => Model.Gender, value, this, true);
}
}
My viewmodel uses a MonitoredNotificationObject to maintain a undo/redo history and notify of any property changes;
public void RaisePropertyChanged(Expression<Func<string>> propertyExpression,
string newValue,
object sender,
bool canChain)
{
PropertyExpressionHelper propertyExpressionHelper = new PropertyExpressionHelper(propertyExpression)
{
NewValue = newValue
};
#if DEBUG
VerifyPropertyExists(propertyExpressionHelper.Name, sender);
#endif
var monitoredAction = new MonitoredProperty<TViewModel, TModel>(this)
{
ObjectPropertyName = propertyExpressionHelper.MakeObjectPropertyName(),
PropertyExpressionHelper = propertyExpressionHelper,
Sender = (TViewModel) sender,
CanChain = canChain
};
propertyExpressionHelper.SetToNewValue();
RaisePropertyChanged(propertyExpressionHelper.Name, sender);
MaintainMonitorState(monitoredAction);
}
Undo and redo are implemented as below (undo shown);
public override bool UndoExecute(MonitoredObject<TViewModel, TModel> undoAction,
Stack<MonitoredObject<TViewModel, TModel>> redoActions,
Stack<MonitoredObject<TViewModel, TModel>> undoActions)
{
PropertyExpressionHelper.SetToNewValue();
redoActions.Push(undoAction);
var action = (MonitoredProperty<TViewModel, TModel>) undoAction;
HandleAutoInvokedProperties(action);
if (action.CanChain)
{
if (undoActions.Any())
{
if (CanDoChain(undoActions, action))
return true;
}
}
action.RaiseChange();
Sender.RaiseCanExecuteChanges();
return false;
}
The property change notification is raised like this;
protected virtual void RaiseChange()
{
MonitoredNotificationObject.RaisePropertyChanged(PropertyExpressionHelper.Name, Sender);
if (RaiseChangeAction != null)
RaiseChangeAction.Invoke();
}
Using the above works fine for normal textboxes and successfully allows the user to undo and redo their changes as they desire. This also works for the EditableCombo when the user types an entry in the field - again, undo and redo perform as expected.
The issue is when the user selects a new value in the EditableCombo from the drop down list. The field updates, the Gender is set and everything looks fine. Clicking Undo successfully changes the field back to its original value - everything looking dandy.
However, when the user tries to redo the change the on screen value does not update. The underlying value is changed, the get on the Gender property is called and the Model.Gender value is correctly set. But then nothing. The screen does not update. The editablecombo control TextBoxChangedEvent does not fire so unsurprisingly the value on screen is not correct.
Basically the control is not being notified of the change.
Any ideas?
Update:
The view containing the EditableCombo has a viewmodel containing the Gender property. The property is bound like this;
<EditCombo:EditableCombo ItemsSource="{Binding Genders}"
ItemTemplate="{StaticResource editableComboDataTemplate}"
Style="{StaticResource EditableComboStyle}"
Text="{Binding Path=Gender,
UpdateSourceTrigger=PropertyChanged,
Mode=TwoWay,
ValidatesOnDataErrors=True}"
TextBoxStyle="{StaticResource editableComboDataEntryField}"
ValueMemberPath="Value" />
My implementation of undo/redo works fine for non-editablecombo controls and for the editablecombo when the new values are entered via the keyboard. The redo problem is only apparent when a property has been changed via the drop down toggle button. I know the underlying values are correctly updated as explained previously (and also, for example, as ValidatesOnDataErrors is on, when I redo and set the Gender property back to a valid value the red border signifying an error disappears - BUT, the text remains unchanged).
For whatever reason, the TextBoxChanged event never fires in the above scenario. Could it be the event is being handled elsewhere?
Does it work if you add this line:
Model.Gender = value;
to the property setter?

Silverlight DataGrid MouseLeftButtonDown event not raised when clicking on rows

Note: I have found a solution to my problem so I am posting this for reference purposes, although I would be happy to be educated with a better solution.
I'm trying to provide double click functionality on a Silverlight DataGrid by hooking into the UIElement.MouseLeftButtonDown but when I subscribe to the DataGrid.MouseLeftButtonDown using XAML or the DataGrid.MouseLeftButtonDown += syntax, my event handler is not called when I click on the rows within the DataGrid. If I click on the Header, the event is raised.
If I subscribe to the same event at the parent UserControl level, the event handler is called successfully as you would expect based on Silverlight RoutedEvents but then I have to detect whether the click occurred on the DataGrid or somewhere else.
If I subscribe to the event using this UIElement.AddHandler syntax, as shown below, then it works as expected based on the handledEventsToo: true parameter.
dataGrid.AddHandler(UIElement.MouseLeftButtonDownEvent,
new MouseButtonEventHandler(dataGrid_MouseLeftButtonDown)
, handledEventsToo: true);
It seems that the DataGrid implementation is marking these events as handled, prevent event bubbling, by default in one of the child UIElements, which is not what I expected initially. With more thought I can see that the click behaviour drives all sorts of things (select item, edit field etc.) so perhaps the implementation makes sense.
I had the same problem and I used MouseLeftButtonUp which fires the event but the clickcount value is always 1.
Here is the fix for that:
private const int MOUSE_SENSITIVITY = 300;
private DateTime _previousClick;
private void exceptionsDataGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
DataGrid dg = (sender as DataGrid);
DateTime current=DateTime.Now;
LoggerService.Exception exception = (LoggerService.Exception)dg.SelectedItem;
if (_previousClick != null)
{
TimeSpan clickSpan = current - _previousClick;
if (clickSpan.TotalMilliseconds < MOUSE_SENSITIVITY)
{
MessageBox.Show("You double clicked!");
}
}
_previousClick = current;
}

Canceling SelectedIndexChanged in WinForm ListView

The winform ListView doesn't seem to have an easy way to cancel the SelectedIndexChanged event. I don't see a SelectedIndexChanging event either.
The code is my attempt. However the hightlight is gone and I was wondering if I need to color the selection also or if there's a better way to cancel. _prevSelectedIndex is the index from the last selection. I want the highlight to go back to the previous selection.
lvSearchResults.SelectedIndexChanged -= new EventHandler(lvSearchResults_SelectedIndexChanged);
lvSearchResults.SelectedIndices.Clear();
lvSearchResults.SelectedIndices.Add(_prevSelectedIndex);
lvSearchResults.Items[_prevSelectedIndex].Selected = true;
lvSearchResults.SelectedIndexChanged += new EventHandler(lvSearchResults_SelectedIndexChanged);
The best and easy way is to have a boolean property which you set to say, true when you dont want the event to fire. In the SelectedIndexChange event, you test to see if you should allow the event to continue firing else you return. Check my code out. The code below behaves the same.
//somewhere on top
private bool dontFireEvent = false;
//somewhere else
dontFireEvent = true;
treeView1.SelectedNode = treeView1.Nod.... bla bla //event won't fire
dontFireEvent = false;
//within the event code
private void treeView1_AfterSelect(object sender, TreeViewEventArgs e)
{
if (!dontFireEvent)
ProcessLogin();
}
As long as you have multiselect turned off you shouldn't have to call
SelectedIndices.Clear() Selectedndices.Add(..)
as well as:
Items[_prevSelectedIndex].Selected = true;
The latter will accomplish the same result.
I believe you're also adding a continually growing list of event handlers. To remove an event handler you have to store an instance of the delegate then remove that instance;-= new EventHandler(...) isn't going to remove the handler.

Resources