WPF ve Win32 Birlikte Çalışması

Bu konu, WPF ve Win32 kodunun birlikte nasıl kullanılacağına ilişkin bir genel bakış sağlar. Windows Presentation Foundation (WPF), uygulamalar oluşturmak için zengin bir ortam sağlar. Ancak, Win32 kodunda önemli bir yatırımınız olduğunda, bu kodların bazılarını yeniden kullanmak daha etkili olabilir.

WPF ve Win32 birlikte çalışabilirlik temelleri

WPF ve Win32 kodu arasında birlikte çalışabilirlik için iki temel teknik vardır.

  • Bir Win32 penceresinde WPF içeriğini barındırın. Bu teknikle, standart bir Win32 penceresi ve uygulamasının çerçevesi içinde WPF 'nin gelişmiş grafik yeteneklerini kullanabilirsiniz.

  • WPF içeriğinde Win32 penceresi barındırın. Bu teknikle, mevcut özel bir Win32 denetimini diğer WPF içerikleri bağlamında kullanabilir ve verileri sınırlar arasında geçirebilirsiniz.

Bu tekniklerin her biri kavramsal olarak bu konuda sunulmuştur. Win32 'de WPF barındırma hakkında daha fazla kod odaklı bir çizim için bkz. Izlenecek yol: Win32 'de WPF Içeriğini barındırma. WPF 'de Win32 barındırmanın daha fazla kod odaklı bir çizimi için bkz. Izlenecek yol: WPF 'de Win32 denetimi barındırma.

WPF birlikte çalışma projeleri

WPF API 'Leri yönetilen koddur, ancak var olan Win32 programlarının çoğu yönetilmeyen C++ dilinde yazılır. Doğru yönetilmeyen bir programdan WPF API 'Leri çağrılamaz. ancak, /clr Microsoft Visual C++ derleyicisi ile seçeneğini kullanarak, yönetilen ve yönetilmeyen apı çağrılarını sorunsuzca karıştırabileceğiniz, karma yönetilen, yönetilmeyen bir program oluşturabilirsiniz.

Proje düzeyinde bir karmaşıkma, Extensible Application Markup Language (XAML) dosyalarını C++ projesine derleyemezsiniz. Bunun için telafi eden çeşitli proje bölmesi teknikleri vardır.

  • Tüm XAML sayfalarınızı derlenmiş derleme olarak içeren bir C# DLL oluşturun ve ardından C++ yürütülebilir dosyanızı bir başvuru olarak bu DLL 'yi içermesini sağlayabilirsiniz.

  • WPF içeriği için bir C# yürütülebiliri oluşturun ve Win32 içeriğini içeren bir C++ DLL 'ye başvurın.

  • LoadXaml 'nizi derlemek yerine çalışma zamanında herhangi BIR xaml yüklemek için kullanın.

  • XAML 'yi hiç kullanmayın ve kod içinde, içindeki öğe ağacını oluşturan tüm WPF ' i yazın Application .

Sizin için en uygun yaklaşımı kullanın.

Not

Daha önce C++/CLı kullandıysanız, gcnewnullptr birlikte çalışabilirlik kod örneklerinde ve gibi bazı "yeni" anahtar kelimelerinde fark edebilirsiniz. Bu anahtar sözcükler, eski çift alt çizgi söz dizimini ( __gc ) yerine ekler ve C++ ' ta yönetilen kod için daha doğal bir sözdizimi sağlar. C++/CLı tarafından yönetilen özellikler hakkında daha fazla bilgi edinmek için bkz. çalışma zamanı platformları Için bileşen uzantıları.

WPF, HWNDs 'yi nasıl kullanır?

WPF "HWND birlikte çalışabilirliği" oluşturmak için WPF 'in HWNDs 'i nasıl kullandığını anlamanız gerekir. herhangi bir HWND için, DirectX işleme veya gdı/GDI+ işlemesi ile WPF işlemesini karıştıramazsınız. Bu bir dizi etkilere sahiptir. Öncelikle, bu işleme modellerini hiç karıştırmak için, birlikte çalışabilirlik çözümü oluşturmanız ve kullanmayı seçtiğiniz her bir işleme modeli için birlikte çalışabilirlik 'nin belirlenen segmentlerini kullanmanız gerekir. Ayrıca, işleme davranışı, birlikte çalışma çözümünüzün gerçekleştirebilecekleri bir "hava sahası" kısıtlaması oluşturur. "Hava sahası" kavramı, teknoloji bölgelerine genel bakışkonusunda daha ayrıntılı olarak açıklanmıştır.

