Quick question about the Item realization event in WP8.
Here is my event registration which I call in the ctor for the View.
EpisodeList.ItemRealized += EpisodeList_ItemRealized;
Also here is my EventHandler
private void EpisodeList_ItemRealized(object sender, ItemRealizationEventArgs e)
{
if (!vm.Loading && EpisodeList.ItemsSource != null && EpisodeList.ItemsSource.Count >= _offset)
{
if (e.ItemKind == LongListSelectorItemKind.Item)
{
if ((e.Container.Content as Medium).Equals(EpisodeList.ItemsSource[EpisodeList.ItemsSource.Count - _offset]))
{
//Ask Messenger to notify the ViewModel To Load More Items
Messenger.Default.Send<MainPageLoadMoreEpisodesMessage>(new MainPageLoadMoreEpisodesMessage());
}
}
}
}
My problem is that the event handler fires a few times but then it never fires again, I have no clue why I event tried to register the event handler again after loading was complete, I am unable to get the event handler to fire again.
LongListSelctor Item Realized & Item Unrealized event fires when longlistselector scroll down or top, it take 20 element to realize at once, to fire it again it need more than 20 item in list. It don't need to register twice.
Exactly where I must write this code?
button1.MouseHover += Common_MouseHover;
The problem is I want to declare one event handler and point each button at it. This is the common handler:
private void Common_MouseHover(object sender, EventArgs e)
{
Button btn = sender as Button;
if (btn != null)
btn.Image = pic
}
But I dont know where i must write:
button1.MouseHover += Common_MouseHover;
utton2.MouseHover += Common_MouseHover;
.. etc
In designer? Where exactly?
Either in the designer or the Constructor of your Form or if you are creating dynamic Buttons at the time of creation.
public Form1()
{
InitializeComponent();
button1.MouseHover += new EventHandler(Common_MouseHover);
button2.MouseHover += new EventHandler(Common_MouseHover);
}
If in the Property Editor.
Technically, it depends when you want to assign it. For example, you might not want the event to be handled by that method until certain conditions are met: then you assign the event handler once the conditions are true.
Bear in mind that assigning event handlers can cause memory leaks if you aren't careful. For example, you might have a timer that continually assigns the same event handler to the event. You need to check if the event already has the event handler, or if it's null, or whatever you need to prevent duplication. You might also want to remove event handlers dynamically using the -= operator.
For the example given, the form's constructor seems right, and is the most common place for assigning event handlers manually.
Call following function in your form Constructor after InitializeComponent(); -
private void init()
{
foreach (Control ctrl in this.Controls)
{
if (ctrl is Button)
{
(ctrl as Button).MouseHover += new EventHandler(Common_MouseHover);
}
}
}
Call it like this -
// Form Constructor
public Form3()
{
InitializeComponent();
Init();
}
I need to define 3 events in a Custom Control as OnChange, OnSave, and OnDelete.
I have a GridView and work with its rows.
Can you help me and show me this code?
Good article which can help you to achieve your task:
Custom Controls in Visual C# .NET
Step 1: Create the event handler in your control as below.
public event SubmitClickedHandler SubmitClicked;
// Add a protected method called OnSubmitClicked().
// You may use this in child classes instead of adding
// event handlers.
protected virtual void OnSubmitClicked()
{
// If an event has no subscribers registered, it will
// evaluate to null. The test checks that the value is not
// null, ensuring that there are subscribers before
// calling the event itself.
if (SubmitClicked != null)
{
SubmitClicked(); // Notify Subscribers
}
}
// Handler for Submit Button. Do some validation before
// calling the event.
private void btnSubmit_Click(object sender, System.EventArgs e)
{
OnSubmitClicked();
}
Step 2 : Utilize the event in the page where you register your control. The following code is going to be part of your page where your control is registered. If you register it, it will be triggered by the submit button of the control.
// Handle the SubmitClicked Event
private void SubmitClicked()
{
MessageBox.Show(String.Format("Hello, {0}!",
submitButtonControl.UserName));
}
Heyo,
I have a standard WinForms MonthCalendar in my application with a handler hooked up to the DateChanged event. Whenever I change the date by day, clicking on a certain date in the little calendar, the event fires once. However, whenever I change the date by month, clicking on the < and > in the control, the event fires twice. I want the event to fire once in all situations.
Any ideas?
EDIT: I debugged and found out that the SelectedItem or Range is the same on the first and second handler call. So I need a way to differentiate between the first and second call while still allowing for proper handling when the event only fires once.
The handler code was requested, here it is, but it has nothing to do with the event firing multiple times:
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
Somewhat of a hack, but compare the SelectionRange string value with the last DataChanged event. Just run your code if it's different:
private string _LastRange = string.Empty;
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
if (monthCalendar1.SelectionRange.ToString() != _LastRange) {
_LastRange = monthCalendar1.SelectionRange.ToString();
List<TimestampInfo> displayTimestamps = databaseManger.QueryForTimestamps(DayPicker.SelectionRange);
if (displayTimestamps == null) return;
TimestampsListBox.Items.Clear();
TimestampsListBox.Items.AddRange(displayTimestamps.ToArray());
}
}
I couldn't reproduce this until I hooked up the event handler twice.
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
monthCalendar1.DateChanged += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateChanged);
Is you code munging around with the event handlers?
Try this:
private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
Calendar1.SelectedDate = Calendar1.VisibleDate;
// any additional code optional
}
My scenario, simplified: I have a ListView containing rows of Employees, and in each Employee row, there are buttons "Increase" and "Decrease" adjusting his salary.
Pretend that in my program, double-clicking an Employee row means "fire this person".
The problem is that while I'm clicking "Increase" rapidly, this triggers a double click event on the ListViewItem. Naturally, I don't want to fire people when I'm just increasing their salary.
According to how all other events work, I expect to be able to solve this by setting Handled=true on the event. This, however, doesn't work. It appears to me that WPF generates two separate, completely unlinked, double click events.
The following is a minimal example to reproduce my issue. The visible components:
<ListView>
<ListViewItem MouseDoubleClick="ListViewItem_MouseDoubleClick">
<Button MouseDoubleClick="Button_MouseDoubleClick"/>
</ListViewItem>
</ListView>
And the handler code:
private void Button_MouseDoubleClick(object s, MouseButtonEventArgs e) {
if (!e.Handled) MessageBox.Show("Button got unhandled doubleclick.");
e.Handled = true;
}
private void ListViewItem_MouseDoubleClick(object s, MouseButtonEventArgs e) {
if (!e.Handled) MessageBox.Show("ListViewItem got unhandled doubleclick.");
e.Handled = true;
}
After firing up this program and double-clicking the listed button, both messageboxes show up in sequence. (Also, the button is stuck in the down position after this.)
As a "fix" I can, on the ListViewItem handler, inspect the visual tree attached to the event and check that "there is a button there somewhere" and thus discard the event, but this is a last resort. I want to at least understand the issue before coding such a kludge.
Does anyone know why WPF does this, and an elegant idiomatic way to avoid the problem?
I think you'll find that the MouseDoubleClick event is an abstraction on top of the MouseDown event. That is, if two MouseDown events occur in quick enough succession, the MouseDoubleClick event will also be raised. Both the Button and ListViewItem appear to have this logic, so that explains why you're seeing two distinct MouseDoubleClick events.
As per MSDN:
Although this routed event seems to
follow a bubbling route through an
element tree, it actually is a direct
routed event that is raised along the
element tree by each UIElement. If you
set the Handled property to true in a
MouseDoubleClick event handler,
subsequent MouseDoubleClick events
along the route will occur with
Handled set to false.
You could try handling MouseDown on the Button and setting that to handled so that it doesn't propagate to the ListViewItem.
Wish I could verify this myself but I'm .NET-less at the moment.
The MSDN documentation for the MouseDoubleClick does give a suggestion on how to keep the MouseDoubleClick event from bubbling up:
Control authors who want to handle
mouse double clicks should use the
MouseLeftButtonDown event when
ClickCount is equal to two. This will
cause the state of Handled to
propagate appropriately in the case
where another element in the element
tree handles the event.
So you could hanlde the MouseLeftButtonDown event and set hanged to true if ClickCount is two. But this fails on Buttons because they already handle the MouseLeftButtonDown and don't raise that event.
But there is still the PreviewMouseLeftButtonDown event. Use that on your buttons to set handled to true when ClickCount equals two as below:
private void Button_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) {
if (e.ClickCount == 2)
e.Handled = true;
}
Since there have been no definite answers to this question, this is the workaround I ended up using:
protected override void ListViewItem_MouseDoubleClick(MouseButtonEventArgs e) {
var originalSource = e.OriginalSource as System.Windows.Media.Visual;
if (originalSource.IsDescendantOf(this)) {
// Test for IsDescendantOf because other event handlers can have changed
// the visual tree such that the actually clicked original source
// component is no longer in the tree.
// You may want to handle the "not" case differently, but for my
// application's UI, this makes sense.
for (System.Windows.DependencyObject depObj = originalSource;
depObj != this;
depObj = System.Windows.Media.VisualTreeHelper.GetParent(depObj))
{
if (depObj is System.Windows.Controls.Primitives.ButtonBase) return;
}
}
MessageBox.Show("ListViewItem doubleclicked.");
}
Class names are here unnecessarily typed with full namespaces for documentation purposes.
Well it may not be elegant or idiomatic, but you might like it better than your current workaround:
int handledTimestamp = 0;
private void ListViewItem_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.Timestamp != handledTimestamp)
{
System.Diagnostics.Debug.WriteLine("ListView at " + e.Timestamp);
handledTimestamp = e.Timestamp;
}
e.Handled = true;
}
private void Button_MouseDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.Timestamp != handledTimestamp)
{
System.Diagnostics.Debug.WriteLine("Button at " + e.Timestamp);
handledTimestamp = e.Timestamp;
}
e.Handled = true;
}
The weird thing is this doesn't work if you don't set e.Handled = true. If you don't set e.Handled and put a breakpoint or a Sleep into the button's handler, you will see the delay in the ListView's handler. (Even without an explicit delay there will still be some small delay, enough to break it.) But once you set e.Handled it doesn't matter how long of a delay there is, they will have the same timestamp. I'm not sure why this is, and I'm not sure if this is documented behavior that you can rely on.
Control.MouseDoubleClick is not a bubble event but a direct event.
Since checking this question with Snoop, which is a tool for browsing visual trees and routed events, I see that Control.MouseDoubleClick events of 'ListView' and 'ListBoxItem' are fired at one time. You could check with this Snoop tool.
First, to find an answer, it is needed to check that both event arguments of the MouseDoublClick are same objects. You would expect they are same objects. If it is true, it is very strange as your question, but they are not same instances. We can check it with following codes.
RoutedEventArgs _eventArg;
private void Button_MouseDoubleClick(object s, RoutedEventArgs e)
{
if (!e.Handled) Debug.WriteLine("Button got unhandled doubleclick.");
//e.Handled = true;
_eventArg = e;
}
private void ListViewItem_MouseDoubleClick(object s, RoutedEventArgs e)
{
if (!e.Handled) Debug.WriteLine("ListViewItem got unhandled doubleclick.");
e.Handled = true;
if (_eventArg != null)
{
var result = _eventArg.Equals(e);
Debug.WriteLine(result);
}
}
It means that the event argument of the MouseDoublClick is created newly at somewhere, but I don't understand deeply why it is.
To be clearer, let's check for the event argument of the BottonBase.Click. It will be return the true about checking same instances.
<ListView>
<ListViewItem ButtonBase.Click="ListViewItem_MouseDoubleClick">
<Button Click="Button_MouseDoubleClick" Content="click"/>
</ListViewItem>
</ListView>
If you only focus on the execution as you mentioned there'll be lots of solutions. As above, I think that using the flag(_eventArg) is also good choice.
I've just had this same problem. There is a simple but non-obvious solution.
Here is how double click is raised by Control ....
private static void HandleDoubleClick(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
Control control = (Control)sender;
MouseButtonEventArgs mouseButtonEventArgs = new MouseButtonEventArgs(e.MouseDevice, e.Timestamp, e.ChangedButton, e.StylusDevice);
if (e.RoutedEvent == UIElement.PreviewMouseLeftButtonDownEvent || e.RoutedEvent == UIElement.PreviewMouseRightButtonDownEvent)
{
mouseButtonEventArgs.RoutedEvent = Control.PreviewMouseDoubleClickEvent;
mouseButtonEventArgs.Source = e.OriginalSource;
mouseButtonEventArgs.OverrideSource(e.Source);
control.OnPreviewMouseDoubleClick(mouseButtonEventArgs);
}
else
{
mouseButtonEventArgs.RoutedEvent = Control.MouseDoubleClickEvent;
mouseButtonEventArgs.Source = e.OriginalSource;
mouseButtonEventArgs.OverrideSource(e.Source);
control.OnMouseDoubleClick(mouseButtonEventArgs);
}
if (mouseButtonEventArgs.Handled)
{
e.Handled = true;
}
}
}
So if you handle PreviewMouseDoubleClick setting e.Handled = true on the child control MouseDoubleClick won't fire on the parent control.
You cannot easily change the way double clicking events get fired because they are dependent on user settings and that delay is customized in control panel.
You should checkout RepeatButton that allows you to press's button and while it is pressed it generates multiple click events in regular sequence.
In case if you want to customize event bubbling then you should search for Preview events that allows you to block propogation of events. What are WPF Preview Events?