none
Opening WPF Window from a WPF control hosted in WinForms RRS feed

  • Question

  • Hi,
    The title should already explain what I have, but I'll return. I have a WinForms application, which hosts a WPF control inside ElementHost. The control opens a modal dialog, which is a WPF Window.
    The problem I have is that I cannot set Owner to the new window, because there is actually no WPF Window created and the dialog bust be shown in TaskBar (ugly), otherwise user can switch to another application and when switching back (using task bar) he/she will not see the dialog(even uglier :D ). Needless to say, usual code "Window.GetWindow()" doesn't work here and returns null.

    Is there anything can be done with this? I'm either missing something, or not HwndSource, not WindowInteropHelper, nor their combination gives the required functionality.

    Thanks in advance :)
    Philip Patrick
    Sunday, December 27, 2009 3:55 PM

Answers

  • Thanks Linda, but that was not my question. I'm aware of WindowInteropHelper (as I wrote in my question), but it doesn't help in my case because I have a WPF Window opened from WPF control, which in turn added to WinForm - I stated that in the title of my post.

    Geert: from first glance, your solution looks similar to using WindoInteropHelper itself - at the end the method SetWindowOwner uses it.

    In both cases - WinForm hosting WPF control doesn't (and shouldn't be) aware of any WPF Window opened form hosted controls. I know I have a workaround, passing handle of winform to the WPF control, but that makes it tightly-coupled to host. I can live with this solution for now, but I was wondering if there is an ideal way of doing this.

    Philip Patrick
    • Marked as answer by Linda Liu Monday, January 4, 2010 9:21 AM
    Friday, January 1, 2010 10:52 AM
  • Hi Philip,

    Thank you for your response!

    I know that you host a WPF UserControl within a Winform and open a WPF window from the WPF UserControl. Although my sample demonstrate opening a WPF window directly from a Winform and setting the owner of the WPF window to the Winform, the theory to set a owner of a WPF window to a Winform is the same.

    In your scenario, the best solution is to define a public property of type IntPtr in the WPF UserControl and set the value of this property to the Winform's handle from the Winform. Thus, you can set the owner of the WPF window before it is shown using the method I provided in my first reply.

    Sincerely,
    Linda Liu

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Linda Liu Monday, January 4, 2010 9:21 AM
    Monday, January 4, 2010 9:21 AM