Ekrandaki tüm WPF öğeleri, sonunda bir HWND tarafından desteklenir. WPF oluşturduğunuzda Window WPF, en üst düzey BIR HWND oluşturur ve HwndSource , Window ve onun WPF içeriğini HWND içine koymak için bir kullanır. Bu tekil HWND, uygulama paylaşımlarında bulunan WPF içeridedir. Menüler, Birleşik giriş kutusu açılan listeleri ve diğer açılır pencereler özel bir durumdur. Bu öğeler kendi üst düzey penceresini oluşturur. Bu, WPF menüsünün neden büyük olasılıkla onu içeren bir HWND 'nin kenarından geçebileceğini gösteren kendi üst düzey penceresini oluşturur. WPF HwndHost 'ye BIR HWND koymak için KULLANDıĞıNıZDA WPF, yeni alt HWND 'YI WPF HWND 'ye göre nasıl konumlandırdığını bildirir Window .

HWND ile ilgili bir kavram, her HWND içinde ve arasında saydamdır. Bu, teknoloji bölgelerine genel bakışkonusunda da ele alınmıştır.

Microsoft Win32 penceresinde WPF Içeriğini barındırma

Bir Win32 penceresinde bir WPF barındırmak için anahtar HwndSource sınıfı olur. Bu sınıf WPF içeriğini bir Win32 penceresinde sarmaladığı için WPF içeriğinin bir alt pencere olarak kullanıcı arayüzüne (UI) dahil edilebilir. Aşağıdaki yaklaşım, Win32 ve WPF 'yi tek bir uygulamada birleştirir.

  1. WPF içeriğinizi (içerik kök öğesi) yönetilen bir sınıf olarak uygulayın. Genellikle, sınıfı birden çok alt öğe içerebilen ve/veya gibi bir kök öğe olarak kullanılan sınıflardan birinden devralır DockPanelPage . Sonraki adımlarda, bu sınıf WPF içerik sınıfı olarak adlandırılır ve sınıfın örnekleri WPF içerik nesneleri olarak adlandırılır.

  2. C++/cliile Windows uygulaması uygulama. Var olan bir yönetilmeyen C++ uygulamasıyla başlıyorsanız, genellikle proje ayarlarınızı derleyici bayrağını içerecek şekilde değiştirerek yönetilen kodu çağırabilir /clr . (derlemeyi desteklemek için gerekli olan tam kapsam /clr Bu konuda açıklanmamıştır).

  3. İş parçacığı modelini tek Iş parçacıklı Apartment (STA) olarak ayarlayın. WPF bu iş parçacığı modelini kullanır.

  4. WM_CREATE bildirimini pencere yordamınıza işleyin.

  5. İşleyici içinde (veya işleyicinin çağırdığı bir işlev), aşağıdakileri yapın:

    1. HwndSourceParametresi olarak üst pencere HWND ile yeni bir nesne oluşturun parent .

    2. WPF içerik sınıfınızın bir örneğini oluşturun.

    3. Nesne özelliğine WPF içerik nesnesine bir başvuru atayın HwndSourceRootVisual .

    4. HwndSourceObject Handle özelliği, pencere TANıTıCıSıNı (hwnd) içerir. Uygulamanızın yönetilmeyen bölümünde kullanabileceğiniz bir HWND almak için Handle.ToPointer() BIR HWND 'ye atayın.

  6. WPF içerik nesneniz için bir başvuru tutan bir statik alan içeren yönetilen bir sınıf uygulayın. Bu sınıf, Win32 kodunuzda WPF içerik nesnesine bir başvuru almanızı sağlar, ancak daha da önemlisi, HwndSource istemeden atık toplanmasını önler.

  7. WPF içerik nesnesi olaylarına bir veya daha fazla işleyici ekleyerek WPF içerik nesnesinden bildirim alın.

  8. Özellikleri ayarlamak için statik alanda depoladığınız başvuruyu kullanarak WPF içerik nesnesiyle iletişim kurun, yöntemleri çağırın, vb.

Not

