الإرشادات التفصيلية: استضافة محتوى WPF في تطبيق Win32

توفر Windows Presentation Foundation (WPF) بيئة منسق لإنشاء تطبيقات. However, when you have a substantial investment in Win32 تعليمات برمجية, it might be more effective إلى إضافة WPF functionality إلى your application rather than rewriting your original تعليمات برمجية. WPFتوفر تقنية مباشرة للاستضافةWPFالمحتويات الموجودة فيWin32نافذة.

هذا البرنامج التعليمي يصف كيفية كتابة نموذج للتطبيق ، استضافة محتوى WPF في نموذج إطار Win32، التي تستضيف محتوي WPF في إطار Win32. يمكنك توسيع هذه العينة لاستضافة أي إطار Win32. لأنها تتضمن عملية خلط التعليمات البرمجية المدارة و غير المدارة, التطبيق مكتوب في C++/CLI.

يشتمل هذا الموضوع على الأقسام التالية.

  • المتطلبات
  • الإجراءات الاساسية
  • تنفيذ التطبيق المضيف
  • تنفيذ صفحة WPF
  • موضوعات ذات صلة

المتطلبات

يفترض هذا البرنامج التعليمي معرفة أساسية ببرمجة WPF و Win32. للحصول على مقدمة لأسس برمجة WPF، راجع الشروع في العمل (WPF). للحصول على مقدمة عن أسس برمجة Win32، يجب مراجعة أي من الكتب المتعددة عن الموضوع ، بشكل خاص برمجة الويندوز بواسطة Charles Petzold.

لأنه يتم تنفيذ النموذج المرفقة مع هذا البرنامج التعليمي في C++/CLI ، يفترض هذا البرنامج التعليمي معرفة استخدام ++C لبرمجة Win32 API بالإضافة إلى فهم برمجة التعليمات البرمجية المدارة. معرفة C++/CLI مفيدة و لكن غير ضرورية.

ملاحظةملاحظة

يتضمن هذا البرنامج التعليمي عدداً من أمثلة التعليمات البرمجية من النموذج المقترن.ومع ذلك، لكى يكون قابل للقراءة، هو لا يتضمن النموذج الكامل للتعليمات البرمجية.للحصول على نموذج التعليمات البرمجية الكامل، راجع نموذج استضافة محتوى WPF في إطار Win32.

الإجراءات الاساسية

يوضح هذا المقطع الإجراء الأساسي الذي تستخدمه لاستضافة محتوى WPF في إطار Win32. توضح المقاطع المتبقية تفاصيل كل خطوة.

المفتاح لاستضافة محتوي WPF على إطار Win32 هو فئة HwndSource. هذه الفئة تلف محتوي WPF في إطار Win32، سامحاً له بان يدمج ب واجهة المستخدم (UI) الخاص بك كإطار تابع. يدمج الأسلوب التالي Win32 و WPF في تطبيق واحد.

  1. تنفيذ محتوي WPF الخاص بك كفئة مدارة.

  2. تنفيذ تطبيق Win32 مع C++/CLI. إذا بدأت بتطبيق موجود و تعليمات برمجية ++C غير مدارة، يمكنك عادةً تمكينه من استدعاء التعليمات البرمجية المدارة بواسطة تغيير إعدادات المشروع الخاصة بك لتتضمن علامة برنامج التحويل البرمجي /clr.

  3. تعيين طراز مؤشر الترابط إلى شقة ترابط واحد (STA).

  4. قم بمعالجة إعلام WM_CREATE في إجراء الإطار الخاص بك ثم قم بما يلي:

    1. إنشاء كائن HwndSource جديد مع إطار الأصل كمعلمة parent.

    2. قم بإنشاء مثيل من فئة محتوي WPF الخاص بك.

    3. قم بتعيين مرجع إلى كائن محتوي WPF إلى خاصية RootVisual من HwndSource.

    4. احصل على HWND للمحتوي. خاصية Handle من كائن HwndSource تحتوي على مؤشر الإطار (HWND). للحصول على HWND التي يمكنك استخدامه في الجزء غير المدار من التطبيق الخاص بك، حول Handle.ToPointer() إلى HWND.

  5. تنفيذ فئة مدارة التي تحتوي على حقل ثابت للاحتفاظ بمرجع إلى المحتوي WPF الخاص بك. تسمح هذه الفئة لك بالحصول على مرجع إلى محتوي WPF من التعليمات البرمجية Win32 الخاصة بك.

  6. قم بتعيين محتوي WPF إلى حقل ثابت.

  7. تلقي إعلامات من محتوي WPF عن طريق إرفاق معالج إلى واحد أو أكثر من أحداث WPF.

  8. الاتصال مع محتوي WPF باستخدام مرجع المخزن في حقل ثابت لتعيين خصائص و هكذا.

