Refer to active Window in WPF? - c#

How can I refer to active Window of WPF application in C#, using something like ActiveForm property in WinForms?

One possible way would be to scan the list of open windows in the application and check which one of them has IsActive = true:
Application.Current.Windows.OfType<Window>().SingleOrDefault(x => x.IsActive);
Not sure if there may be more than one active window if, for example, there's a modal dialog showing, in which case, the owner of the dialog and the dialog itself might be active.

There is better way to do this using PInvoke. Aviads answer is not working all the time (there are some edge cases with dialogs).
IntPtr active = GetActiveWindow();
ActiveWindow = Application.Current.Windows.OfType<Window>()
.SingleOrDefault(window => new WindowInteropHelper(window).Handle == active);
One must include following import first:
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();

I know this is a bit old question but I think my answer could help someone.
My problem was this: I had a WPF MVVM application and I needed to get my MainWindow instance in the second view, i.e. second view model, in order to set the visibility of title bar button to visible.
This is my solution:
MainWindow window = (MyApp.MainWindow)App.Current.MainWindow;
window.btnSearch.Visibility = System.Windows.Visibility.Visible;
Hope this would help someone.

I have problems With this way "Application.Current.Windows.OfType().SingleOrDefault(x => x.IsActive);" specialy because I was building an aplication with a main Window then i had problems when the main window was selected. I resolve it creating this:
In some base class or App.xaml.cs create this:
public static Window ActivatedWindow {get;set;}
Then put in your base class deriving Window or all of your Window's Activate Event:
First Option - personal Window Base Class:
public class MetroToolWindowBase
{
public MetroToolWindowBase()
{
Activated += new EventHandler(MakeActive);
}
private void MakeActive(object sender, EventArgs e)
{
App.ActivatedWindow= this;
}
}
Second Option- In Activated Event of Windows:
private void XWindow_Activated(object sender,EventArgs e)
{
App.ActivatedWindow= this;
}

Another way to do it is to use the native GetActiveWindow function from user32.dll.
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr GetActiveWindow();
To convert it to an actual WPF Window:
IntPtr handle = GetActiveWindow();
HwndSource hwndSource = HwndSource.FromHwnd(handle);
var window = hwndSource?.RootVisual as Window;
If hosting a WPF Window in a WinForms app, WindowInteropHelper should be used. This makes for example the Window owner work correctly:
var wih = new WindowInteropHelper(window)
{
Owner = GetActiveWindow()
};
I edited my old answer because the edge case I encountered disappeared after a Visual Studio update, but it can be checked from answer history. I encountered an issue there where I was getting null for active window in certain circumstances while debugging.

Related

How to know if a form is not selected?

