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
}
}
Related
I have an ListView defined in XAML, and it's ItemsSource is set code-behind. ItemsSource is not a property, so I dont want bind it to observable collection.
To update GUI I call ListView.Items.Refresh() method after selected index was changed (I do some work on selection changed and list view items are display the result).
After that two situations may occurs:
if I change selected item of ListView by mouse, selected index is changed right and stay in its place after Refresh() method was called;
if I change selected item by arrows up and down on keyboard, selected index is always jumps to first item.
My question is what may I do to make selected item index of ListView right after selected item was changed by keyboard and items were refreshed in code?
Instead of SelectionChanged event why dont you try MouseLeftButtonDown event and KeyDown event.
This will solve your issue.
Snippet as follow,
private void lst_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
item = lst.SelectedItem;
fnTask();
}
private void lst_KeyDown(object sender, KeyEventArgs e)
{
item = lst.SelectedItem;
fnTask();
}
private void fnTask()
{
lst.Items.Refresh();
lst.SelectedItem = item;
}
I want to remove the selected items from a DataGrid when the user clicks on any other control in the UserControl. The grid has selection mode as "Extended".
I thought of oneapproach
LostFocus event on the DataGrid or the same event on DataGridCell:- But this event is called whenever I select any row in the grid. So I can't remove selected items here.
Use FrameworkElement.PreviewGotKeyboardFocusEvent and handle it at the root which is UserControl in your case like this :
<UserControl ... FrameworkElement.PreviewGotKeyboardFocus="FrameworkPreviewGotKeyboardFocus" />
// Handler :
Important is to check for DataGridCells etc, so we use IsDescendantOf() method to check if some element which lies in our DataGrid is having focus.
Take note of e.Handled and set it's value accordingly.
private void FrameworkPreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
if (sender is FrameworkElement)
{
Debug.WriteLine(((FrameworkElement)e.OriginalSource).ToString());
if (!((FrameworkElement)e.OriginalSource).IsDescendantOf(MyDataGrid))
{
Debug.WriteLine("Datagrid lost focus completely !");
//e.Handled = true;
// Do something now
}
}
}
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());
}
I have an ObservableCollection of "things" in my view model, and a couple filtered subsets of that list in additonal ObservableCollections. I have two DataGrids on the screen, and I have bound them each to one of the subset ObservableCollections.
Both DataGrids have their SelectedItem property bound to a SelectedThing property in the view model.
When I change SelectedThing either programatically or by selecting a row in one of the two grids, it will change as expected. If the item now pointed to by SelectedThing exists in a grid, the grid will update it's selected item.
So here is my problem... if SelectedThing does not exist in the grid's ItemSource, the selection acts like nothing happened and remains in whatever state it was in before SelectedThing was changed. Ideally I would like the selected to Clear if the underlying view model property no longer is set to something in the grid's ItemsSource... anyone have any suggestions?
Ok. Got it working. In case it helps someone else in the future, here's what made it work...
In your code behind, register an event handler for the view model's PropertyChanged event, and then use that to check each grid to see if it contains the item being selected. If not, then clear the selected in that grid. I also modified my SelectedThing property to ignore incoming NULL values to avoid a deadlock (and in my app it will never be NULL after initialization)
_vm is a Property that returns my view model.
_vm.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(_vm_PropertyChanged);
void _vm_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "SelectedThing")
{
CheckSelection(grid1, _vm.SelectedThing);
CheckSelection(grid2, _vm.SelectedThing);
}
}
void CheckSelection(DataGrid grid, object selectedItem)
{
if (grid.ItemsSource != null)
{
bool itemInGrid = false;
foreach (var item in grid.ItemsSource)
{
if (item == selectedItem)
{
itemInGrid = true;
break;
}
}
if (!itemInGrid) // clear selection
{
grid.SelectedItem = null;
// not sure why, but this causes the highlight to clear. Doesn't work otherwise
grid.IsEnabled = false;
grid.IsEnabled = true;
}
}
}
For a ListView how can you make it so you CAN'T deselect the selected index by holding the control button while you select any item?
Thank you very much
Subscribe to the PreviewMouseButtonDown event on the ListView. In that event handler you can catch when the user ctrl-clicks and mark the event has handled. Then it won't be passed on.
As andrea pointed out they can do unselect through shortcut keys as well. Instead I think you should subscribe to the SelectionChangedEvent. You can then loop through the removed items and remark them as selected:
void list_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
foreach (var item in e.RemovedItems)
{
myList.SelectedItems.Add(item);
}
}