İçerik sınıfının varsayılan kısmi sınıfını kullanarak XAML 'de adım adım için WPF içerik sınıfı tanımının bir kısmını veya tümünü, ayrı bir derleme üretemiyor ve daha sonra başvurdıysanız yapabilirsiniz. Genellikle, Application xaml 'yi bir derlemeye derlemenin parçası olarak bir nesne dahil olsanız da, bunu Application birlikte çalışma 'nin bir parçası olarak kullanarak, uygulama tarafından başvurulan XAML dosyaları için bir veya daha fazla kök sınıftan yalnızca bir veya daha fazla tane kullanın ve kısmi sınıflarına başvurmayın. Yordamın geri kalanı temelde yukarıda ana hatlarıyla benzerdir.

Bu adımların her biri, Izlenecek yol: Win32 'de WPF Içeriğini barındırmakonusundaki kod aracılığıyla gösterilmiştir.

WPF 'de Microsoft Win32 penceresi barındırma

Diğer WPF içeriklerde Win32 penceresini barındırmak için anahtar HwndHost sınıfı olur. Bu sınıf, bir WPF öğe ağacına eklenebilen bir WPF öğesinde pencereyi sarmalanmış. HwndHost Ayrıca, bu gibi görevleri barındırılan pencere için işlem iletileri olarak yapmanıza imkan tanıyan API 'Leri destekler. Temel yordam:

  1. WPF uygulaması için bir öğe ağacı oluşturun (kod veya biçimlendirme aracılığıyla olabilir). Öğe ağacında, HwndHost uygulamanın bir alt öğe olarak eklenebileceği uygun ve izin verilen bir nokta bulun. Bu adımların geri kalanında, bu öğe, ayırma öğesi olarak adlandırılır.

  2. ' Dan türet HwndHost , Win32 içeriğinizi tutan bir nesne oluşturun.

  3. Bu ana bilgisayar sınıfında, yöntemini geçersiz HwndHost kılın BuildWindowCore . Barındırılan pencerenin HWND 'sini döndürün. Gerçek denetimleri döndürülen pencerenin alt penceresi olarak kaydırmak isteyebilirsiniz; denetimleri bir ana bilgisayar penceresinde sarmalama, WPF içeriğiniz için denetimlerden bildirimleri almak için basit bir yol sağlar. Bu teknik, barındırılan denetim sınırında ileti işleme ile ilgili bazı Win32 sorunları için düzeltmeye yardımcı olur.

  4. HwndHostVe yöntemlerini geçersiz DestroyWindowCore kılın WndProc . Buradaki amaç, özellikle yönetilmeyen nesnelere başvurular oluşturduysanız, temizleme işlemini ve barındırılan içeriğe başvuruları kaldırmayı sağlar.

  5. Arka plan kod dosyanızda, denetim barındırma sınıfının bir örneğini oluşturun ve bunu ayırma öğesinin bir alt öğesi yapın. Genellikle gibi bir olay işleyicisi kullanır Loaded veya kısmi sınıf oluşturucusunu kullanabilirsiniz. Ancak, birlikte çalışabilirlik içeriğini çalışma zamanı davranışı ile de ekleyebilirsiniz.

  6. Denetim bildirimleri gibi seçili pencere iletilerini işleyin. İki yaklaşım vardır. Her ikisi de ileti akışına özdeş erişim sağlar, böylece seçiminiz programlama kolaylığına göre büyük ölçüde önemlidir.

    • Yöntemi geçersiz kılmanızda tüm iletiler için ileti işlemeyi uygulayın (yalnızca kapalı iletiler değil) HwndHostWndProc .

    • Barındırma WPF öğesinin, olayı işleyerek iletileri işlemesini sağlayabilirsiniz MessageHook . Bu olay barındırılan pencerenin ana pencere yordamına gönderilen her ileti için oluşturulur.

    • Kullanarak işlem dışı olan Windows iletilerini işleyemez WndProc .

  7. Yönetilmeyen işlevi çağırmak için platform Invoke kullanarak barındırılan pencereyle iletişim kurun SendMessage .

Bu adımları takip etmek, fare girişi ile birlikte çalışarak bir uygulama oluşturur. Arabirimini uygulayarak barındırılan pencereniz için sekme desteği ekleyebilirsiniz IKeyboardInputSink .

Bu adımların her biri, konu başlığı altında kod aracılığıyla gösterilmiştir : WPF 'Te Win32 denetimi barındırma.

WPF Içinde HWNDs

