Is there a way to watch WPF Routed Events? - wpf

I was wondering if there's a way to watch all RoutedEvents that are raised in a WPF application. A way to write some info about the events fired to the console would be prefect to see what's going on.

I've found another way:
I've added this to the loaded handler of my UserControl.
var events = EventManager.GetRoutedEvents();
foreach (var routedEvent in events)
{
EventManager.RegisterClassHandler(typeof(myUserControl),
routedEvent,
new RoutedEventHandler(handler));
}
and this is the handler method:
internal static void handler(object sender, RoutedEventArgs e)
{
if (e.RoutedEvent.ToString() != "CommandManager.PreviewCanExecute" &&
e.RoutedEvent.ToString() != "CommandManager.CanExecute")
Console.WriteLine(e.OriginalSource+"=>"+e.RoutedEvent);
}
The CanExecute events are a bit too much in my case. If you would like to see these too, just remove the if statement.

Yes, but it requires some reflection. You're better off using a tool like Snoop that already does the hard lifting for you.
In the tab Events you can see list of events, and the element that handled it.

Related

How to know when binding is completed?

When I set the .ItemSource() property on a DataGrid to a Collection, the call returns fast, but the actual binding happens afterwards. Since I want to display a waiting cursor, I need to detect when the actual binding has finished. Is there any event for this?
Anything based on ItemsControl uses an ItemContainerGenerator to generate its items in the background. You can access the ItemContainerGenerator property of the DataGrid and hook up the StatusChanged event to determine when it's done. If you're using virtualization and scroll, this will fire again so you need to handle that if necessary in your case.
I waited for my DataGrid's Loaded event to fire, and I did a BeginInvoke, like this:
private void SubjectsList_Loaded(object sender, RoutedEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => ColorMyRows()));
}
More details available in my answer here: https://stackoverflow.com/a/44464630/2101117
Your best bet is to hook into OnPropertyChanged event in your Window or User Control. This event is fired every time a property is updated. Then check for the actual property you wish to observe and take action.
protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
if ("YOUR_PROPERTY_NAME".Equals(e.Property.ToString()))
{
// Take action
}
base.OnPropertyChanged(e);
}

Unload childwindow on close (silverlight mvvm)

How may I ensure that my childwindow is unloaded when it's closed?
I am opening the childwindow from my viewmodel, but after it's been closed it still fires of events like selectionchanged on comboboxes.
The childwindow is using the same viewmodel as it's been called from, so I guess that explains why the events are being fired. The itemssources are still valid.
But when it's closed, I would like to "dispose" the childwindow for good.
I've tried to add a Closed handler like this (Default view code behind):
private void OnLaunchEditItem(ItemMessage msg)
{
var editWnd = new EditItemWindow();
editWnd.Closed += new EventHandler(editWnd_Closed);
editWnd.Show();
}
void editWnd_Closed(object sender, EventArgs e)
{
sender = null;
}
No sucesss..
So what I'm doing now is to remove the itemssource from the childwindow controls, which seems to me... not the ideal solution to the problem. It must be possible to dispose it all from memory on closing? (Childwindow "view" code-behind)
private void OKButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = true;
combobox1.ItemsSource = null;
combobox2.ItemsSource = null;
}
private void CancelButton_Click(object sender, RoutedEventArgs e)
{
this.DialogResult = false;
combobox1.ItemsSource = null;
combobox2.ItemsSource = null;
}
The messaging has a known problem that it introduces a hard link between the messenger and the recipient of a message. So if you use messaging you havee to ensure that the Messenger.Unregister method is called. In other words, when you call Register to handle a messsage make sure you call Unregister as well!
So in your view you have to register for the Unloaded event; there you then call Messenger.Unregiser(this); where this is your view.
In ViewModels you have to make sure that the Cleanup method is called to deregister the ViewModel as a message recipient.
Also see:
MVVM Light Listener not releasing / deterministic finalization for registered object? and MVVM Light Messenger executing multiple times.
Laurent is aware of this Problem but - as of now - has no solution.
Sharing ViewModels between views can lead to problems like this. That's why it's rarely done.
A ViewModel should generally not be concerned with navigation because in an ideal world it shouldn't even know what kind of view it is bound to. This includes spawing child views (ChildWindows).
I would recommend two changes to you. The first one is to create a dedicated viewmodel for your dialog. And second to decouple the navigation from the viewmodel by delegating navigation to a Controller. A controller in MVVM is usually a singleton object who's whole purpose is opening windows, dialogs etc. This can be implemented using the Event Aggregator pattern in a quite elegant fashion.