All replies

  • See these extremely useful extension methods for WPF windows. It turns the WPF window into a win32 window and then sets the owner (which can be any window).

    namespace CatenaLogic.Windows
    {
    	/// <summary>
    	/// Extensions for <see cref="System.Windows.Window"/>.
    	/// </summary>
    	public static class WindowExtensions
    	{
    		#region Win32
    		[DllImport("user32.dll")]
    		[return: MarshalAs(UnmanagedType.Bool)]
    		static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
    
    		/// <summary>
    		/// RECT struct for platform invokation.
    		/// </summary>
    		[StructLayout(LayoutKind.Sequential)]
    		public struct RECT
    		{
    			/// <summary>
    			/// Left.
    			/// </summary>
    			public int Left;
    
    			/// <summary>
    			/// Top.
    			/// </summary>
    			public int Top;
    
    			/// <summary>
    			/// Right.
    			/// </summary>
    			public int Right;
    
    			/// <summary>
    			/// Bottom.
    			/// </summary>
    			public int Bottom;
    		}
    		#endregion
    
    		#region Current process main window
    		/// <summary>
    		/// Sets the owner window to the main window of the current process.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		public static void SetOwnerWindow(this Window window)
    		{
    			// Set new owner window without forcing
    			SetOwnerWindow(window, GetProcessMainWindowHandle(), false, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window to the main window of the current process, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		public static void SetOwnerWindowAndFocus(this Window window)
    		{
    			// Set new owner window without forcing
    			SetOwnerWindow(window, GetProcessMainWindowHandle(), false, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window to the main window of the current process.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindow(this Window window, bool forceNewOwner)
    		{
    			// Set owner window to process main window without forcing
    			SetOwnerWindow(window, GetProcessMainWindowHandle(), false, false);
    		}
    
    		/// <summary>
    		/// Sets the owner window to the main window of the current process, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindowAndFocus(this Window window, bool forceNewOwner)
    		{
    			// Set owner window to process main window without forcing
    			SetOwnerWindow(window, GetProcessMainWindowHandle(), false, true);
    		}
    		#endregion
    
    		#region Specific window - Window
    		/// <summary>
    		/// Sets the owner window of a specific window via the Window class.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		public static void SetOwnerWindow(this Window window, Window owner)
    		{
    			// Set owner without forcing
    			SetOwnerWindow(window, owner, false, false);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the Window class, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		public static void SetOwnerWindowAndFocus(this Window window, Window owner)
    		{
    			// Set owner without forcing
    			SetOwnerWindow(window, owner, false, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the Window class.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindow(this Window window, Window owner, bool forceNewOwner)
    		{
    			// Set owner window but do not focus
    			SetOwnerWindow(window, owner, forceNewOwner, false);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the Window class, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindowAndFocus(this Window window, Window owner, bool forceNewOwner)
    		{
    			// Set owner window and focus
    			SetOwnerWindow(window, owner, forceNewOwner, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the Window class.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		/// <param name="focusFirstControl">If true, the first control will automatically be focused.</param>
    		private static void SetOwnerWindow(this Window window, Window owner, bool forceNewOwner,
    			bool focusFirstControl)
    		{
    			// Focus if required
    			if (focusFirstControl) window.FocusFirstControl();
    
    			// Check if this window currently has an owner
    			if (!forceNewOwner && HasOwner(window)) return;
    
    			// Set owner
    			window.Owner = owner;
    		}
    		#endregion
    
    		#region Specific window - IntPtr
    		/// <summary>
    		/// Sets the owner window of a specific window via the window handle.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		public static void SetOwnerWindow(this Window window, IntPtr owner)
    		{
    			// Set owner without forcing
    			SetOwnerWindow(window, owner, false, false);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the window handle, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		public static void SetOwnerWindowAndFocus(this Window window, IntPtr owner)
    		{
    			// Set owner without forcing
    			SetOwnerWindow(window, owner, false, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the window handle.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindow(this Window window, IntPtr owner, bool forceNewOwner)
    		{
    			SetOwnerWindow(window, owner, forceNewOwner, false);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the window handle, but
    		/// also sets the focus on the first control.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		public static void SetOwnerWindowAndFocus(this Window window, IntPtr owner, bool forceNewOwner)
    		{
    			SetOwnerWindow(window, owner, forceNewOwner, true);
    		}
    
    		/// <summary>
    		/// Sets the owner window of a specific window via the window handle.
    		/// </summary>
    		/// <param name="window">Reference to the current window.</param>
    		/// <param name="owner">New owner window.</param>
    		/// <param name="forceNewOwner">If true, the new owner will be forced. Otherwise, if the
    		/// window currently has an owner, that owner will be respected (and thus not changed).</param>
    		/// <param name="focusFirstControl">If true, the first control will automatically be focused.</param>
    		private static void SetOwnerWindow(Window window, IntPtr owner, bool forceNewOwner,
    			bool focusFirstControl)
    		{
    			// Focus if required
    			if (focusFirstControl) window.FocusFirstControl();
    
    			// Check if this window currently has an owner
    			if (!forceNewOwner && HasOwner(window)) return;
    
    			// Set owner via interop helper
    			WindowInteropHelper interopHelper = new WindowInteropHelper(window);
    			interopHelper.Owner = owner;
    
    			// Since this owner type doesn't support WindowStartupLocation.CenterOwner, do
    			// it manually
    			if (window.WindowStartupLocation == WindowStartupLocation.CenterOwner)
    			{
    				// Subscribe to the load event
    				window.Loaded += delegate(object sender, RoutedEventArgs e)
    				{
    					// Get the parent window rect
    					RECT ownerRect;
    					if (GetWindowRect(owner, out ownerRect))
    					{
    						// Get some additional information
    						int ownerWidth = ownerRect.Right - ownerRect.Left;
    						int ownerHeight = ownerRect.Bottom - ownerRect.Top;
    						int ownerHorizontalCenter = (ownerWidth / 2) + ownerRect.Left;
    						int ownerVerticalCenter = (ownerHeight / 2) + ownerRect.Top;
    
    						// Set the location to manual
    						window.WindowStartupLocation = WindowStartupLocation.Manual;
    
    						// Now we know the location of the parent, center the window
    						window.Left = ownerHorizontalCenter - (window.ActualWidth / 2);
    						window.Top = ownerVerticalCenter - (window.ActualHeight / 2);
    					}
    				};
    			}
    		}
    		#endregion
    
    		/// <summary>
    		/// Returns the main window handle of the current process.
    		/// </summary>
    		/// <returns>Handle of the main window of the current process.</returns>
    		private static IntPtr GetProcessMainWindowHandle()
    		{
    			return System.Diagnostics.Process.GetCurrentProcess().MainWindowHandle;
    		}
    
    		/// <summary>
    		/// Returns whether the window currently has an owner.
    		/// </summary>
    		/// <param name="window">Window to check.</param>
    		/// <returns>True if the window has an owner, otherwise false.</returns>
    		private static bool HasOwner(Window window)
    		{
    			return ((window.Owner != null) || (new WindowInteropHelper(window).Owner != IntPtr.Zero));
    		}
    	}
    }


    Geert van Horrik - CatenaLogic
    Visit my blog: http://blog.catenalogic.com

    Looking for a way to deploy your updates to all your clients? Try Updater!
    Tuesday, December 29, 2009 8:00 PM
  • Hi Philip,

    You can use WindowInteropHelper class to interoperate between WPF and Win32 code. Let's say we open a WPF window from a WinForm, and want to set the owner of the WPF window to the WinForm. To do this, initialize the WindowInteropHelper with the WPF window object, and specify the owner of the WPF window with the Owner property of the WindowInteropHelper. The following is a sample.

    // in WinForm
     public partial class Form1 : Form
    {
            private void button1_Click(object sender, EventArgs e)
            {
                WpfApplication1.Window1 window = new WpfApplication1.Window1();
                WindowInteropHelper helper = new WindowInteropHelper(window);
                   helper.Owner = this.Handle;
                window.Show();
    }

    Hope this helps.
    If you have any question, please feel free to let me know.

    Sincerely,
    Linda Liu


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Linda Liu Thursday, December 31, 2009 10:47 AM
    • Unmarked as answer by Philip Patrick Friday, January 1, 2010 10:40 AM
    Wednesday, December 30, 2009 10:30 AM
  • Thanks Linda, but that was not my question. I'm aware of WindowInteropHelper (as I wrote in my question), but it doesn't help in my case because I have a WPF Window opened from WPF control, which in turn added to WinForm - I stated that in the title of my post.

    Geert: from first glance, your solution looks similar to using WindoInteropHelper itself - at the end the method SetWindowOwner uses it.

    In both cases - WinForm hosting WPF control doesn't (and shouldn't be) aware of any WPF Window opened form hosted controls. I know I have a workaround, passing handle of winform to the WPF control, but that makes it tightly-coupled to host. I can live with this solution for now, but I was wondering if there is an ideal way of doing this.

    Philip Patrick
    • Marked as answer by Linda Liu Monday, January 4, 2010 9:21 AM
    Friday, January 1, 2010 10:52 AM
  • Hi Philip,

    Thank you for your response!

    I know that you host a WPF UserControl within a Winform and open a WPF window from the WPF UserControl. Although my sample demonstrate opening a WPF window directly from a Winform and setting the owner of the WPF window to the Winform, the theory to set a owner of a WPF window to a Winform is the same.

    In your scenario, the best solution is to define a public property of type IntPtr in the WPF UserControl and set the value of this property to the Winform's handle from the Winform. Thus, you can set the owner of the WPF window before it is shown using the method I provided in my first reply.

    Sincerely,
    Linda Liu

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    • Marked as answer by Linda Liu Monday, January 4, 2010 9:21 AM
    Monday, January 4, 2010 9:21 AM
  • Thanks Linda, that's what I do right now, was wondering if there is a better way of handling such situation, because, as I stated in the previous post, this makes WPF control aware of its WinForm parent, but guess there is no better way.
    Philip Patrick
    Monday, January 4, 2010 7:42 PM
  • If it helps this is an extension method that I use to find the parent form for a WPF control hosted within a WinForms app. I know this still implies that your WPF parts are aware that they are hosted within a Windows Forms application but at least it cuts down on the steps to reach the parent Form as well as the corresponding window handle.

            public static Form FindForm(this Visual element)
            {
                HwndSource wpfHandle = PresentationSource.FromVisual(element) as HwndSource;
    
                if(wpfHandle == null)
                {
                    return null;
                }
                
                ElementHost elementHost = System.Windows.Forms.Control.FromChildHandle(wpfHandle.Handle) as ElementHost;
                return elementHost.FindForm();
            }
    Wednesday, February 3, 2010 6:01 AM
  • Hiya, just a quickie, how would one host a WPF exe( it is an executable process with file path *.exe) inside a windows form process. giving a bit of context, we have legacy win32 processes(all upgraded to .NET 4.0) and some new WPF plugin based UI apps. the requirement is to show(the UI of WPF) apps within the existing windows apps as tabs. i.e. if there are four PWF exe's  then start all four processes and make them look like one within a tabbed winform app. an ideas or existing implementations. can you also please post a copy of the response to samir.parekh@credit-suisse.com. Thanks in advance.

    Wednesday, March 9, 2011 3:27 PM