HwndHostÖzel bir denetim olarak düşünebilirsiniz. (Teknik olarak, HwndHostFrameworkElement türetilmiş sınıf değil, türetilmiş bir sınıftır, Control ancak birlikte çalışma amacıyla bir denetim olarak kabul edilebilir.) HwndHost barındırılan içeriğin temel alınan Win32 yapısını, örneğin, WPF 'nin geri kalanı barındırılan içeriği, girişi oluşturması ve işlemesi gereken başka bir denetim benzeri nesne olacak şekilde değerlendirir. HwndHost genellikle diğer tüm WPF gibi davranır FrameworkElement , ancak temeldeki HWND NDS 'nin destekleyebilecekleri sınırlamalara göre çıkış (çizim ve grafik) ve giriş (fare ve klavye) etrafında bazı önemli farklılıklar vardır.

Çıkış davranışındaki önemli farklılıklar

  • FrameworkElementtemel sınıf olan, HwndHost Kullanıcı arabiriminde yapılan değişiklikleri belirten birkaç özelliği vardır. Bunlar gibi FrameworkElement.FlowDirection , bu öğe içindeki öğelerin yerleşimini üst öğe olarak değiştiren özellikler içerir. Ancak, bu özelliklerin çoğu, bu tür eşdeğerleri mevcut olabilseler bile olası Win32 eşdeğerlerine eşlenmez. Bu özelliklerden çok fazla ve anlamları, eşlemelerin pratik olması için çok fazla işleme teknolojisine özgüdür. Bu nedenle, gibi özelliklerinin ayarlanması FlowDirectionHwndHost hiçbir etkiye sahip değildir.

  • HwndHost bir dönüşümden döndürülemez, ölçeklendirilemez, çarpıtılmış veya başka bir şekilde etkilenmemelidir.

  • HwndHostOpacityözelliği desteklemez (Alfa karıştırma). İçindeki içerik, HwndHostSystem.Drawing bir ihlal olmayan alfa bilgilerini içeren işlemler gerçekleştirirse, ancak HwndHost tam olarak yalnızca opaklığı destekler = 1,0 (100%).

  • HwndHost , aynı üst düzey penceredeki diğer WPF öğelerinin üstünde görünür. Ancak, ToolTip veya ContextMenu oluşturulmuş bir menü ayrı bir üst düzey penceredir ve bu nedenle ile doğru şekilde davranır HwndHost .

  • HwndHost üst öğesinin kırpma bölgesine göre değil UIElement . Bu, bir HwndHost sınıfı kaydırılan bir bölgenin içine veya bir sınıf koymaya çalışırsanız sorun olabilir Canvas .

Giriş davranışında önemli farklılıklar

  • Genel olarak, giriş cihazları HwndHost barındırılan Win32 bölgesi kapsamında olduğunda, giriş olayları doğrudan Win32 'ye gider.

  • Fare üzerindeyken HwndHost , UYGULAMANıZ WPF fare olaylarını almaz ve WPF özelliğinin değeri olacaktır IsMouseOverfalse .

  • HwndHostKlavye odağı olsa da, UYGULAMANıZ WPF klavye olayları almaz ve WPF özelliğinin değeri olacaktır IsKeyboardFocusWithinfalse .

  • Odak içinde olduğunda HwndHost ve içindeki başka bir denetimdeki değişiklikler olduğunda HwndHost , uygulamanız WPF olaylarını ya da almaz GotFocusLostFocus .

  • İlgili ekran kalemi özellikleri ve olayları benzerdir ve ekran kalemi üzerindeyken bilgileri rapor etmez HwndHost .

Sekme, anımsatıcı ve Hızlandırıcılar

IKeyboardInputSinkVe IKeyboardInputSite arabirimleri, karma WPF ve Win32 uygulamaları için sorunsuz bir klavye deneyimi oluşturmanıza imkan tanır:

  • Win32 ve WPF bileşenleri arasında sekme

  • Odak bir Win32 bileşeni içindeyse ve bir WPF bileşeni içindeyse her ikisi de çalışan anımsatıcıları ve Hızlandırıcılar.

HwndHostVe HwndSource sınıflarının her ikisi de uygulamalarını sağlar IKeyboardInputSink , ancak daha gelişmiş senaryolar için istediğiniz tüm giriş iletilerini işleyemeyebilir. İstediğiniz klavye davranışını almak için uygun yöntemleri geçersiz kılın.

Arabirimler yalnızca WPF ve Win32 bölgeleri arasındaki geçişte ne olacağı için destek sağlar. Win32 bölgesi içinde sekme davranışı, varsa, sekme için, Win32 tarafından uygulanan mantık tarafından tamamen denetlenir.

Ayrıca bkz.