Hotkeys in Silverlight?

Is there a way to create global keys in Silverlight? I added a KeyDown event handler to the topmost Page element. I can catch the key signal when elements like a Button, TextBox, Calendar, and RichTextBox have focus. But the DatePicker won't let me handle the key down event at the Page level. Any way to make a hotkey in non-OOB SL?
P.S. I am assuming that the DatePicker control behaves differently than others as it is still in the Silverlight Toolkit.
have you tried using the AddHandler method? With this method you can add a handler and define if you want to handle already handled events, too.
In my simple example I added it to the RootVisual in the app.xaml.cs.
private void Application_Startup(object sender, StartupEventArgs e)
{
this.RootVisual = new MainPage();
RootVisual.AddHandler(UIElement.KeyDownEvent, new KeyEventHandler(HandleKeyDown), true);
}
private void HandleKeyDown(object sender, KeyEventArgs e)
{
//Add your keyhandling code here
Debug.WriteLine(e.Key);
}
I tried it with a DatePicker and it works.
Hope this helps!
BR,
TJ
This may help you. The author provides two ways using HTML bridge (when your Silverlight does not have focus) and using the KeyUp event on Application.RootVisual.
I have not tried it myself so I wouldn't know if it's working.

WPF Routed Command only fires sometimes

I have some RoutedCommands for commands like control-A, copy paste and they all work fine.
Then I added 4 more routedcommands to move object up down left and right in the canvas using arrowkeys, they sometimes works and sometime doesn't. At first I thought it was a Focus issue on the Canvas but I just found out that at the same time, all the other routedcommands like control-A works but arrowkeys doesn't.
I really have no idea what's going on here, they are identical routedcommands with different variable names, how come one works 100% of time and one only work 50% of time?
Working RoutedCommand:
_bindings.Add(new CommandBinding(DesignerCanvas.SelectAll, SelectAll_Executed));
SelectAll.InputGestures.Add(new KeyGesture(Key.A, ModifierKeys.Control));
private void SelectAll_Executed(object sender, ExecutedRoutedEventArgs e)
{
SelectionService.SelectAll();
}
Malfunctioning RoutedCommand:
_bindings.Add(new CommandBinding(DesignerCanvas.MoveDown, MoveDown_Executed));
MoveDown.InputGestures.Add(new KeyGesture(Key.Down));
private void MoveDown_Executed(object sender, ExecutedRoutedEventArgs e)
{
e.Handled = true;
var selectedItems = from item in SelectionService.CurrentSelection.OfType<DesignerItem>()
select item;
if (selectedItems.Count() > 0)
{
for (int i = 0; i < selectedItems.Count(); i++)
selectedItems.ElementAt(i).Top += Option.OptionSingleton.Sensitivity;
}
}
The malfunctioning RoutedCommand is just not firing sometimes, especially after I open some other window and come back to the canvas, then it will stop firing while other routedcommands are unaffected. Any ideas what's causing this weird behavior?
You can sometiems use very inclusive class event handlers to trace the route of an event:
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.CanExecuteEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("CanExecute: " + s)), true);
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.ExecutedEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("Executed:" + s)), true);
EventManager.RegisterClassHandler(typeof(FrameworkElement), CommandManager.ExecutedEvent,
new CanExecuteRoutedEventHandler((s, e) => Debug.WriteLine("KeyDown:" + s)), true);
In your case the KeyDown may be handled before it reaches the command binding or the CanExecute event may not reach it for some other reason.
Hopefully this will help you debug the problem
This may be due to the fact that the key you are using is the "Down" key. I suspect that if you used a different key, it would work.
Some controls consume the arrow keys and pageup/pagedown keys. For example, TextBox does this. If your Canvas is in a scrollviewer, the scrollviewer might be eating it.
There are two workarounds for this:
Add a binding to the control that is eating the key gesture.
Handle KeyPreview for the Canvas (or any parent of the control that is eating the keystroke) and execute the command from there.
The answer to this question shows how you can do #2 without writing specific code in the KeyPreview handler for each command.
It turns out that it was a focus issue, I just set the focus to the canvas whenever mouse enters, now it's sort of fixed. Thanks everybody for answering.

