What's the best way to detect idle state for a silverlight application? I have read quite a few articles on the net by now and usually they are either for wpf/mobile apps etc.
I have created a DispatcherTimer which locks the screen after 5 minutes and it seems that I will have to go to every widget in every screen(my application has around 4-5 screens) and add a mousebuttondown or mouseenter eventhandler to reset this timer. This doesn't seem to be efficient but just adding the handler to the layroot is not helping either.
Any helpful suggestions?
Thanks
You don't need to modify every control. If you add the following code on startup:
Application.Current.RootVisual.MouseMove += new MouseEventHandler(RootVisual_MouseMove);
Application.Current.RootVisual.KeyDown += new KeyEventHandler(RootVisual_KeyDown);
With the following event handlers:
private void RootVisual_KeyDown(object sender, KeyEventArgs e)
{
idle = false;
}
private void RootVisual_MouseMove(object sender, MouseEventArgs e)
{
idle = false;
}
Where idle is the variable you use in your DispatcherTimer Tick event to check if things are happening or not.
As events bubble up the tree this should work for all your controls.
Handled events will not bubble up to root control. Instead you should use the AddHandler method with handledEventsToo = true.
Related
Hi I have a code to be written while window(WPF window) activate like clicking on the window or using alt/tab. The window is the child of a main form (windows app). I have used ToolWindow as the windowstyle.
It has a xamdatagrid which has to updated on activation
Problem is it fires multiple times. It should be fired once. I don not want my code to run multiple times
How to make it work. please help
From the Window.Activated Event page on MSDN:
Occurs when a window becomes the foreground window.
The Window.Activated Event is supposed to be called multiple times, so perhaps it is not the best event for you to handle. Alternatively, you could add a bool isFirstTime variable and use it to restrict your code to only being called once. Take this example:
private bool isFirstTime = true;
...
private void WindowActivated(object sender, EventArgs e)
{
if (isFirstTime)
{
isFirstTime = false;
// do something here just once
}
}
However, as (from the linked page)...
A window is activated (becomes the foreground window) when:
• The window is first opened.
• A user switches to a window by selecting it with the mouse, pressing ALT+TAB, or from Task Manager.
• A user clicks the window's taskbar button.
... you may find that this will not work for you.
I got it done.
I was using the below code
private void OnAttributeHistoryWindowActivated(object sender, EventArgs e)
{
var win = ((RoutedEventArgs)(e)).Source as AttributeHistoryWindow;
//My Code
}
The first line of code was firing back the Activated event. And it never goes to the next line of my code.
Now I used below code and it works.
private void OnAttributeHistoryWindowActivated(object sender, EventArgs e)
{
var win = sender as AttributeHistoryWindow;
//My Code
}
Now it fires once.
I have an OpenTK GLControl embedden in a WindowsFormsHost in my WPF application.
I want to continuously update and render it.
In Winforms a solution would be to attach the UpdateAndRender method to the Application.Idle event, but there is no such thing in WPF.
So what would be the best way to do (60FPS) updating of my scene and GLControl ?
You can use a System.Timers.Timer to control how often your render code is called. In your window containing the GLControl-in-WindowsFormsHost, declare a private System.Timers.Timer _timer;, then when you're ready to start the rendering loop, set the timer interval and it's event handler, then start it up, as in the following example:
private void btnLoadModel_Click(object sender, RoutedEventArgs e)
{
LoadModel(); // do whatever you need to do to prepare your scene for rendering
_timer = new System.Timers.Timer(10.0); // in milliseconds - you might have to play with this value to throttle your framerate depending on how involved your update and render code is
_timer.Elapsed += TimerElapsed;
_timer.Start();
}
private void TimerElapsed(object sender, ElapsedEventArgs e)
{
UpdateModel(); // this is where you'd do whatever you need to do to update your model per frame
// Invalidate will cause the Paint event on your GLControl to fire
_glControl.Invalidate(); // _glControl is obviously a private reference to the GLControl
}
You'll clearly need to add using System.Timers to your usings.
You can use Invalidate() for it. This causes the GLControl to redraw it's content.
If you call it at the end of Paint() you may blocking some UI rendering of the other WPF controls.
WPF provides a per frame render event: CompositionTarget.Rendering. This event is called before WPF wants to render the content. Subscribe from it and call Invalidate:
public YourConstructor()
{
//...
CompositionTarget.Rendering += CompositionTarget_Rendering;
}
void CompositionTarget_Rendering(object sender, EventArgs e)
{
_yourControl.Invalidate();
}
You need to unsubscribe if you don't use it anymore (to avoid memory leaks).
Here is a How to: Render on a Per Frame Interval Using CompositionTarget from MSDN.
I use GLControl with that method and it works fine. I did not checked how much FPS I have but it feels smooth.
You may also have a look on this: Why is Frame Rate in WPF Irregular and Not Limited To Monitor Refresh?
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.
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.
I am trying to create a custom scrollbar and am using images as button.
For now a simple
I can handle the MouseLeftButtonDown and Up event just fine but what I'd like to do is while its held down, every so many millisecond trigger an event is fired.
I tried something like this but it isn't quite working. Suggestions?
public delegate void Changed(RangeScrollButtonControl sender, int value);
public event Changed OnChanged;
private System.Threading.Timer Timer;
private void Image_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.Timer = new System.Threading.Timer(Timer_Callback, null, 0, 100);
}
private void Image_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
this.Timer = null;
}
private void Timer_Callback(object sender)
{
if (this.OnChanged != null)
{
this.OnChanged(this, 1);
}
}
The piece of functionality you're looking for is a RepeatButton, this will fire it's Click event repeatedly while the mouse button is held down. You can configure the delay and the interval of the events.
You could then style this button to use the image at Silverlight Show
Hope this helps.
Which piece "isn't quite working" ?
Also, could you restyle or retemplate Silverlght's scrollbar similar to what is seen in this blog post to get what you need?
I would use a Storyboard as a timer. Something like:
Then you can do a MouseSTB.Begin. Once the Storyboard is finished you can catch it in the MouseSTB.Completeed Event. In that event you can do what ever you need to do and then just start it over again. It can easilly be controled by setting some flags on the mouseover, mouseenter and mouseleave events. I use these timers in a lot of place and they work just fine and they do not peg the processor.