I have a lots of problem to distinguish such a simple thing.
I need to know if a form is currently in front of everything, the one which receives key entries.
I have no way to know if it is.
I can check if not minimized. But then it may just be behind other windows, or just not being selected (for example it is openend, desktop is behind, you click on desktop, then you still see the application, but it doesn't receive key inputs).
The property focus is irrevelant for this.
Here is the code
protected override void OnActivated(EventArgs e)
{
base.OnActivated(e);
if (this.Focused)
{
gotFocus = true;
// never reaches tis
}
Check if window is the current active window.
Code:
using System.Runtime.InteropServices; // To use DllImport
...
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
if ((IntPtr)GetForegroundWindow() == this.Handle)
{
// Do stuff
}
See: Use GetForegroundWindow result in an if statement to check user's current window

Lost focus issue when using WPF and WindowsInteropHelper

I have a problem with hosting a WPF window inside Excel. What we want to achieve is a window similar to Excel 2013 chart icons next to the chart when chart is selected.
The normal logic is already in place, but there was an issue with click on the ribbon or switching to another window and back to Excel. Both of those scenarios resulted in our window getting hidden.
The solution to this is to set the Owner of our WPF window which is not straight forward when combining Excel and WPF windows. The solution for now was this:
// Getting the active window
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
// Using the WindowInteropHelper to bind WPF window to excel
var wpfWindow = new WPFWindow();
var handle = GetActiveWindow();
helper = new WindowInteropHelper(wpfWindow) { Owner = handle };
wpfWindow.Show();
The above code works fine as long as we only stay in Excel. However the following steps produce a problem:
show our wpfWindow from an Excel addin
switch to another program that is currently running (like browser,...)
switchback to Excel
when our form hides the previously selected program becomes activated and is shown on top of Excel
Any solution to this issue? I have read two similar problems here and here, but they don't offer a working solution.
(I realise this is an old question but hopefully will help someone in the future)
This seems to be a known bug with using window.Show() in wpf windows that hasn't been fixed ( here and here )
Forcing focus to the Owner before Closing seems to work for me (Solution posted in the first link):
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
// Getting the active window
[DllImport("user32.dll")]
static extern IntPtr GetActiveWindow();
// Using the WindowInteropHelper to bind WPF window to excel
var wpfWindow = new WPFWindow();
wpfWindow.Closing += (sender, args) => SetForegroundWindow(new WindowInteropHelper(wpfWindow).Owner);
var handle = GetActiveWindow();
helper = new WindowInteropHelper(wpfWindow) { Owner = handle };
wpfWindow.Show();

this.TopMost = true not working?

I'm very new to C# and still trying to get my head round it (with help of some very patient friends).
I have an issue with setting a new windows form's TopMost property to true. I have two (almost) identical forms; 1 which works OK and one which doesn't.
Both of the forms have the TopMost property set to true.
Form1 shows the window and when I try to click behind it, the form flashes a few times and issues a windows beep.
Form2 also shows the form but when I click behind it, the form greys out (or loses focus) and I can click away on the main form.
I've searched for an answer to this issue and found an answer which suggested putting this.TopMost = true; in the form's load event but that didn't work.
The only thing I have changed which may or may not have had an effect is that Form1 was created with .NET 4.5 set in the properties and before creating Form2, I changed this to .NET 3.5 (client profile). I've tried changing it back but it hasn't helped. Before I delete and create Form2 again, does anyone have any ideas?
Many thanks in advance.
(If you need any more information, please just let me know)
TopMost is a property that is used to make sure one window is always shown above all others within an application. Microsofts example was a find and replace tool.
The difference you are finding is that Form1 was created as a modal dialog through the use of ShowDialog. Show dialog makes sure that your form must be closed before all other windows in the application can be used again. For example; using a form to gain user data to enter into a parent forms database.
Show is used when you don't mind if your user has finished with their dialog or not, such as allowing your user the chance to use some utility (e.g timer, stopwatch) that will assist within the main function of a program.
The only visual difference I can think of when using different .Net frameworks, is different windows dialogs such as the OpenFileDialog, that have been updated throughout the framework
It may help you;
frm.TopLevel = true;
frm.TopMost = true;
This link from Microsoft confirm that could be a Bug in Windows 7 and Windows Server 2008 R2 I've faced it in a Windows 7 Embedded system and the provided patch fix the problem so please consider to take a look :)
http://support.microsoft.com/kb/2587473/en-us
Hope it help!
The DIY-way to do it - works 100%!
public static class User32
{
public const int SW_HIDE = 0;
public const int SW_SHOW = 5;
public const int SW_SHOWNORMAL = 1;
public const int SW_SHOWMAXIMIZED = 3;
public const int SW_RESTORE = 9;
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool AllowSetForegroundWindow(uint dwProcessId);
[DllImport("user32.dll")]
public static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
}
User32.AllowSetForegroundWindow((uint)Process.GetCurrentProcess().Id);
User32.SetForegroundWindow(Handle);
User32.ShowWindow(Handle, User32.SW_SHOWNORMAL);
I hat a similar problem in my solution. After using the overloaded Show-function it worked:
frm.TopLevel = true;
frm.TopMost = true;
frm.Show(this)
Add the following code in the Shown event:
this.TopMost = true;
this.Focus();
this.TopMost = true;

Possible to cast active Microsoft Word window to WPF Window?

I've created a Microsoft Word 2010 vsto add-in which displays a number of custom Wpf Window dialogs when users click on ribbon buttons.
The issue I'm having is that the custom dialog dissapears behind the Word instance if you click the Word icon in the task bar.
After some Googling it appears that this can be fixed by setting the Owner property of my window, but I'm struggling to get the Window instance of the Word application.
I've attached the relevant code below, any suggestions?
using WordNS = Microsoft.Office.Interop.Word;
Window wrapperWindow = new Window();
wrapperWindow.ResizeMode = ResizeMode.NoResize;
wrapperWindow.WindowStartupLocation = System.Windows.WindowStartupLocation.CenterScreen;
wrapperWindow.ShowInTaskbar = false;
wrapperWindow.Content = dialogViewModel.View;
wrapperWindow.Title = dialogViewModel.Title;
wrapperWindow.SizeToContent = SizeToContent.WidthAndHeight;
WordNS.Application app = (WordNS.Application)Marshal.GetActiveObject("Word.Application");
wrapperWindow.Owner = (Window)app.ActiveWindow;
The exception clearly states that the answer to your question is No.
If Microsoft.Office.Interop.Word provides any means to get the window handle (HWND) of Word's main window (or if you get that handle by some Win32 call), you might try to set your window's owner by the WindowInteropHelper.Owner property.
Used Clemens' suggestion to go with the WindowInteropHelper route, below is the complete code to get this working:
1) Define this pointer anywhere inside your class:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
2) Add the following code to the window declaration code:
Window wrapperWindow = new Window();
//Set all the relevant window properties
//Set the owner of the window to the Word application
IntPtr wordWindow = GetForegroundWindow();
WindowInteropHelper wih = new WindowInteropHelper(wrapperWindow);
wih.Owner = wordWindow;