ملاحظةملاحظة

يمكنك أيضاً استخدام Extensible Application Markup Language (XAML) لتنفيذ محتوي WPF الخاص بك.مع ذلك، سيجب عليك ترجمته بشكل منفصل كـمكتبة الارتباط الديناميكي (DLL) و الإشارة إلى أن DLL من تطبيق Win32 الخاص بك.يشبه باقي الإجراء ذلك الذي ورد ذكره أعلاه.

تنفيذ التطبيق المضيف

يصف هذا المقطع كيفية استضافة محتوي WPF في تطبيق Win32 الأساسي. يتم تنفيذ المحتوى نفسه في C++/CLI كفئة مدارة. على الجزء الأكثر, هو برمجة WPF مباشرة. وستتم مناقشة الأوجه الهامة من تطبيق المحتوى في تطبيق محتوى WPF.

  • التطبيق الأساسي

  • استضافة محتوى WPF

  • الاحتفاظ بمرجع إلى محتوى WPF

  • الاتصال مع محتوى WPF

التطبيق الأساسي

نقطة البداية للتطبيق المضيف هي إنشاء قالب Microsoft Visual Studio 2005.

  1. افتح Visual Studio 2005, و حدد مشروع جديد من قائمة ملف.

  2. حدد Win32 من القائمة من أنواع المشروع ++Visual C. إذا كانت اللغة الافتراضية لديك ليست ++C، ستجد أنواع المشروع هذه ضمن لغات أخرى.

  3. حدد قالب Project Win32 , قم بتعيين اسم إلى المشروع ثم انقر فوق موافق لتشغيل معالج التطبيق Win32.

  4. اقبل بالإعدادات الافتراضية للمعالج و انقر فوق إنهاء لبدء المشروع.

القالب ينشأ تطبيق Win32 أساسي، بما في ذلك:

  • نقطة دخول للتطبيق.

  • إطار، مع إجراء إطار مقترن (WndProc).

  • قائمة ذات عناوين ملف و تعليمات. قائمة ملف لديها عنصر إنهاء الذي يقوم بإغلاق التطبيق. قائمة تعليمات لديها عنصر حول الذي يقوم بتشغيل مربع حوار بسيط.

قبل البدء في كتابة التعليمات البرمجية لاستضافة محتوي WPF, تحتاج إلى إجراء تعديلين للقالب الأساسي.

الأول هو ترجمة المشروع كتعليمات برمجية مدارة. بشكل افتراضي، يتم ترجمة المشروع كتعليمات برمجية غير مدارة. مع ذلك، لأن WPF يتم تنفيذه في تعليمات برمجية مُدارة، يجب أن يتم ترجمة المشروع وفقاً لذلك.

  1. انقر فوق اسم المشروع بالزر الأيمن في مستكشف الحلول ثم حدد خصائص من قائمة السياق لبدء تشغيل مربع الحوار صفحات الخصائص.

  2. حدد خصائص التكوين من طريقة عرض الشجرة في الجزء الأيسر.

  3. حدد دعم وقت تشغيل اللغة العامة من قائمة افتراضيات المشروع في الجزء الأيسر.

  4. حدد دعم وقت تشغيل اللغة العامة" (/مسح) من مربع القائمة المنسدلة.

