2010-07-10 24 views
7

Win32 etkinleştirme iletilerini kullanabilmem için bazı WPF pencerelerinin Win32 pencere tutamaçlarına erişmem gerekiyor. Win32 pencere tanıtıcısını almak için PresentationSource.FromVisual veya WindowInteropHelper kullanabileceğimi biliyorum, ancak WPF penceresi henüz oluşturulmamışsa sorunlara koşuyorum.WPF Penceresinin yerel Win32 tanıtıcısının oluşturulmasını zorlama

PresentationSource.FromVisual kullanırsanız ve pencere oluşturulmadıysa, döndürülen PresentationSource boştur. WindowInteropHelper kullanıyor ve pencere oluşturulmamışsa, Handle özelliği IntPtr.Zero (boş) 'dir.

Tutamağa erişmeye çalışmadan önce pencerede this.Show() ve this.Hide() numaralı telefonu aramayı denedim. Daha sonra tutamağı alabilirim, ama pencere anlık olarak ekranda yanıp söner (çirkin!).

Bir WPF penceresinin oluşturulmasını zorlamanın bir yolu var mı? Windows Forms'da bu, Form.Handle özelliğine erişim kadar kolaydı.

Düzeltme: Chris Taylor'un yanıtında bir varyantla devam ettim. İşte, durumunda başkasının yardımcı olur:

static void InitializeWindow(Window window) 
{ 
    // Get the current values of the properties we are going to change 
    double oldWidth = window.Width; 
    double oldHeight = window.Height; 
    WindowStyle oldWindowStyle = window.WindowStyle; 
    bool oldShowInTaskbar = window.ShowInTaskbar; 
    bool oldShowActivated = window.ShowActivated; 

    // Change the properties to make the window invisible 
    window.Width = 0; 
    window.Height = 0; 
    window.WindowStyle = WindowStyle.None; 
    window.ShowInTaskbar = false; 
    window.ShowActivated = false; 

    // Make WPF create the window's handle 
    window.Show(); 
    window.Hide(); 

    // Restore the old values 
    window.Width = oldWidth; 
    window.Height = oldHeight; 
    window.WindowStyle = oldWindowStyle; 
    window.ShowInTaskbar = oldShowInTaskbar; 
    window.ShowActivated = oldShowActivated; 
} 

// Use it like this: 
InitializeWindow(myWpfWindow); 
+0

Bu soruyu gördünüz mü? - http://stackoverflow.com/questions/1556182/finding-the-handle-to-a-wpf-window - Pencerenin zaten mevcut olup olmadığından bahsedilmediği için yardımcı olmayabilir ya da değil. – ChrisF

+0

@ChrisF: Teşekkürler! Evet, bunu gördüm. Ne yazık ki, henüz oluşturulmamış pencerede sorun var. –

+0

Cevabınızı almak için bahsettiğimi düşünürdüm ki, eğer durumunuz farklı olsaydı, kopya olarak seçilmezdi. – ChrisF

cevap

3

Seçeneklerden biri minimize etmek pencere durumuna ayarlamak için ve pencereyi gösterme önce görev çubuğunda göstermek için değildir. Böyle bir şey dene.

IntPtr hWnd; 
    WindowInteropHelper helper = new WindowInteropHelper(wnd); 

    WindowState prevState = wnd.WindowState; 
    bool prevShowInTaskBar = wnd.ShowInTaskbar; 

    wnd.ShowInTaskbar = false; 
    wnd.WindowState = WindowState.Minimized; 
    wnd.Show(); 
    hWnd = helper.Handle; 
    wnd.Hide(); 

    wnd.ShowInTaskbar = prevShowInTaskBar; 
    wnd.WindowState = prevState; 
+0

Teşekkürler! Bunun bir varyantı ile devam ettim (sorudaki benim düzenime bakın). –

+2

