As per the title, is there any way to programatically change the selected item in a ComboBox and have it raise an event?
I am setting the selected item using myComboBox.SetSelection(index), but this doesn't raise the wx.EVT_COMBOBOX event.
I use C++ version of wxWidget. Look up documentation on these two functions:
void wxPostEvent(wxEvtHandler *dest, wxEvent& event)
void AddPendingEvent(wxEvent& event)
Related
One of those 'Why is this so hard?" questions.
I have a ListBox (containing details of share portfolios). The listbox item uses a grid to display attributes of the portfolio. Source is a list of portfolios in the View Model.
ListBox is multiselect - when selection changes, a list of the constituents of the selected portfolios is re-populated.
What I want to do is put a button (or menu or whatever) on the listboxitem to display a list of possible actions (Trade, Unitise, Delete etc).
When an action is selected I need to execute the action against the appropriate portfolio. Ideally I want the actions to be available for both selected and unselected items.
I can handle the event, but how do I detect which item (portfolio) the user selected? I've looked at GotFocus() but it doesn't seem to fire.
In other words if a control in a Listboxitem, fires an event, how does the event 'know' which ListBoxItem raised it?
For me, the solution here, seen as you mentioned MVVM, would be to have the ListBox populated by a collection of ViewModels, e.g., something like ObservableCollection<PortfolioViewModel>.
It would then just be a case of binding the Command property of the Button to an ICommand on the ViewModel that executes whatever work you need doing.
I can handle the event, but how do I detect which item (portfolio) the user selected? I've looked at GotFocus() but it doesn't seem to fire.
You could cast the DataContext of the clicked Button to the corresponding object in te ListBox, e.g.:
private void DeleteButton_Clicked(object sender, RoutedEventArgs e)
{
Button deleteButton = sender as Button;
var portfolio = deleteButton.DataContext as Portfolio; //or whatever your type is called
//access any members of the portfolio...
}
I have a WPF DataGrid which I'm trying to auto-scroll using this code:
private void mydatagrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
mydatagrid.ScrollIntoView(mydatagrid.CurrentItem);
}
The problem I'm having is that this event handler is not called every time the SelectedIndex of the DataGrid changes. Yes, it does get called when I click on the grid or add or delete an item, but it does NOT get called upon some other actions, such as moving the currently selected item up or down in the underlying collection, which is set via:
mydatagrid.ItemsSource = Seq;
(where Seq is an object of a type derived from ObservableCollection<>).
In my troubleshooting attempts I bound the text of a TextBlock to the SelectedIndex property of mydatagrid. The index number updates perfectly, regardless of what action I perform on the datagrid and/or underlying data source.
So my question is: how can I create an event handler in C# code that gets called upon ANY and ALL changes to the value of SelectedIndex, just like my little textblock binding example does?
I've tried finding a propertyChanged event for the DataGrid, but to no avail. I've tried tapping into all of the events of the DataGrid that seemed remotely related, but to no avail. I've also tried using the CollectionChanged event of the underlying collection, but this doesn't seem to be nicely synchronized with the datagrid (at least at the moment that the event occurs).
Thanks
I have a ListBox that uses DataTemplateSelector to dynamically decide what
template to use based on the type of the item in the list. I now want to hook
the events that could be fired by controls within the DataTemplate. For example,
if one of the templates has a checkbox in it, I want the application using the
control to be notified when the checkbox is checked. If a different template has
a button within it, I want to be notified when the button is clicked.
Also, since its a ListBox, many of the items could have the same template. So
I will need some kind of RoutedEventArgs so I can walk up from OriginalSource to get
some context information to handle the event.
My solution was to use MouseLeftButtonUp. This works fine for TextBlocks, but it looks like CheckBox and Button controls set handled to true, so the event doesnt bubble up. How can I address these
events so I can assign handlers to them in my calling application?
(Also, Silverlight doesn't actually support DataTemplateSelector, so i followed this example to implement it)
If you are defining the templates in the Xaml for the user control where your event handlers are placed then you should simply be able to assign the event handlers in the Xaml.
However in the specific scenario you outline you can also listen for the MouseLeftButtonUp event via the AddHandler method:-
myListBox.AddHandler(UIElement.MouseLeftButtonUpEvent, myListBox_MouseLeftButtonUp, true);
...
private void myListBox_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
//e.OriginalSource available for your inspection
}
Note by using AddHandler and passing true in the third parameter you will get the event regardless of whether it has been handled.
I am building an issue tracking system that uses Silverlight. I use DataGrids to display the issue lists, set the selected index to -1 so that no row appears selected and then use the selection change event to popup an issue details window for the particular selected issue.
When I try to refresh the DataGrid by rebinding it to its ItemsSource, I disable the SelectionChanged event, rebind the DataGrid to its ItemsSource, set the SelectedIndex to -1 and then enable the SelectionChanged event again. However, no matter how late I leave the re-enabling of the SelectionChanged event (even until after the DataGrid_Loaded event), a SelectionChanged event is fired and the issue details window pops up.
Is there a better way to refresh the data in a DataGrid that won't cause the SelectedIndex to change? If not, is there a way of telling which events are caused by a programmatic index change and not a human interaction?
(Also up for discussion, is this the best control for the job? I need to display multiple fields per row, such as the issue title, assigned user, requested by user, status, etc.)
Thanks in advance.
I have had a similar issue in the past with the comctl32 ListView control's selection events: Programmatic selection cause selection change events to be raised.
My workaround for this issue is to have a per-grid/list counter variable that lets the event handler know if it should care about the selection event or not. The code would go something like:
int issueList_ProgrammaticEventCount_Selection = 0;
void refreshIssueList()
{
++issueList_ProgrammaticEventCount_Selection;
issueList.ItemsSource = ...;
}
void issueList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (issueList_ProgrammaticEventCount_Selection > 0)
{
--issueList_ProgrammaticEventCount_Selection;
return;
}
showIssueDetails();
}
I want to get notified when an item in a ListBox gets clicked by the mouse, whether it is already selected or not.
I searched and found this: (http://kevin-berridge.blogspot.com/2008/06/wpf-listboxitem-double-click.html see the comments)
private void AddDoubleClickEventStyle(ListBox listBox, MouseButtonEventHandler mouseButtonEventHandler)
{
if (listBox.ItemContainerStyle == null)
listBox.ItemContainerStyle = new Style(typeof(ListBoxItem));
listBox.ItemContainerStyle.Setters.Add(new EventSetter()
{
Event = MouseDoubleClickEvent,
Handler = mouseButtonEventHandler
});
}
//Usage:
AddDoubleClickEventStyle(listView1, new MouseButtonEventHandler(listView1_MouseDoubleClick));
This works, but it does it for a DoubleClick. I can't get it working for a single click though. I tried MouseLeftButtonDownEvent - as there doesn't seem to be a MouseClick event, but it's not being called.
A bit more general side question: How can I see what events do exist and which handlers correspond to them and when they actually do something? For example, what tells me that for a MouseDoubleClickEvent I need a MouseButtonEventHandler? Maybe for a MouseLeftButtonDownEvent I need some other handler and that's why it's not working?
I also tried subclassing ListBoxItem and override OnMouseLeftButtonDown - but it doesn't get called either.
Marc
I believe that your MouseLeftButtonDown handler is not called because the ListBox uses this event internally to fire its SelectionChanged event (with the thought being that in the vast majority of cases, SelectionChanged is all you need). That said, you have a couple of options.
First, you could subscribe to the PreviewLeftButtonDown event instead. Most routed events have a routing strategy of Bubbling, which means that the control that generated the event gets it first, and if not handled, the event works its way up the visual tree giving each control a chance at handling the event. The Preview events, on the other hand, are Tunneling. This means that they start at the root of the visual tree (generally Window), and work their way down to the control that generated the event. Since your code would get the chance to handle the event prior to the ListBoxItem, this will get fired (and not be handled) so your event handler will be called. You can implement this option by replacing MouseDoubleClickEvent in your sample with PreviewMouseLeftButtonDown.
The other option is to register a class handler that will be notified whenever a ListBoxItem fires the MouseLeftButtonDown event. That is done like this:
EventManager.RegisterClassHandler(typeof(ListBoxItem),
ListBoxItem.MouseLeftButtonDownEvent,
new RoutedEventHandler(this.MouseLeftButtonDownClassHandler));
private void OnMouseLeftButtonDown(object sender, RoutedEventArgs e)
{
}
Class Handlers are called before any other event handlers, but they're called for all controls of the specified type in your entire application. So if you have two ListBoxes, then whenever any ListBoxItem is clicked in either of them, this event handler will be called.
As for your second question, the best way to know what type of event handler you need for a given event, and to see the list of events available to a given control, is to use the MSDN documentation. For example, the list of all events handled by ListBoxItem is at http://msdn.microsoft.com/en-us/library/system.windows.controls.listboxitem_events.aspx. If you click on the link for an event, it includes the type of the event handler for that event.
There is also another way - to handle PreviewMouseDown event and check if it was triggered by the list item:
In XAML:
<ListBox PreviewMouseDown="PlaceholdersListBox_OnPreviewMouseDown"/>
In codebehind:
private void PlaceholdersListBox_OnPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var item = ItemsControl.ContainerFromElement(sender as ListBox, e.OriginalSource as DependencyObject) as ListBoxItem;
if (item != null)
{
// ListBox item clicked - do some cool things here
}
}
Was inspired by this answer, but it uses listbox by name, I propose to use sender argument to avoid unnecessary dependencies.
I think the first option in Andy's answer, of using PreviewMouseLeftButtonDown, is the way to go about this. In XAML it would look like this:
<ListBox Name="testListBox">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<EventSetter
Event="PreviewMouseLeftButtonDown"
Handler="ListBox_MouseLeftButtonDown" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
There is another way to get MouseDown event in ListBox. You can add event handler for events that are marked as handled by using handledEventsToo signature of AddHandler method:
myListBox.AddHandler(UIElement.MouseDownEvent,
new MouseButtonEventHandler(ListBox_MouseDown), true);
Third parameter above is handledEventsToo which ensures that this handler will be invoked no matter if it is already marked as Handled (which ListBoxItem does in ListBox).
See Marking Routed Events as Handled, and Class Handling for explanation.
See How to Attach to MouseDown Event on ListBox for example.
You can use Event="MouseLeftButtonUp"
Unlike "PreviewLeftButtonDown" it will get the ListBoxItem handled too.
You can use the SelectionChangedEventArgs argument of the SelectionChanged event to find what item is add or removed through AddedItems and RemovedItems, usually only have the latest clicked on, or if not, then look at the last item which is the count-1.