Click here to Skip to main content
15,885,244 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
See more:
Hello guys,

I've got a question about a more or less weired behavior of my application after I called Activate() of a WPF window.

I'm developing a tray application which is showing a window when e.g. the hotkey WIN+C is pressed. To capture global hotkeys I'm using this[^] - although I don't think that it might be caused by that library.

So, in case the window is hidden and I do a call to Show(), everything's working as expected - the window shows up. But in case the window is already shown but not active (IsActive != true) and I call window.Activate() it happens that the window is only shown the first time I do this call. When I focus another application and the hitting WIN+C again nothing happens. I put a breakpoint on the according line in my code. It breaks at window.Activate() but doesn't activate it.

I also tried to bring the window in front by using the Win32 API, also without success.

Here's the code I've tried (in comments the calls to the Win32 API I've used):
[I've implemented the property IsShown by overriding the methods Show() and Hide()]

C#
if ( _winKeyPressed && e.KeyCode == Keys.C )
{
    if ( _launcher.IsShown && !_launcher.IsActive )
    {
        //IntPtr wndHandle = new WindowInteropHelper( _launcher ).Handle;
        //IntPtr focused = GetForegroundWindow();
        //if ( focused != wndHandle )
        //{
        //    SetForegroundWindow( wndHandle );
        //}

        _launcher.Activate();
    }
    else
    {
        _launcher.Show();
    }
}


...

C#
//[DllImport( "user32.dll" )]
//public static extern bool SetForegroundWindow( IntPtr hWnd );

//[DllImport( "user32.dll" )]
//public static extern IntPtr GetForegroundWindow();


However, as mentioned it didn't work with that code.
Well, the weired behavior:

C#
if ( _winKeyPressed && e.KeyCode == Keys.C )
{
    if ( _launcher.IsShown && !_launcher.IsActive )
    {
        Thread.Sleep( 100 ); // wtf??
        _launcher.Activate();
    }
    else
    {
        _launcher.Show();
    }
}


When I put a sleep before I call Activate() everything's working fine.
So, as you see in my comment. WTF?
Anybody an idea, what's going? I don't understand this kind of behaviour.

Thanks in advance for any explanations.

Best regards

Edit.
Maybe it is important.
The library I'm using to capture the hotkeys relays on Windows Forms. So e is of type System.Windows.Forms.KeyEventArgs.
The code above is within a KeyDown event handler.

----

Update:

@SAKryukov,
I tried invoking the Dispatcher already. When I first read your comment about the UI thread it suddenly came to my mind :) I'm sorry for not replying directly. However, it is also not working.

I tried before
C#
_launcher.Dispatcher.BeginInvoke( new Action( () => _launcher.Activate() ) );

as well as your suggestion later on. But as far as I know that shouldn't make a difference.

I felt a kind of bad reading your solution because you probably spent more time rebuilding my issue than me seeking for the cause. I know it is not a good idea to use Thread.Sleep() at this point. It was just an idea because I noticed that in case I debug my application, putting a breakpoint before the Active() and wait instead of stepping through directly, made it work. Miracle ha? :)

I also tried to reproduce my problem. I've created a simple project. In case you're interested, you can download it here[^].
It contains just a plain window. After hitting WIN+C a new window should show up.

So, what did I do?
First I only added the reference to the library[^] mentioned in my initial question. Surprisingly I was not able to reproduce my problem, too.
Then I added another reference. I told you, I'm developing a tray application. But I didn't tell you that I'm a lazy boy. Thus I'm playing around with the WPF NotifyIcon[^]
And there we go. Same issue again.

At this moment I'm not sure if it is a "bug" within the NotifyIcon or whether it is caused by using the Windows.Forms key-events. I hope I find some time later on to try dropping all references to Windows.Forms and registering the hooks by myself.

So far, thanks to you two for your solutions.

----