Determine Whether Program is the Active Window in .NET

I have a C#/.NET app and I want to implement the following behavior:
I have a popup menu. Whenever the user clicks on anything within the application that is not the popup menu, I want the popup menu to close.
However, whenever a user is not in the application I don't want anything to happen.
I'm trying to manage this through the LostFocus event, but I'm having trouble determining whether my application is the active window. The code looks something like this.
private void Button_LostFocus(object sender, System.EventArgs e)
{
if (InActiveWindow()) {
CloseMenu()
}
else {
// not in active window, do nothing
}
}
What I need to know is how to implement the InActiveWindow() method.
You could P/Invoke into GetForegroundWindow(), and compare the HWND returned to the application's form.Handle property.
Once you have the handle, you can also P/Invoke GetAncestor() to get the root owner window. This should be the handle of your application's main, startup window, if this is in your application.
I stumbled upon your question while working on a project and based on Reed Copsey's answer, I wrote this quick code which seems to do the job well.
Here's the code:
Public Class Form1
'''<summary>
'''Returns a handle to the foreground window.
'''</summary>
<Runtime.InteropServices.DllImport("user32.dll", SetLastError:=True)> _
Private Shared Function GetForegroundWindow() As IntPtr
End Function
'''<summary>
'''Gets a value indicating whether this instance is foreground window.
'''</summary>
'''<value>
'''<c>true</c> if this is the foreground window; otherwise, <c>false</c>.
'''</value>
Private ReadOnly Property IsForegroundWindow As Boolean
Get
Dim foreWnd = GetForegroundWindow()
Return ((From f In Me.MdiChildren Select f.Handle).Union(
From f In Me.OwnedForms Select f.Handle).Union(
{Me.Handle})).Contains(foreWnd)
End Get
End Property
End Class
I didn't have too much time to convert it to C# as I'm working on a project with a deadline in 2 days but I believe you can quickly do the conversion.
Here is the C# version of the VB.NET code:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[System.Runtime.InteropServices.DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
///<summary>Gets a value indicating whether this instance is foreground window.</summary>
///<value><c>true</c> if this is the foreground window; otherwise, <c>false</c>.</value>
private bool IsForegroundWindow
{
get
{
var foreWnd = GetForegroundWindow();
return ((from f in this.MdiChildren select f.Handle)
.Union(from f in this.OwnedForms select f.Handle)
.Union(new IntPtr[] { this.Handle })).Contains(foreWnd);
}
}
}
It seems like the biggest reason this is tricky is because the popup loses focus before the main form is deactivated, so the active window will always be in the application at the time of this event. Really, you want to know whether it will still be the active window after the event is over.
You could set up some kind of scheme where you remember that a popup is losing focus, set aside the fact that you will need to close it, and in the LostFocus or Deactivate event of the application's main form cancel the note that tells you you need to close it; but the problem is when will you process the note?
I'm thinking it might be easier, at least if the popup is a direct child of the main form (which I suspect in your case it may be) to hook the Focus or maybe even Click event of the main form and use it close the popup if it is open (perhaps by scanning its list of child forms for any that implement an ICloseOnLostFocus interface, so that the popup will have a chance to participate in the decision and do anything else it needs to do).
I wish I knew of a better document explaining what all these events actually mean and how they are sequenced with respect to one another, MSDN leaves a lot to be desired in describing them.

Categories

Resources