İzlenecek yol: Win32 'de WPF saati barındırma
WPFWin32 uygulamalarının içine koymak için HwndSource IÇERIĞINIZI içeren HWND 'yi sağlayan kullanın WPF . İlk olarak, HwndSource CreateWindow 'a benzer parametreler vererek oluşturun. Ardından, HwndSource WPF içinde istediğiniz içeriğe ilişkin bilgi verin. Son olarak, HWND 'yi ' den alın HwndSource . Bu izlenecek yol WPF , işletim sistemi Tarih ve saat özellikleri iletişim kutusunu yeniden uygulayan bir karma içinde karma uygulamanın nasıl oluşturulacağını göstermektedir.
Önkoşullar
Bkz. WPF ve Win32 birlikteçalışma.
Bu öğreticiyi kullanma
Bu öğretici, birlikte çalışabilirlik uygulaması üretmede önemli adımlarla yoğunlaşır. Öğretici örnek, Win32 saat birlikte çalışabilirlikörneğiyle desteklenir, ancak bu örnek, son ürünün yansıtıcı örneğidir. Bu öğreticide, kendi mevcut bir Win32 projesiyle başladıysanız, belki de önceden var olan bir projede ve uygulamanıza barındırılan bir proje gibi adımlar belgeliyoruz WPF . Son ürününüzü, Win32 saat birlikte çalışabilirlikörneğiyle karşılaştırabilirsiniz.
Win32 Içindeki Windows Presentation Framework 'e yönelik bir adım adım (HwndSource)
Aşağıdaki grafikte, Bu öğreticinin amaçlanan son ürünü gösterilmektedir:

Visual Studio 'da bir C++ Win32 projesi oluşturarak ve iletişim düzenleyicisini kullanarak, aşağıdakileri oluşturmak için bu iletişim kutusunu yeniden oluşturabilirsiniz:

