WPF Datagrid OnPropertyChanged causes SelectionChanged event - wpf

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());
}

Related

How to use a WPF-Combo-Box with fluent nHibernate so its saves after the user changes the selection?

This is my ComboBox:
<ComboBox x:Name="comboBoxExchange" HorizontalAlignment="Left" Margin="167,162,0,0" VerticalAlignment="Top" Width="222" SelectedItem="{Binding Exchange}"/>
This is the code I use to initialize the ComboBox:
private void InitExchange()
{
comboBoxExchange.ItemsSource = (from p in m_DbSession.Query<Exchange>() orderby p.Name select p);
comboBoxExchange.DisplayMemberPath = "Name";
comboBoxExchange.SelectionChanged += comboBoxExchange_SelectionChanged;
}
So I want to save my data after the user changes the selection with this function:
private void Save()
{
using (var transaction = m_DbSession.BeginTransaction())
{
m_DbSession.SaveOrUpdate(m_DBProduct);
transaction.Commit();
}
}
The problem is that I cant find the event that works with this.
SelectionChanged is fired when the window is loaded without the user doing anything
LostFocus is fired multible times even when the user just "opens" the combobox and closes it without changing anything.
SelectionChanged is fired when the window is loaded without the user doing anything
Yes, but you could return from the event handler immediately the first time using the IsLoaded property:
private void comboBoxExchange_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!IsLoaded)
return;
//your code to be executed when the user actually selects an item...
}
So SelectionChanged is the event to handle here.
Alternatively, you could implement kick-off your logic in the setter of the Exchange source property.

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

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.

Get event trigger

I am using WPF ListBox, binding the ItemsSource to an ObservableCollection.
I subscribed to the SelectionChanged event, which will notify me when the user select/deselect any ListItem.
Now, can I get whether the selection in the ListBox was changed due to user click or Collection change (i.e. items were removed from the Collection which were selected in the ListBox) ??
As you know when you remove some items from the collection, you could set a bool flag as you remove something and then ignore calls to the handler when the flag is true... of course, don't forget to set the flag to false again afterwards:
isProgramAction = true;
Items.Remove(item);
isProgramAction = false;
...
private void SelectionChanged(object sender, RoutedEventArgs e)
{
if (!isProgramAction)
{
// User Action
}
}

WPF: UserControl.IsFocused will not set

I created a WPF UserControl, that handles all GotFocus/LostFocus events of its child controls. I call the OnGotFocus/OnLostFocus of the UserControl, but the IsFocused property of the UserControl will not set:
void MyUserControl_Initialized(object sender, EventArgs e)
{
foreach (UIElement control in (Content as Panel).Children)
{
control.LostFocus += control_LostFocus;
control.GotFocus += control_GotFocus;
}
}
void control_GotFocus(object sender, RoutedEventArgs e)
{
if (!IsFocused)
{
e.Handled = false;
OnGotFocus(e);
}
}
void control_LostFocus(object sender, RoutedEventArgs e)
{
bool hasAnythingTheFocus = false;
foreach (UIElement control in (Content as Panel).Children)
{
if (control.IsFocused)
{
hasAnythingTheFocus = true;
}
}
if (!hasAnythingTheFocus)
{
OnLostFocus(e);
}
}
How can I set it?
Instead of the IsFocused you can use IsKeyboardFocusWithin
use the event UIElement.IsKeyboardFocusWithinChanged and it should worked perfectly.
The GotFocus method will be called when the relevant control receives logical focus... from the UIElement.GotFocus Event page on MSDN:
Logical focus differs from keyboard focus if focus is deliberately forced by using a method call but the previous keyboard focus exists in a different scope. In this scenario, keyboard focus remains where it is and the element where a Focus method is called still gets logical focus.
A more precise interpretation of this event is that it is raised when the value of the IsFocused property of an element in the route is changed from false to true.
Because this event uses bubbling routing, the element that receives focus might be a child element instead of the element where the event handler is actually attached. Check the Source in the event data to determine the actual element that gained focus.
it will get focus when the user clicks on the relevant control in the UI and/or when you call control.Focus() in your code. The IsFocused is readonly and cannot be set.

MouseDown in WinForm ListBox Kills SelectedIndexChanged

I'm writing some code to detect toggling of selections in a WindForms ListBox with MultiSelect turned on. Since SelectedIndexChanged only lets me see what is selected after the click, I was looking for a way to detect what was selected before the ListBox was clicked. I implemented the MouseDown event and I can get exactly what I want, but an unfortunate side effect is that I have killed the SelectedIndexChanged event. It will not fire.
Is this known behavior? Are there any thoughts about getting to the selection list before the click?
Thanks.
Edited to include code snippets as requested.
Designer generated events:
this.lbPhysicianClinic.SelectedIndexChanged += new System.EventHandler( this.lbPhysicianClinic_SelectedIndexChanged );
this.lbPhysicianClinic.MouseDown += new System.Windows.Forms.MouseEventHandler( this.lbPhysicianClinic_MouseDown );
Code snippet showing MouseDown event:
private void lbPhysicianClinic_MouseDown( object sender, MouseEventArgs e )
{
List<Clinic_List_ByPhysicianResult> Selected = this.PhysicianGetSelectedClinics( this.lbPhysicianClinic.SelectedIndices );
}
Code snippet showing SelectedIndexChanged event:
private void lbPhysicianClinic_SelectedIndexChanged( object sender, EventArgs e )
{
try
{
if ( this.FormInitComplete && this.RefreshUIComplete )
{
List<Clinic_List_ByPhysicianResult> Selected = this.PhysicianGetSelectedClinics( this.lbPhysicianClinic.SelectedIndices );
Clinic_List_ByPhysicianResult DroppedClinic = new Clinic_List_ByPhysicianResult();
I set a breakpoint in each event and if the MouseDown event is there, the SelectedIndexChanged event never fires. It only fires when the MouseDown event is gone.
Hopefully this clarifies things.
The ListBox changes its selection before it raises the MouseDown or SelectedIndexChanged events.
What you need to do is capture the underlying Win32 message and raise an event yourself. You can subclass ListBox to do this.
class MyListBox : ListBox
{
private const int WM_LBUTTONDOWN = 0x201;
public event EventHandler PreSelect;
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_LBUTTONDOWN:
OnPreSelect();
break;
}
base.WndProc(ref m);
}
protected void OnPreSelect()
{
if(null!=PreSelect)
PreSelect(this, new EventArgs());
}
}
You can use the MyListBox class, and add a handler for the PreSelect event like so:
this.lbPhysicianClinic.PreSelect +=
new EventHandler(this.lbPhysicianClinic_PreSelect);
Inside the event handler you can access the selected indices before the listbox has changed them.

Resources