How define priority for events in c#? - c#

I'm developing a Windows Phone app using Map Control. Map control has CenterChanged and ZoomLevelChanged events.
When I change the zoom value for map, both events are raised (because the center changes as well).
But I want using only ZoomLevelChanged event, when I change zoom value.
How do I set priority for events if multiple events are available or how switch off CenterChanged event when ZoomLevelChanged is raised?
Any Solution/Demo/Link would be very much helpful for me.

You cannot define the priority for events, and you can't depend on the order of events.
I'm not a Windows Phone developer, but ask yourself: what if there were a zoom change at the same time as a large center change? You would need to handle both events, right? I would make that work, then make it work for the case of a zoom change with a small center change.

Events that happen "simultaneously" are added to the Dispatcher queue. If a single event sets "zoom" and then "center", the queue will contain the zoom event followed by the center event.
I'm not completely sure what you mean by defining priority. If you mean changing the order the event handlers are called, the only way to do this would be to modify the code that sets the two properties so that they are set in a different order. Once the event handlers are added to the queue, you can't reorder them.
If you want to handle only the first "simultaneous" event though, this should be possible by disabling the other handler until the end of the queue. Something like this:
// in ZoomLevelChanged handler:
_zooming = true;
mapControl.Dispatcher.BeginInvoke(new Action(() => _zooming = false));
// in CenterChanged handler:
if (_zooming) return;
// rest of implementation
BeginInvoke adds the action to the end of the queue, so the _zooming flag will only be reset once the immediate CenterChanged handler has been called and skipped, allowing subsequent CenterChanged events to be handled normally.

Related

WPF - Knowing which control will end up with focus

I've been playing around with events in WPF and have so far I've got good mileage out of 'Source' and 'OriginalSource' properties of the event args as well as using the sending control and FocusManager. Here's the thing, when a chain of events starts firing, is there any way to know what control will be ending up with focus at the end barring any intervening logic throughout the chain of events?
I'm afraid that the only reliable way of doing this is actually letting focus change and then handling it in some PreviewGotKeyboardFocus handler at top view level.
You can then know which control was going to get the focus, and cancel the change with e.Handled = true.
PD. There's a function in all UIElements called PredictFocus, but it only works with positional traverse changes, not with tab-based changes (or custom focusing).

How do I perform sequential BringIntoView calls in WPF?

We have a TreeView in our application with the following requirements:
When an item is added:
The newly-added item is scrolled into view
The parent of the newly added item is also scrolled into view.
If they are too far away to both be seen at the same time, the item takes precedence.
This seems easy, simply scroll the parent into view first, then scroll the child.
The problem is when you call it like this:
parent.BringIntoView();
child.BringIntoView();
...only the second one seems to have any effect. The first one is basically ignored.
I then tried wrapping the second call in a BeginInvoke() call like this:
parent.BringIntoView();
Dispatcher.BeginInvoke((Action)(() => {
child.BringIntoView();
}));
Which does work, but now you can visibly see the TreeView scroll twice; once for the parent, then a moment later, for the child, which just looks bad.
So how can I call BringIntoView back-to-back but without the double-refresh issue of using the dispatcher?
Try using the Loaded event instead of the dispatcher. According to this article, it's a perfect fit for situations like this:
... we initially implemented the Loaded event so that
it would fire just after the window was rendered, but before any input
was processed. We figured that if it was ready enough for input, it
was ready enough for load-time initialization. But then we started to
trigger animations off of the Loaded event, and saw the problem; for a
split second you’d see the content render without the animation, then
you’d see the animation start. You might not always notice it, but it
was especially noticeable when you run the app remotely.
So we moved
Loaded so that it now fires after layout and data binding have had a
chance to run, but just before the first render. (And note that if
you do anything in your Loaded event handler that invalidates layout,
it might be necessary to re-run it before rendering.)
In other words, on Loaded you have the most up to date information about the physical layout of the element, but it hasn't actually rendered yet, so you should be safe from any "screen flicker" issues.
EDIT: To answer your question in the comments, you can wire up events "local" to the current method using a closure, like this:
EventHandler handler = null;
handler = (sender, e) => {
this.LayoutUpdated -= handler; // only run once
child.BringIntoView();
};
this.LayoutUpdated += handler;
By defining the handler inside the method, you are able to access the method's local variables (child) from within. Very similar to the Dispatcher call.
I'm not sure if relying on LayoutUpdated is a good idea, actually. It happens quite often so it may end up firing sooner than you need. It happens twice for individual Width and Height settings, for example. Another one to look into is ScrollViewer.ScrollChanged. Or you could avoid BringIntoView altogether and try manually examining the element sizes to calculate where to scroll to.

Create Event in WPF

I want to rise an event to zoom in and zoom out the image once the gesture is recognized that it is valid (gesture recognized by Kinect). my image is shown in different user control loaded in a frame present in main window.
<Frame Name="currentFrame" NavigationUIVisibility="Hidden"></Frame>
and frame source is set like this.
currentFrame.Source = new Uri("Images.xaml", UriKind.RelativeOrAbsolute);
How can i create the custom event? and which one is the best ? tunnel or bubble?
I think in your case it's better to use tunel event, as what you need is immediate feedback from the user interaction and execute a single action on that: zooming. So there is no sence of notifying other controls between your usecontrol canvas (if any) and actual handling code.
For concrete implementation of the event, can have a look on:
Routed Events