Update 2 & Solved:
I finally solved my problem. I completely dropped all references to Windows.Forms as well as the library I used to hook the global hot-keys and implemented it on my own.
I'm using now the Win32 API to register the hotkeys (1[^]) (2[^]) and the ComponentDispatcher [^] to listen to the system messages. Works very well ;)
Posted
Updated 6-Jan-12 6:57am
v5
Comments
Sergey Alexandrovich Kryukov 5-Jan-12 12:04pm    
I added WPF tag -- you always need it.
Yes, sounds weird. Now, you should not use hotkey capture used on Windows Form, not with WPF. I do have a keyboard capture system in WPF -- this is not so trivial (maybe will publish later if I find time). I don't think it is related to Activation problem. I would need to see it.
--SA
Sergey Alexandrovich Kryukov 5-Jan-12 12:05pm    
Thread.Sleep on UI thread is a sign of completely wrong approach. You never needed it and should not allow yourself to use it. But I understand why would it work... Again, I need to write some code to sort it out...
--SA
Philippe Mori 6-Jan-12 8:53am    
By the way, WIN key is reserved for Windows itself and should never, never be used by any application. No excuse.

And Windows does handle that key somewhat differently than other key like CTRL key as it is handled by the OS and not the application.
SvenMe 6-Jan-12 9:11am    
I didn't know that. Thanks for the hint.
Philippe Mori 6-Jan-12 9:27am    
An interesting link on current shortcut: Windows key.

By the way, if your program allows to configure the shortcut and the shortcut is not used by existing OS (and Windows 8 Preview), it might not be that bad.

By the way, WIN+C is used in Windows 8:
Windows 8 shortcuts

In fact, almost all letters are now used in Windows 8 as shortcuts.

I tried to model this situation and failed to reproduce the effect you describe. Probably, you do something is a different way, something unusual. Do you try to activate another window in a UI thread? As I say, under no condition should you Sleep for any fixed amount of time — this is just pushing trash under the carpet. :-)

Still, I'll try to help.

Usually, it this time dependency exists, it is the observation of so called "race condition" (http://en.wikipedia.org/wiki/Race_condition[^]). I don like this term. I used to learn this phenomena under much more certain term "incorrect dependency on the time of execution". This term itself makes things looking more clear, doesn't it? You have a situation where dependency of the time of elaboration of deferred action comes into play.

In such cases, one very usual technique can help. Please try it. Even without having full understanding of your code and your code itself, I'm almost sure it will work. You simply need to queue the delegate calling Activate. This is a sure method not depending on the actual timing (every time you put an immediate constant like 100, you do something wrong; but I really appreciate your comment which you put at the end of that line :-) — you certainly understand the problem):

C#
if ( _winKeyPressed && e.KeyCode == Keys.C )
{
    if ( _launcher.IsShown && !_launcher.IsActive )
    {
        this.Dispatcher.BeginInvoke(new Action<Window>((window) => {
            window.Activate();
        }), _launcher);

    }
    else
    {
        _launcher.Show();
    }
}


Please try it and report back, if it solved the problem or not.

—SA
 
Share this answer
 
v5
Comments
SvenMe 6-Jan-12 7:52am    
First of all, thank you for spending so much time trying to solve my problem. I really appreciate this.
Please have a look at my updated question.

Best regards
Another solution that often works when there is a problem executing some code during an event is to simply start (enable) a timer instead of executing the code.

And if the timer event handler, you do the actual code and also disable the timer.

This will effectively delay the processing after the current event is handled and thus avoid any possible conflict the code might have with the original event.

A similar alternative would be to PostMessage although I never used that approch in .NET.

The timer approche works quite well in WinForms. I nver tried it in WPF so I don't know if there would be any issue with that approch.

BY the way, I have used hot key (registered hot keys) in a WPF application I have made without any problem but I was not activating any windows in such case, so I cannot confirm if it would have work correctly.
 
Share this answer
 
Comments
SvenMe 6-Jan-12 7:57am    
Thank you for your solution.
To be honest, I don't like that approach because you're actually not solving the issue by just using a timer. As you said already, it is another way to delay the execution and work around bad timings.

About PostMessage, I've to read first what I shall do with that ;)

Best regards
Philippe Mori 6-Jan-12 8:49am    
But it is far better than Sleep has it won't delay the calling thread... It is really bad to call sleep from your hook code. Code in a hook should always be really fast.
SvenMe 6-Jan-12 9:11am    
Maybe you got me wrong. I don't want/like the sleep either else I wouldn't have asked the question. Actually I don't want to delay the execution in anyway. It is bothering me that it isn't working without.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900