What event is fired when a UserControl is displayed?

I'm trying to add a fade effect (animation) for WPF UserControls (although rather for FrameworkElement, to make it more general).
If I let the Loaded event trigger the initial fade-in, the fade animation will sometimes have started before the UserControl has been displayed. The result is a mess. That happens for example if the UserControl does something lengthy (a few tenths of a second), like execute a query, in the Loaded event handler.
So, I would need to handle some event that FrameworkElement/UserControl gets when the content has been rendered, and start the fade-in then. The System.Windows.Window has a ContentRendered event, but UserControl has not. So, what event is fired when a FrameworkElement (or UserControl) has been rendered?
Try to check size on SizeChanged or LayoutUpdated. Do job when actual width or height not equals to 0.
view.LayoutUpdated+=(o,e)=>
{
if (!loaded && (view.ActualHeight > 0 || view.ActualWidth > 0))
{
// You can also unsubscribe event here.
loaded =true;
}
}
Years late, but since I was looking for working solution since now in vain, I want to share my discovery.
If you want a ContentRendered event for any Control (or any Visual or even DependencyObject), you have to dig down to Visual.
I use this code:
// Wait for Control to Load
void TestUserControl_Loaded(object sender, RoutedEventArgs e)
{
// Get PresentationSource
PresentationSource presentationSource = PresentationSource.FromVisual((Visual)sender);
// Subscribe to PresentationSource's ContentRendered event
presentationSource.ContentRendered += TestUserControl_ContentRendered;
}
void TestUserControl_ContentRendered(object sender, EventArgs e)
{
// Don't forget to unsubscribe from the event
((PresentationSource)sender).ContentRendered -= TestUserControl_ContentRendered;
// ..
}
You have to wait for Control Loaded otherwise PresentationSource.FromVisual() returns null.
Various Dispatcher.BeginInvoke methods didn't work consistently for me. Sometimes firing my rendered event long before the control was actually displayed.
This does work for me every time.
I am aware that I am playing with HwndSource here, which is quite low level and I'm not sure of possible implications. (Maybe somebody more experienced can elaborate.)
You can use IsVisibleChnaged event
Assign event handler
MyUserControl.IsVisibleChanged += ScheduleUserControl_IsVisibleChanged;
In event handler check for if is visible or not.
void _IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
//Visible
}
else
{
//Not Visible
}
}
You can schedule the beginning of your Storyboard with a lower priority, for example:
Dispatcher.BeginInvoke(BeginStoryboardAction, DispatcherPriority.ContextIdle);
Here's an article that discusses the issues related to using this method:
Build More Responsive Apps With The Dispatcher
Maybe try IsVisibleChanged, haven't used it much myself though.
This event is not raised if the element is not being rendered by the layout system, for reasons other than the value of the IsVisible property. For example, the element might not have an associated visual.
You can use GotFocus Event
<i:Interaction.Triggers>
<i:EventTrigger EventName="GotFocus">
<i:InvokeCommandAction Command="{Binding ContentControlLoadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>

Resources