ملاحظةملاحظة

تسمح علامة برنامج التحويل البرمجي لك باستخدام التعليمات البرمجية المدارة في التطبيق الخاص بك و لكن لا يزال سيتم ترجمة التعليمات البرمجية غير المُدارة الخاصة بك كما قبل.

WPF يستخدم طراز مؤشر ترابط شقة ترابط واحد (STA). للعمل بشكل صحيح مع تعليمات برمجية محتوي WPF، يجب عليك تعيين طراز مؤشر الترابط للتطبيق إلى STA من خلال تطبيق سمة إلى نقطة الإدخال.

[System::STAThreadAttribute] //Needs to be an STA thread to play nicely with WPF
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{

استضافة محتوى WPF

محتوي WPF هو تطبيق إدخال عنوان بسيط. هو يتكون من عدة عناصر تحكم TextBox لأخذ اسم المستخدم و العنوان و هكذا. يوجد أيضاً عنصري تحكم Button، موافق و إلغاء الأمر. عندما ينقر المستخدم فوق موافق ، معالج الحدث Click الخاص بالزر يقوم بتجميع البيانات من عناصر تحكم TextBox, و يعيّنها إلى الخصائص المطابقة و يقوم بإصدار حدث مخصص ,OnButtonClicked. عندما يقوم المستخدم بالنقر فوق إلغاء الأمر , المعالج يرفع ببساطة OnButtonClicked. كائن وسيطة الحدث ل OnButtonClicked يحتوي على حقل منطقية الذي يشير إلى أي زر تم النقر فوقه.

التعليمات البرمجية لاستضافة محتوي WPF يتم تنفيذها في معالج لإعلام WM_CREATE على إطار المضيف.

case WM_CREATE :
  GetClientRect(hWnd, &rect);
  wpfHwnd = GetHwnd(hWnd, rect.right-375, 0, 375, 250);
  CreateDataDisplay(hWnd, 275, rect.right-375, 375);
  CreateRadioButtons(hWnd);
break;

أسلوب GetHwnd يأخذ معلومات الحجم و الموضع بالإضافة إلى أن إطار الأصل يقوم بمعالجة و إرجاع مؤشر الإطار لمحتوي WPF الذي تمت استضافته.

ملاحظةملاحظة

لا يمكنك استخدام موجه #using لمساحة اسم System::Windows::Interop.يؤدي القيام بذلك ينشئ تضارب اسم بين MSGبنية في مساحة الاسم التي و بنية MSG التي تم تعريفها في winuser.h.You must instead use fully-qualified names إلى access the المحتويات of that namespace.

HWND GetHwnd(HWND parent, int x, int y, int width, int height)
{
    System::Windows::Interop::HwndSourceParameters^ sourceParams = gcnew System::Windows::Interop::HwndSourceParameters(
    "hi" // NAME
    );
    sourceParams->PositionX = x;
    sourceParams->PositionY = y;
    sourceParams->Height = height;
    sourceParams->Width = width;
    sourceParams->ParentWindow = IntPtr(parent);
    sourceParams->WindowStyle = WS_VISIBLE | WS_CHILD; // style
    System::Windows::Interop::HwndSource^ source = gcnew System::Windows::Interop::HwndSource(*sourceParams);
    WPFPage ^myPage = gcnew WPFPage(width, height);
    //Assign a reference to the WPF page and a set of UI properties to a set of static properties in a class
    //that is designed for that purpose.
    WPFPageHost::hostedPage = myPage;
    WPFPageHost::initBackBrush = myPage->Background;
    WPFPageHost::initFontFamily = myPage->DefaultFontFamily;
    WPFPageHost::initFontSize = myPage->DefaultFontSize;
    WPFPageHost::initFontStyle = myPage->DefaultFontStyle;
    WPFPageHost::initFontWeight = myPage->DefaultFontWeight;
    WPFPageHost::initForeBrush = myPage->DefaultForeBrush;
    myPage->OnButtonClicked += gcnew WPFPage::ButtonClickHandler(WPFButtonClicked);
    source->RootVisual = myPage;
    return (HWND) source->Handle.ToPointer();
}

لا يمكنك استضافة محتوي WPF مباشرة في إطار التطبيق الخاص بك. بدلاً من ذلك، تقوم أولا بإنشاء كائن HwndSource ليلف محتوي WPF. هذا الكائن هو بشكل أساسي إطار تم تصميمه لاستضافة محتوي WPF. انك تقوم باستضافة كائن HwndSource في إطار الأصل عن طريق إنشائه كتابع من إطار Win32 الذي هو جزء من التطبيق الخاص بك. معلمات الدالة الإنشائية HwndSource تحتوي نفس المعلومات التي ستقوم بتمريرها إلى CreateWindow حينما تنشئ إطار تابع Win32.

بعد ذلك تقوم بإنشاء مثيل من كائن محتوي WPF. في هذه الحالة، محتوي WPF يتم تطبيقه كفئة منفصلة, WPFPage باستخدام C++/CLI. قد تقوم أيضاً بتطبيق محتوي WPF مع XAML. مع ذلك، للقيام بذلك تحتاج إلى إعداد مشروع منفصل و إنشاء محتوي WPF مثل DLL. يمكنك إضافة إلى ذلك DLL إلى المشروع الخاص بك و استخدام هذا المرجع لإنشاء مثيل من محتوي WPF.

تقوم بعرض محتوي WPFفي الإطار التابع بواسطة تعيين مرجع إلى محتوى WPF إلى خاصية RootVisual من HwndSource.

يصل السطر التالي من التعليمات البرمجية معالج الحدث، WPFButtonClicked، إلى محتوي WPF حدث OnButtonClicked. يتم استدعاء معالج هذا عندما يقوم المستخدم بالنقر فوق زر موافق أو إلغاء الأمر. راجع communicating_with_the_WPF content لمناقشة إضافية لهذا المعالج للحدث.

السطر الأخير من التعليمات البرمجية الموضح يقوم بإرجاع مؤشر الإطار (HWND) المقترن مع كائن HwndSource. يمكنك استخدام هذا المؤشر من التعليمات البرمجية Win32 الخاصة بك لإرسال رسائل إلى الإطار المستضاف على الرغم من أنه النموذج لا يقوم بذلك. كائن HwndSource يرفع حدث كل مرة يتلقى فيها الرسالة. لمعالجة الرسائل ، قم باستدعاء أسلوب AddHook لإرفاق معالج رسالة و ثم معالجة الرسائل الموجودة في هذا المعالج.

الاحتفاظ بمرجع إلى محتوى WPF

للعديد من التطبيقات ستحتاج إلى الاتصال مع المحتوي WPF فيما بعد. على سبيل المثال، قد تحتاج إلى تعديل خصائص محتوي WPF أو ربما من كائن HwndSource استضافة محتوي WPF مختلف. للقيام بذلك، تحتاج مرجع إلى كائن HwndSource أو محتوي WPF. كائن HwndSourceو محتوي WPF المقترن به يظلوا في الذاكرة حتى تقوم بإتلاف مؤشر الإطار. ومع ذلك، المتغير الذي تعيينه إلى كائن HwndSource سوف ينتقل خارج النطاق بمجرد العودة من إجراء الإطار. الطريقة المألوفة لمعالجة هذه المشكلة مع تطبيقات Win32 هو باستخدام متغير عمومي أو ثابت. لسوء الحظ، لا يمكنك تعيين كائن مُدار إلى هذه الأنواع من المتغيرات. يمكنك تعيين مؤشر الإطار المقترن مع كائن HwndSource إلى متغير عمومي أو ثابت إلا أن ذلك لا يوفر الوصول إلى الكائن نفسه.

حل هذه المشكلة الأبسط هو بتنفيذ فئة مدارة التي تحتوي على مجموعة من الحقول الثابتة للاحتفاظ بالمراجع إلى أية كائنات مدارة تريد الوصول إليها. يستخدم النموذج فئة WPFPageHost للاحتفاظ بمرجع إلى محتوي WPF، بالإضافة إلى القيم الأولية من عدد من الخصائص الخاصة التي قد يتم تغييرها لاحقاً بواسطة المستخدم. يتم تعريف هذا في الرأس.

public ref class WPFPageHost
{
public:
  WPFPageHost();
  static WPFPage^ hostedPage;
  //initial property settings
  static System::Windows::Media::Brush^ initBackBrush;
  static System::Windows::Media::Brush^ initForeBrush;
  static System::Windows::Media::FontFamily^ initFontFamily;
  static System::Windows::FontStyle initFontStyle;
  static System::Windows::FontWeight initFontWeight;
  static double initFontSize;
};

الجزء الأخير من دالة GetHwnd تقوم بتعيين قيم إلى تلك الحقول لاستخدامها لاحقاً بينما لا يزال myPage في النطاق.

الاتصال مع محتوى WPF

هناك نوعان من الاتصال مع محتوي WPF. يتلقى التطبيق المعلومات من محتوي WPF عند قيام المستخدم بالنقر فوق أزرار موافق أو إلغاء الأمر. التطبيق يحتوي أيضاً على واجهة المستخدم الذي يسمح للمستخدم بتغيير خصائص محتوي WPF المتعددة مثل لون الخلفية أو حجم الخط الافتراضي.

كما هو مذكور أعلاه, عند قيام المستخدم بالنقر فوق أي زر منهم يقوم محتوي WPF برفع حدث OnButtonClicked. يقوم التطبيق بإرفاق معالج لهذا الحدث لتلقي هذه الإعلامات. إذا تم النقر فوق زر موافق, يحصل المعالج على معلومات المستخدم من محتوي WPF و يعرضها في مجموعة من عناصر التحكم الثابتة.

void WPFButtonClicked(Object ^sender, MyPageEventArgs ^args)
{
    if(args->IsOK) //display data if OK button was clicked
    {
        WPFPage ^myPage = WPFPageHost::hostedPage;
        LPCWSTR userName = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Name: " + myPage->EnteredName).ToPointer();
        SetWindowText(nameLabel, userName);
        LPCWSTR userAddress = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Address: " + myPage->EnteredAddress).ToPointer();
        SetWindowText(addressLabel, userAddress);
        LPCWSTR userCity = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("City: " + myPage->EnteredCity).ToPointer();
        SetWindowText(cityLabel, userCity);
        LPCWSTR userState = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("State: " + myPage->EnteredState).ToPointer();
        SetWindowText(stateLabel, userState);
        LPCWSTR userZip = (LPCWSTR) InteropServices::Marshal::StringToHGlobalAuto("Zip: " + myPage->EnteredZip).ToPointer();
        SetWindowText(zipLabel, userZip);
    }
    else
    {
        SetWindowText(nameLabel, L"Name: ");
        SetWindowText(addressLabel, L"Address: ");
        SetWindowText(cityLabel, L"City: ");
        SetWindowText(stateLabel, L"State: ");
        SetWindowText(zipLabel, L"Zip: ");
    }
}

يتلقي المعالج كائن وسيطة حدث مخصص من محتوي WPF، MyPageEventArgs. خاصية IsOK للكائن يتم تعيينها إلى true إذا تم النقر فوق زر موافق، و إلى false إذا تم النقر فوق زر إلغاء الأمر .

إذا تم النقر فوق زر موافق, يحصل المعالج على مرجع إلى محتوي WPF من فئة الحاوية. ثم يقوم بتجميع معلومات المستخدم التي تتضمنها خصائص محتوي WPF المقترن و يستخدم عناصر تحكم ثابتة لعرض المعلومات على الإطار الأصل. لأن بيانات محتوي WPF هو في شكل سلسلة مدارة, بجب أن يتم تنظيمه و إرساله للاستخدام من قبل عنصر تحكم Win32. إذا تم النقر فوق زر إلغاء الأمر, يمسح المعالج البيانات من عناصر التحكم الثابتة.

التطبيق واجهة المستخدم يوفر مجموعة من أزرار الخيارات التي تسمح للمستخدم بتعديل لون الخلفية من محتوي WPF، و عدة خصائص ذات الصلة بالخطوط. المثال التالي هو مقتطف من إجراء إطار التطبيق (WndProc) و معالج الرسالة الخاص به الذي يقوم بتعيين خصائص مختلفة على رسائل مختلفة بما في ذلك لون الخلفية. الأخرى متشابهة و لا يتم توضيحها. راجع النموذج الكامل للتفاصيل و السياق.

case WM_COMMAND:
  wmId    = LOWORD(wParam);
  wmEvent = HIWORD(wParam);

  switch (wmId)
  {
  //Menu selections
    case IDM_ABOUT:
      DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
    break;
    case IDM_EXIT:
      DestroyWindow(hWnd);
    break;
    //RadioButtons
    case IDC_ORIGINALBACKGROUND :
      WPFPageHost::hostedPage->Background = WPFPageHost::initBackBrush;
    break;
    case IDC_LIGHTGREENBACKGROUND :
      WPFPageHost::hostedPage->Background = gcnew SolidColorBrush(Colors::LightGreen);
    break;
    case IDC_LIGHTSALMONBACKGROUND :
      WPFPageHost::hostedPage->Background = gcnew SolidColorBrush(Colors::LightSalmon);
    break;

لتعيين لون الخلفية، احصل على مرجع إلى محتوي WPF (hostedPage) من WPFPageHost و قم بتعيين خاصية لون الخلفية إلى اللون المناسب. يستخدم النموذج ثلاثة خيارات لللون: اللون الأصلى, أخضر فاتح أو salmon فاتح. يتم تخزين لون الخلفية الأصلي كحقل ثابت في فئة WPFPageHost. إذا كنت تريد تعيين الاثنين الآخران، قم بإنشاء كائن SolidColorBrush جديد و تمرير للمُنشئ قيمة الألوان الثابتة من كائن Colors.

تنفيذ صفحة WPF

يمكنك استضافة و استخدام محتوي WPF دون أي معرفة عن التطبيق الفعلي. إذا تم حزم محتوي WPF في DLL منفصل، فإنه قد يكون تم إنشاؤها في أي لغة وقت تشغيل اللغة العامة (CLR). يكون التالي إرشادات تفصيلية مختصرة لتنفيذ C++/CLI المستخدم في النموذج. يشتمل هذا القسم على الأقسام الفرعية التالية.

  • تخطيط

  • إرجاع البيانات إلى الإطار المضيف

  • إعداد خصائص WPF

تخطيط

عناصر واجهة المستخدم في محتوي WPF يتكون من خمسة عناصر تحكم TextBox، مع عناصر تحكم Label المقترنة: اسم، عنوان, المدينة، حالة و البريدي. يوجد أيضاً عنصري تحكم Button، موافق و إلغاء الأمر.

محتوي WPF يتم تنفيذه في فئة WPFPage. تتم معالجة التخطيط مع عنصر تخطيط Grid. ترث الفئة من Grid، الذي يجعله بشكل فعال عنصر جذر محتوي WPF.

مُنشئ محتوي WPF يأخذ العرض و الارتفاع المطلوب و يقوم بتغيير حجم Grid وفقاً لذلك. ثم يعرف التخطيط الأساسي عن طريق إنشاء مجموعة من كائنات ColumnDefinition و RowDefinition و إضافتها إلى كائن Grid الأساسي, مجموعات ColumnDefinitions و RowDefinitions، على التوالي. وهذا يحدد شبكة من خمسة صفوف و سبعة أعمدة ذات الأبعاد المحددة بواسطة محتويات الخلايا.

WPFPage::WPFPage(int allottedWidth, int allotedHeight)
{
  array<ColumnDefinition ^> ^ columnDef = gcnew array<ColumnDefinition ^> (4);
  array<RowDefinition ^> ^ rowDef = gcnew array<RowDefinition ^> (6);

  this->Height = allotedHeight;
  this->Width = allottedWidth;
  this->Background = gcnew SolidColorBrush(Colors::LightGray);

  //Set up the Grid's row and column definitions
  for(int i=0; i<4; i++)
  {
    columnDef[i] = gcnew ColumnDefinition();
    columnDef[i]->Width = GridLength(1, GridUnitType::Auto);
    this->ColumnDefinitions->Add(columnDef[i]);
  }
  for(int i=0; i<6; i++)
  {
    rowDef[i] = gcnew RowDefinition();
    rowDef[i]->Height = GridLength(1, GridUnitType::Auto);
    this->RowDefinitions->Add(rowDef[i]);
  }

بعد ذلك، يضيف المُنشئ عناصر واجهة المستخدم إلى Grid. العنصر الأول هو نص العنوان و هو عنصر تحكم Label الذي يتم وضعه في وسط الصف الأول من الشبكة.

//Add the title
titleText = gcnew Label();
titleText->Content = "Simple WPF Control";
titleText->HorizontalAlignment = System::Windows::HorizontalAlignment::Center;
titleText->Margin = Thickness(10, 5, 10, 0);
titleText->FontWeight = FontWeights::Bold;
titleText->FontSize = 14;
Grid::SetColumn(titleText, 0);
Grid::SetRow(titleText, 0);
Grid::SetColumnSpan(titleText, 4);
this->Children->Add(titleText);

يحتوي الصف التالي على عنصر تحكم عنصر تحكم اسم Label و عنصر تحكم TextBox المقترن به. لأن نفس التعليمات البرمجية تُستخدم لكل زوج تسمية/مربع نص,يتم وضعها في زوج من الأساليب الخاصة و استخدامها لكافة أزواج تسمية/مربع النص الخمسة. الأساليب تقوم بإنشاء عنصر التحكم المناسب و استدعاء من فئة Grid الأساليب الثابتة SetColumn و SetRow لوضع عناصر التحكم في الخلية المناسبة. بعد إنشاء عنصر التحكم, العينة تستدعي أسلوب Add على خاصية Children من Grid لإضافة عنصر التحكم إلى الشبكة. التعليمات البرمجية لإضافة أزواج تسمية/مربع النص المتبقية متشابهة. راجع نموذج التعليمات البرمجية للحصول على التفاصيل.

//Add the Name Label and TextBox
nameLabel = CreateLabel(0, 1, "Name");
this->Children->Add(nameLabel);
nameTextBox = CreateTextBox(1, 1, 3);
this->Children->Add(nameTextBox);

تنفيذ الأسلوبين يتم كما يلي:

Label ^WPFPage::CreateLabel(int column, int row, String ^ text)
{
  Label ^ newLabel = gcnew Label();
  newLabel->Content = text;
  newLabel->Margin = Thickness(10, 5, 10, 0);
  newLabel->FontWeight = FontWeights::Normal;
  newLabel->FontSize = 12;
  Grid::SetColumn(newLabel, column);
  Grid::SetRow(newLabel, row);
  return newLabel;
}
TextBox ^WPFPage::CreateTextBox(int column, int row, int span)
{
  TextBox ^newTextBox = gcnew TextBox();
  newTextBox->Margin = Thickness(10, 5, 10, 0);
  Grid::SetColumn(newTextBox, column);
  Grid::SetRow(newTextBox, row);
  Grid::SetColumnSpan(newTextBox, span);
  return newTextBox;
}

أخيراً، قم بإضافة أزرار موافق و إلغاء الأمر العينة و إرفاق معالج الحدث إلى الأحداث Clickالخاصة بهم.

//Add the Buttons and atttach event handlers
okButton = CreateButton(0, 5, "OK");
cancelButton = CreateButton(1, 5, "Cancel");
this->Children->Add(okButton);
this->Children->Add(cancelButton);
okButton->Click += gcnew RoutedEventHandler(this, &WPFPage::ButtonClicked);
cancelButton->Click += gcnew RoutedEventHandler(this, &WPFPage::ButtonClicked);

إرجاع البيانات إلى الإطار المضيف

عند النقر على أي زر منهم ، يتم رفع حدث Click الخاص به. الإطار المضيف قد يرفق ببساطة معالجات لهذه الأحداث ثم الحصول على البيانات مباشرة من عناصر تحكم TextBox. يستخدم النموذج أسلوب أقل مباشرة إلى حد ما. هو يعالج Click داخل محتوي WPF و يقوم برفع حدث مخصص OnButtonClicked، لإعلام محتوي WPF. هذا يسمح لمحتوي WPF أن يتحقق من صحة المعلمة قبل إعلام المضيف. يحصل المعالج على النص من عناصر تحكم TextBox و يُعينها إلى الخصائص العمومية من حيث يمكن للمضيف استرداد المعلومات.

تعريف الحدث في WPFPage.h:

public:
  delegate void ButtonClickHandler(Object ^, MyPageEventArgs ^);
  WPFPage();
  WPFPage(int height, int width);
  event ButtonClickHandler ^OnButtonClicked;

معالج حدث Click في WPFPage.cpp:

void WPFPage::ButtonClicked(Object ^sender, RoutedEventArgs ^args)
{

  //TODO: validate input data
  bool okClicked = true;
  if(sender == cancelButton)
    okClicked = false;
  EnteredName = nameTextBox->Text;
  EnteredAddress = addressTextBox->Text;
  EnteredCity = cityTextBox->Text;
  EnteredState = stateTextBox->Text;
  EnteredZip = zipTextBox->Text;
  OnButtonClicked(this, gcnew MyPageEventArgs(okClicked));
}

إعداد خصائص WPF

مضيف Win32 يسمح للمستخدم بتغيير العديد من خصائص محتوي WPF. من جانب Win32، هو ببساطة مسألة تغيير خصائص. التطبيق في فئة محتوي WPF إلى حد ما أكثر تعقيداً لعدم وجود خاصية عمومية واحدة تتحكم في خطوط كافة عناصر التحكم. بدلاً من ذلك، الخاصية المناسبة لكل عنصر تحكم يتم تغييرها في موصلين مجموعة الخصائص. المثال التالي يوضح التعليمات البرمجية لخاصية DefaultFontFamily. تعيين الخاصية يقوم باستدعاء أسلوب خاص الذي بدوره يقوم بتعيين خصائص FontFamily إلى عناصر التحكم المتنوعة.

من WPFPage.h:

property FontFamily^ DefaultFontFamily
{
  FontFamily^ get() {return _defaultFontFamily;}
  void set(FontFamily^ value) {SetFontFamily(value);}
};

من WPFPage.cpp:

void WPFPage::SetFontFamily(FontFamily^ newFontFamily)
{
  _defaultFontFamily = newFontFamily;
  titleText->FontFamily = newFontFamily;
  nameLabel->FontFamily = newFontFamily;
  addressLabel->FontFamily = newFontFamily;
  cityLabel->FontFamily = newFontFamily;
  stateLabel->FontFamily = newFontFamily;
  zipLabel->FontFamily = newFontFamily;
}

راجع أيضًا:

المرجع

HwndSource

المبادئ

نظرة عامة حول التشغيل التفاعلي ل Win32 و WPF