TouchDown event is delayed

My application uses the UiElement.TouchDown event in various places, one of them is to let the user stop a spinning wheel. In this situation, one can easily notice a short delay of about 1/3s between the actual touching of the screen and the TouchDown event.
I have set Stylus.IsPressAndHoldEnabled to false.
In order to troubleshoot this problem, I've written a test tool that reports WPF events and native window messages, and I noticed that as soon as I touched the screen, messages with id 0x02CC, 0x011B and 0x011A are generated, about 100 to 300 ms before the TouchDown event. This leads me to believe that the drivers report the touch quickly, and the delay is introduced somewhere later in the WPF translations.
Is there a way to make the touch interaction more responsive? Please ask for any information you need!
Unless Flicks are needed set both in XAML or by manually setting in code behind: (I assume you meant to say IsPressAndHoldEnabled not IsTouchAndHoldEnabled)
Stylus.IsPressAndHoldEnabled="False" Stylus.IsFlicksEnabled="False"
Furthermore consider handling the TouchDown Event and also capturing it to the relevant UIElement (don't forget to release it in TouchUp).
uielement.CaptureTouch(e.TouchDevice);
e.Handled = true;

What is the last event to fire when loading a new WPF/C# window?

I am trying to load a preferences window for my application and I would like the apply button to initially be disabled, then when a preference is updated, the apply button gets enabled again. I have some controls data bound to a preferences object and what happens is that after the window loads, the combobox events get triggered. Is there any event that is guaranteed to happen dead last after everything is stable?
Here is what my code looks like (the apply button is always enabled after the window loads):
private void Window_Loaded(object sender, RoutedEventArgs e)
{
_preferencesData = new PreferencesDataContext();
LayoutRoot.DataContext = _preferencesData;
ButtonApply.IsEnabled = false;
}
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
ButtonApply.IsEnabled = true;
}
Is it also interesting to note that this only happens with textboxes and comboboxes, not checkboxes or radiobuttons.
Best solution for simple need
Joseph's answer is the best solution by far for your simple need: Just use data binding and let the data model handle it.
Answer to question as posed
There are more complex scenarios when you really do need control after absolutely everything has finished loading and all events have fired. There is no single event that occurs "dead last", but it is easy to effectively roll your own using the Dispatcher queue.
This is how to do it:
Dispatcher.BeginInvoke(DispatcherPriority.ContextIdle, new Action(() =>
{
var x = ComputeSomething(1, 2, 3);
DoSomething(x, "Test");
}));
Everything inside the { } will be executed when WPF finishes everything at a higher priority than ContextIdle, which includes all event handlers, loaded events, input events, rendering, etc.
Sequence of events when a Window is created and shown
As requested, here is the sequence of major events in WPF when a window is created and shown:
Constructors and getters/setters are called as objects are created, including PropertyChangedCallback, ValidationCallback, etc on the objects being updated and any objects that inherit from them
As each element gets added to a visual or logical tree its Intialized event is fired, which causes Styles and Triggers to be found applied in addition to any element-specific initialization you may define [note: Initialized event not fired for leaves in a logical tree if there is no PresentationSource (eg Window) at its root]
The window and all non-collapsed Visuals on it are Measured, which causes an ApplyTemplate at each Control, which causes additional object tree construction including more constructors and getters/setters
The window and all non-collapsed Visuals on it are Arranged
The window and its descendants (both logical and visual) receive a Loaded event
Any data bindings that failed when they were first set are retried
The window and its descendants are given an opportunity to render their content visually
Steps 1-2 are done when the Window is created, whether or not it is shown. The other steps generally don't happen until a Window is shown, but they can happen earlier if triggered manually.
The Window.ContentRendered event fulfilled my requirements.
I just did kind of the same thing behaviorly in a systray WPF app.
However, I didn't do it using event handling. I simply bound the Enabled property of my button to a property in my ViewModel, and had the property updated whenever I needed the behavior.
You can use ManagedSpy to figure this out on your own.
http://msdn.microsoft.com/en-us/magazine/cc163617.aspx
Setting the DataContext will likely fire the SelectionChanged event, and you can't rely on when exactly it's fired. Some logic checking on what exactly is selected would be more reliable:
private void ComboBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
if (myComboBox.SelectedItem == null)
{
buttonApply.IsEnabled = false;
}
else
{
buttonApply.IsEnabled = true;
}
}
The reason it's happening afterwards with your code as-is is because the event gets queued on the thread for the UI, so it's up to Windows if it will execute the next line of code in Load, or to handle the other events on the queue.
Not to throw a whole lot of stuff at you that you may or may not be familiar with, but if this is a relatively new codebase, you may want to consider using the MVVM pattern and use Commands instead of the archaic (emphasis mine) eventing model.
Order of Events in Windows Forms
Control.HandleCreated
Control.BindingContextChanged
Form.Load
Control.VisibleChanged
Form.Activated
Form.Shown

Categories

Resources