(Kullanmak için Visual Studio kullanmanız gerekmez HwndSource ve Win32 programları yazmak için C++ kullanmanız gerekmez, ancak bunu yapmak için oldukça yaygın bir yoldur ve bir tarafınızdaki öğretici açıklamasına dahil değildir.
İletişim kutusuna bir saat koymak için beş özel alt adım gerçekleştirmeniz gerekir WPF :
Visual Studio 'da proje ayarlarını değiştirerek, Win32 projenizi yönetilen kodu (/clr) çağırmak üzere etkinleştirin.
Ayrı bir WPF Page DLL 'de oluşturun.
Bunu WPF Page içine koyun HwndSource .
HWND 'yi daha büyük Win32 uygulamasına nereye yerleştireceğinize karar vermek için kullanın
clr
İlk adım, bu yönetilmeyen Win32 projesini yönetilen kodu çağıralebilecek birine dönüştürmek olur. Kullanmak istediğiniz gerekli dll 'Lere bağlanacak/clr derleyici seçeneğini kullanın ve ana yöntemi ile kullanmak üzere ayarlayın WPF .
C++ projesi içinde yönetilen kodun kullanımını etkinleştirmek için: Win32clock projesine sağ tıklayın ve Özellikler' i seçin. Genel Özellik sayfasında (varsayılan), ortak dil çalışma zamanı desteğini olarak değiştirin /clr .
Ardından, için gereken dll 'lere başvuruları ekleyin WPF : PresentationCore.dll, PresentationFramework.dll, System.dll, WindowsBase.dll, UIAutomationProvider.dll ve UIAutomationTypes.dll. (Aşağıdaki yönergelerde, işletim sisteminin C: Drive üzerinde yüklü olduğu varsayılır.)
Win32clock projesi öğesine sağ tıklayın ve Başvurular...' ı seçin ve bu iletişim kutusunun içinde:
Win32clock projesi öğesine sağ tıklayın ve başvurular ' ı seçin. ...
Yeni Başvuru Ekle' ye tıklayın, araştır sekmesine tıklayın, C:\Program files\reference Assemblies\Microsoft\Framework\v3.0\PresentationCore.dll girin ve Tamam ' a tıklayın.
PresentationFramework.dll için yineleyin: C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\PresentationFramework.dll.
WindowsBase.dll için yineleyin: C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll.
UIAutomationTypes.dll için yineleyin: C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationTypes.dll.
UIAutomationProvider.dll için yineleyin: C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\UIAutomationProvider.dll.
Yeni Başvuru Ekle' ye tıklayın, System.dll öğesini seçin ve Tamam' a tıklayın.
Başvuru eklemek için win32clock Özellik Sayfalarından çıkmak üzere Tamam ' a tıklayın.
Son olarak, öğesini STAThreadAttribute _tWinMain ile kullanmak için yöntemine ekleyin WPF :
[System::STAThreadAttribute]
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
Bu öznitelik, ortak dil çalışma zamanına (CLR) bileşen nesne modeli (COM) başlattığında, WPF (ve Windows Forms) için gerekli olan tek bir iş parçacıklı grup modeli (STA) kullanması gerektiğini söyler.
Windows Presentation Framework Oluştur sayfası
Ardından, öğesini tanımlayan bir DLL oluşturursunuz WPF Page . WPF Page Tek başına uygulama olarak oluşturmak ve bölümü bu şekilde yazmak ve hata ayıklamak genellikle en kolay yöntemdir WPF . Bu proje tamamlandığında, projeye sağ tıklayıp Özellikler' e tıklayıp uygulamaya giderek ve çıkış türünü Windows sınıf kitaplığı olarak değiştirerek dll 'ye açılabilir.
WPFDLL projesi daha sonra Win32 projesiyle birleştirilebilir (iki proje içeren bir çözüm) – çözüme sağ tıklayın, var olan projeyi add' ı seçin.
Win32 projesinden bu DLL 'yi kullanmak için WPF bir başvuru eklemeniz gerekir:
Win32clock projesi öğesine sağ tıklayın ve başvurular ' ı seçin. ...
Yeni Başvuru Ekle' ye tıklayın.
Projeler sekmesine tıklayın. WPFClock ' ı seçin, Tamam ' a tıklayın.
Başvuru eklemek için win32clock Özellik Sayfalarından çıkmak üzere Tamam ' a tıklayın.
HwndSource
Ardından, HwndSource WPF Page bir HWND gibi görünmesini sağlamak için kullanırsınız. Bu kod bloğunu bir C++ dosyasına eklersiniz:
namespace ManagedCode
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Media;
HWND GetHwnd(HWND parent, int x, int y, int width, int height) {
HwndSource^ source = gcnew HwndSource(
0, // class style
WS_VISIBLE | WS_CHILD, // style
0, // exstyle
x, y, width, height,
"hi", // NAME
IntPtr(parent) // parent window
);
UIElement^ page = gcnew WPFClock::Clock();
source->RootVisual = page;
return (HWND) source->Handle.ToPointer();
}
}
}
Bu, bir açıklama kullanan uzun bir kod parçasıdır. İlk bölüm çeşitli yan tümcelerdir, böylece tüm çağrıları tamamen nitelemeniz gerekmez:
namespace ManagedCode
{
using namespace System;
using namespace System::Windows;
using namespace System::Windows::Interop;
using namespace System::Windows::Media;
Ardından, içeriği oluşturan bir işlev tanımlar WPF , etrafına bir ekler HwndSource ve HWND 'yi döndürür:
HWND GetHwnd(HWND parent, int x, int y, int width, int height) {
İlk HwndSource olarak, parametreleri CreateWindow 'unkine benzer olan bir oluşturun:
HwndSource^ source = gcnew HwndSource(
0, // class style
WS_VISIBLE | WS_CHILD, // style
0, // exstyle
x, y, width, height,
"hi", // NAME
IntPtr(parent) // parent window
);
Ardından, WPF yapıcısını çağırarak içerik sınıfını oluşturursunuz:
UIElement^ page = gcnew WPFClock::Clock();
Daha sonra bu sayfayı öğesine bağlayabilirsiniz HwndSource :
source->RootVisual = page;
Son satırda, için HWND 'yi geri döndürün HwndSource :
return (HWND) source->Handle.ToPointer();
HWND 'yi konumlandırma
Saati içeren bir HWND 'ye sahip olduğunuza göre WPF , bu HWND 'Yi Win32 iletişim kutusunun içine koymanız gerekir. Yalnızca HWND 'yi nereye koyabileceğinizi biliyorsanız, bu boyutu ve konumu GetHwnd daha önce tanımladığınız işleve geçitirsiniz. Ancak, iletişim kutusunu tanımlamak için bir kaynak dosyası kullandınız, bu nedenle bir HWND NDS 'nin nerede konumlandığını tam olarak unutmayın. Visual Studio iletişim düzenleyicisini, saatin gitmesini istediğiniz yere bir Win32 STATIK denetimi yerleştirmek için kullanabilirsiniz ("saati buraya ekle") ve bunu kullanarak WPF saati konumlandırabilirsiniz.
WM_INITDIALOG işlebileceğiniz yerlerde, GetDlgItem statik yer tutucu IÇIN HWND 'yi almak için kullanırsınız:
HWND placeholder = GetDlgItem(hDlg, IDC_CLOCK);
Daha sonra bu yer tutucunun STATIK boyutunu ve konumunu hesaplayabilirsiniz, WPF Bu sayede saati ilgili yere koyabilirsiniz:
Dikdörtgen dikdörtgen;
GetWindowRect(placeholder, &rectangle);
int width = rectangle.right - rectangle.left;
int height = rectangle.bottom - rectangle.top;
POINT point;
point.x = rectangle.left;
point.y = rectangle.top;
result = MapWindowPoints(NULL, hDlg, &point, 1);
Sonra STATIK yer tutucuyu gizlemeniz gerekir:
ShowWindow(placeholder, SW_HIDE);
Ve WPF Bu konumdaki saat HWND 'yi oluşturun:
HWND clock = ManagedCode::GetHwnd(hDlg, point.x, point.y, width, height);
Öğreticiyi ilginç hale getirmek ve gerçek bir saat üretmek için WPF WPF Bu noktada saat denetimi oluşturmanız gerekecektir. Arka plan kod içinde yalnızca birkaç olay işleyicileriyle bu şekilde biçimlendirme yapabilirsiniz. Bu öğretici birlikte çalışabilirlik ile ilgili olduğundan ve denetim tasarımı hakkında olmadığından, saat için tüm kod WPF burada bir kod bloğu olarak sağlanır. Denetimin görünümünü ve işlevselliğini değiştirmek için bu kodla denemeler yapın.
Biçimlendirme şu şekildedir:
<Page x:Class="WPFClock.Clock"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Grid>
<Grid.Background>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="#fcfcfe" Offset="0" />
<GradientStop Color="#f6f4f0" Offset="1.0" />
</LinearGradientBrush>
</Grid.Background>
<Grid Name="PodClock" HorizontalAlignment="Center" VerticalAlignment="Center">
<Grid.Resources>
<Storyboard x:Key="sb">
<DoubleAnimation From="0" To="360" Duration="12:00:00" RepeatBehavior="Forever"
Storyboard.TargetName="HourHand"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
<DoubleAnimation From="0" To="360" Duration="01:00:00" RepeatBehavior="Forever"
Storyboard.TargetName="MinuteHand"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
<DoubleAnimation From="0" To="360" Duration="0:1:00" RepeatBehavior="Forever"
Storyboard.TargetName="SecondHand"
Storyboard.TargetProperty="(Rectangle.RenderTransform).(RotateTransform.Angle)"
/>
</Storyboard>
</Grid.Resources>
<Ellipse Width="108" Height="108" StrokeThickness="3">
<Ellipse.Stroke>
<LinearGradientBrush>
<GradientStop Color="LightBlue" Offset="0" />
<GradientStop Color="DarkBlue" Offset="1" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Ellipse VerticalAlignment="Center" HorizontalAlignment="Center" Width="104" Height="104" Fill="LightBlue" StrokeThickness="3">
<Ellipse.Stroke>
<LinearGradientBrush>
<GradientStop Color="DarkBlue" Offset="0" />
<GradientStop Color="LightBlue" Offset="1" />
</LinearGradientBrush>
</Ellipse.Stroke>
</Ellipse>
<Border BorderThickness="1" BorderBrush="Black" Background="White" Margin="20" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextBlock Name="MonthDay" Text="{Binding}"/>
</Border>
<Canvas Width="102" Height="102">
<Ellipse Width="8" Height="8" Fill="Black" Canvas.Top="46" Canvas.Left="46" />
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black" Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="0" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="30" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="60" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black" Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="90" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="120" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="150" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black" Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="180" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="210" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="240" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="48" Fill="Black" Width="4" Height="8">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="270" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="300" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle Canvas.Top="5" Canvas.Left="49" Fill="Black" Width="2" Height="6">
<Rectangle.RenderTransform>
<RotateTransform CenterX="2" CenterY="46" Angle="330" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="HourHand" Canvas.Top="21" Canvas.Left="48"
Fill="Black" Width="4" Height="30">
<Rectangle.RenderTransform>
<RotateTransform x:Name="HourHand2" CenterX="2" CenterY="30" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="MinuteHand" Canvas.Top="6" Canvas.Left="49"
Fill="Black" Width="2" Height="45">
<Rectangle.RenderTransform>
<RotateTransform CenterX="1" CenterY="45" />
</Rectangle.RenderTransform>
</Rectangle>
<Rectangle x:Name="SecondHand" Canvas.Top="4" Canvas.Left="49"
Fill="Red" Width="1" Height="47">
<Rectangle.RenderTransform>
<RotateTransform CenterX="0.5" CenterY="47" />
</Rectangle.RenderTransform>
</Rectangle>
</Canvas>
</Grid>
</Grid>
</Page>
Arka plan kodu aşağıda verilmiştir:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
namespace WPFClock
{
/// <summary>
/// Interaction logic for Clock.xaml
/// </summary>
public partial class Clock : Page
{
private DispatcherTimer _dayTimer;
public Clock()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(Clock_Loaded);
}
void Clock_Loaded(object sender, RoutedEventArgs e) {
// set the datacontext to be today's date
DateTime now = DateTime.Now;
DataContext = now.Day.ToString();
// then set up a timer to fire at the start of tomorrow, so that we can update
// the datacontext
_dayTimer = new DispatcherTimer();
_dayTimer.Interval = new TimeSpan(1, 0, 0, 0) - now.TimeOfDay;
_dayTimer.Tick += new EventHandler(OnDayChange);
_dayTimer.Start();
// finally, seek the timeline, which assumes a beginning at midnight, to the appropriate
// offset
Storyboard sb = (Storyboard)PodClock.FindResource("sb");
sb.Begin(PodClock, HandoffBehavior.SnapshotAndReplace, true);
sb.Seek(PodClock, now.TimeOfDay, TimeSeekOrigin.BeginTime);
}
private void OnDayChange(object sender, EventArgs e)
{
// date has changed, update the datacontext to reflect today's date
DateTime now = DateTime.Now;
DataContext = now.Day.ToString();
_dayTimer.Interval = new TimeSpan(1, 0, 0, 0);
}
}
}
Nihai sonuç şöyle görünür:

Nihai sonucu bu ekran görüntüsünü üreten kodla karşılaştırmak için bkz. Win32 saat karşılıklı çalışma örneği.