[@ DanielAlbuschat'un cevabı] (http://stackoverflow.com/a/4826741/24874) daha basittir ve titremekten kaçınır. –

+0

Evet, aşağıdaki cevap çok daha temiz. –

17

WindowInteropHelper.EnsureHandle kullanın, tam olarak ihtiyacınız olanı yapar.

+0

+1 Harika Bul! Denemek zorundayım. –

+0

Aynı problemi aldım ve bu en iyi cevap! – laishiekai

+0

Yine, bu kabul edilen olandan çok daha iyi bir cevap! Lütfen bunu herkes yerine kullan! –

2

WindowInteropHelper'in tanıtıcısı NULL ise bir çözüm arıyordum. Umarım bu yazı, nasıl çözüleceğine dair bazı ek bilgiler verir.

bir çözüm kullanmaktır:

var window = new Window(); 
var handle = new WindowInteropHelper(window).EnsureHandle() 

Bu yüzden ben başka bir çözüm gerekli .NET Framework 3.5 kullanıyorum anda .NET Framework 4

ile çalışır.

#region 

using System; 
using System.Reflection; 
using System.Windows; 
using System.Windows.Interop; 

#endregion 

namespace System.Windows.Interop 
{ 
    /// <summary> 
    /// Provides NetFX 4.0 EnsureHandle method for 
    /// NetFX 3.5 WindowInteropHelper class. 
    /// </summary> 
    public static class WindowInteropHelperExtension 
    { 
     /// <summary> 
     /// Creates the HWND of the window if the HWND has not been created yet. 
     /// </summary> 
     /// <param name = "helper">An instance of WindowInteropHelper class.</param> 
     /// <returns>An IntPtr that represents the HWND.</returns> 
     /// <remarks> 
     /// Use the EnsureHandle method when you want to separate 
     /// window handle (HWND) creation from the 
     /// actual showing of the managed Window. 
     /// </remarks> 
     public static IntPtr EnsureHandle(this WindowInteropHelper helper) 
     { 
      if (helper == null) 
       throw new ArgumentNullException("helper"); 

      if (helper.Handle == IntPtr.Zero) 
      { 
       var window = (Window) typeof (WindowInteropHelper).InvokeMember(
        "_window", 
        BindingFlags.GetField | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, helper, null); 

       typeof (Window).InvokeMember(
        "SafeCreateWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, null); 
      } 

      return helper.Handle; 
     } 
    } 
} 

WindowInteropHelper.EnsureHandle() bir pencere zaten oluşturulur beklemediğini: Sonra bir WindowInteropHelper uzatma yöntemi ile bir forum başlığını buldum.

Referans: Alexander Yudakov - http://social.msdn.microsoft.com/Forums/en-MY/wpf/thread/5f89ac58-d2ef-4ac0-aefb-b2826dbef48a

0

Bu aynı konuyla ilgili sıkışmış ve (bana daha temiz görünüyor çünkü) J Pollack's answer ile gitti, ancak .NET çalışma zamanı hem aday olacağını şey ihtiyaç vardı 2.0 ve 4.0.

Ama artık .NET çalışma zamanı 4.0 var olmayan çirkin bir MissingMethodException SafeCreateWindow çünkü ile sona erdi bunu yaptıklarında. Ben MissingMethodException yakalamaya karar her iki çalışma süreleri kod çalışması ve bunun yerine böyle .NET 4.0 çalışma zamanı içinde eşdeğer çağırmak için: Bu bana .NET 3.5 ile kod derleme ancak bunu çalışmasına izin

public static IntPtr EnsureHandle(this WindowInteropHelper helper) 
    { 
     if (helper == null) 
      throw new ArgumentNullException("helper"); 

     if (helper.Handle == IntPtr.Zero) 
     { 
      var window = (Window)typeof(WindowInteropHelper).InvokeMember(
       "_window", 
       BindingFlags.GetField | 
       BindingFlags.Instance | 
       BindingFlags.NonPublic, 
       null, helper, null); 

      try 
      { 
       // SafeCreateWindow only exists in the .NET 2.0 runtime. If we try to 
       // invoke this method on the .NET 4.0 runtime it will result in a 
       // MissingMethodException, see below. 
       typeof(Window).InvokeMember(
        "SafeCreateWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, null); 
      } 
      catch (MissingMethodException) 
      { 
       // If we ended up here it means we are running on the .NET 4.0 runtime, 
       // where the method we need to call for the handle was renamed/replaced 
       // with CreateSourceWindow. 
       typeof(Window).InvokeMember(
        "CreateSourceWindow", 
        BindingFlags.InvokeMethod | 
        BindingFlags.Instance | 
        BindingFlags.NonPublic, 
        null, window, new object[] { false }); 
      } 
     } 

     return helper.Handle; 
    } 

.NET çalışma zamanı 4.Yalnızca daha yüksek çalışma zamanı sürümüne sahip olan sistemlerde (Windows 8 ve üstü).