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();
Related
I am using the beta version of selenium webdriver(4.0.0) for microsoft edge. I can't figure out how to save the data as pdf that is in print window, which opens after I click on a button in main window
var found = await driver.WaitForElementToAppear(".//font[contains(text(),'Uploaded')]", 180, token);
if(found)
{
//All buttons , which when clicked opens Print window
var ebrcElements = driver.ElementsByXpath(".//input[#type='submit']");
foreach (var ebrcElement in ebrcElements)
{
ebrcElement.Click();//Opens the new window
Thread.Sleep(2000);
driver.SwitchToNewWindow();//Switches to the last window
//The window has "Print" and "Cancel" button
driver.CloseCurrentWindow();
driver.SwitchToFirstWindow();
}
}
Since the window that opens when print button is clicked, is an os dialog box, it cannot be accessed directly from selenium. The way I solved the problem was using P/Invoke.
Using visual studio's spy++ tool it was easy to find the window handle and its caption.
Next I defined method
[DllImport("user32.dll", EntryPoint = "FindWindow", SetLastError = true)]
static extern IntPtr FindWindowByCaption(IntPtr ZeroOnly, string lpWindowName);
and Called it like,
var saveHandle = FindWindowByCaption(IntPtr.Zero, "Save Print Output As");
Next step was to bring the window to foreground using the handle. For that I used the method
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Last step was to simulate the keyboard and mouse operations. For that I used library InputSimulator. It can be downloaded using nuget package manager
var ins = new InputSimulator();
ins.Keyboard.TextEntry($"ebrc{irandom.NextDouble()}");
Thread.Sleep(2000);
ins.Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.TAB);
ins.Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.TAB);
ins.Keyboard.KeyPress(WindowsInput.Native.VirtualKeyCode.RETURN);
I have a WPF application in which the main window is set to full screen via WindowState="Maximized" in the Window tag. In the application, I'm opening PowerPoint through the Office Interop libraries with the intention that PowerPoint opens in the foreground, on top of the WPF application. However, PowerPoint is not consistently coming to the foreground (particularly on Windows 7 machines). In these cases I have to press the Windows key to bring up the Windows Taskbar and click on the PowerPoint icon.
I've tried a few things, such as using SetForegroundWindow() from the Win32 API, the .Activate() function in the PowerPoint Interop library, and the AutomationElement class (here's some code for the last one):
Process process = System.Diagnostics.Process.GetProcessesByName("POWERPNT").FirstOrDefault();
AutomationElement element = AutomationElement.FromHandle(process.MainWindowHandle);
if (element != null)
{
element.SetFocus();
}
However, none of these seem to consistently bring PowerPoint to the front. Does anyone know why exactly this behavior is occurring and how best to get PowerPoint into the foreground?
[DllImport("user32.dll")]
public static extern bool ShowWindowAsync(HandleRef hWnd, int nCmdShow);
[DllImport("user32.dll")]
public static extern bool SetForegroundWindow(IntPtr WindowHandle);
public const int SW_RESTORE = 9;
static void Main(string[] args)
{
Process process = System.Diagnostics.Process.GetProcessesByName("POWERPNT").FirstOrDefault();
IntPtr hWnd = IntPtr.Zero;
hWnd = process.MainWindowHandle;
ShowWindowAsync(new HandleRef(null, hWnd), SW_RESTORE);
SetForegroundWindow(process.MainWindowHandle);
}
works fine with me.
This may work in your case:
Microsoft.VisualBasic.Interaction.AppActivate("fullTitleOfWindow_OR_firstLettersOfWindowTitle");
I'm looking for some guidance here, if not an example of how to accomplish what I am looking to do in C-Sharp(C#).
There is a particular button on a MS Access Ribbon that I would like to click. The MS Access window has a custom UI and custom buttons in different groups. When the button in the first group is clicked, it then opens a childform window. I need to automate that particular step and have my C# application programmatically open that child form by clicking the button or any other means to get it open.
I attempted to do this with the SendKeys and FindWindow functions, but this prove to be rather faulty, because the ALT id's kept changing in MS Access and the SendKeys would stop working.
I've tried searching for articles that would help me with this issue, but all I came across are tutorials on how to make a custom add-in for MS ribbon (I do not want this).
There might be a better way to do this and any help with it is greatly appreciated!
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string strClassName, int nptWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
Public Void SendTest()
{
IntPtr WinHandle = FindWindow("OMain", 0); // OMain = Window Class --found window by class
if (WinHandle == IntPtr.Zero)
{
MessageBox.Show("Program is not running or could not be detected.");
return;
}
SetForegroundWindow(WinHandle);
SendKeys.SendWait("%"); // ALT
SendKeys.SendWait("Y1"); // Y1
SendKeys.SendWait("Y1"); //Y1
}
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;
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.