مشاركة عبر


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

توفر Windows Presentation Foundation (WPF) بيئة منسق لإنشاء تطبيقات. ومع ذلك، إذا كان لديك اﻻستثمار حقيقية في Win32التعليمة البرمجية، قد يكون أكثر فعالية إلى إعادة استخدامها على الأقل بعض تلك التعليمة البرمجية في الخاص بك WPFتطبيق بدلاً من كتابتها بشكل كامل. WPFيوفر وسيلة مباشرة للاستضافةWin32نافذة, on aWPFالصفحة.

يأخذك هذا البرنامج التعليمي عبر تطبيق ، استضافة عنصر تحكم من مربع القائمة Win32 في نموذج & ، والذي يستضيف Win32 قائمة مربع عنصر التحكم. يمكن توسيع هذا الإجراء العامة لاستضافة أي Win32 الإطار.

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

  • المتطلبات
  • الإجراءات الاساسية
  • تنفيذ تخطيط الصفحة
  • تطبيق على فئة المضيف التحكم Microsoft Win32
  • استضافة التحكم على صفحة
  • تنفيذ الاتصال بين التحكم وعلى الصفحة
  • موضوعات ذات صلة

المتطلبات

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

لأنه يتم تنفيذ نموذج مرفقة مع هذا البرنامج التعليمي في #C ، فإنه يستخدم خدمات استدعاء النظام الأساسي (PInvoke) للوصول لـWin32API. معرفة PInvoke مفيدة و لكن غير ضرورية.

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

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

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

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

إجراء أخذ الصور الأساسي هو:

  1. تنفيذ WPF صفحة لاستضافة النافذة. أسلوب واحد وهو إنشاء Border عنصر لحجز جزء من الصفحة لاستضافتها.

  2. تطبيق فئة لاستضافة عنصر التحكم التي ترث من HwndHost.

  3. في تلك الفئة تجاوز HwndHost عضو الفئة BuildWindowCore.

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

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

  6. معالجة الرسائل المحددة إرسال الإطار المضيف مثل إعلامات من عناصر التحكم التابعة. يوجد طريقتان لتنفيذ ذلك.

    • إذا كنت تفضل مؤشر معالجة الرسائل في الفصل الدراسي استضافة ، تجاوز WndProc أسلوب HwndHost فئة.

    • إذا كنت تفضل ان يكون WPF معالجة الرسائل ، معالجة HwndHost فئة MessageHook الحدث في التعليمات البرمجية-الخلف. هذا الحدث يحدث كل رسالة التي يتم تلقيها من قبل استضافتها النافذة. إذا قمت باختيار هذا الخيار، يجب أن تقوم بمنع استمرار WndProc ، ولكن تحتاج فقط تطبيق الحد الأدنى.

  7. تمنع ال DestroyWindowCore و WndProc أساليب HwndHost. يجب أن تتجاوز هذه الطرق لاستيفاء HwndHost العقد ولكن قد تحتاج فقط لتوفير تطبيق الحد الأدنى.

  8. في التعليمات البرمجية - خلف ملف إنشاء مثيل من عنصر التحكم استضافة فئة وجعله تابعة Border عنصر مخصص الذى يهدف لاستضافة الإطار.

  9. الاتصال مع إطار مستضاف بواسطة إرسال Microsoft Windows رسائل ورسائل معالجة من به الإطارات التابعة مثل للإعلامات المرسلة عن طريق عناصر التحكم.

تنفيذ تخطيط الصفحة

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

رمز لتنفيذ هذا التخطيط هو بسيط جدا. العنصر الجذر DockPanel له التابعة بين العناصر. الأولى هي Border العنصر الذي يستضيف مربع قائمة عنصر تحكم. وتحتل مساحة 200x200 في الزاوية اليمنى العليا من الصفحة. الثاني هو StackPanel العنصر الذي يحتوي على مجموعة من WPF عناصر التحكم التي تعرض المعلومات والسماح للتعامل مع التحكم مربع القائمة بواسطة إعداد المكشوفة interoperation الخصائص. لكل من العناصر التي تعتبر تابعة StackPanel, انظر مواد مرجعية للعناصر المختلفة المستخدمة للحصول على تفاصيل حول ما هذه العناصر أو ماذا أفعل, هذه مسرودة في التعليمات البرمجية المثال أدناه ولكن سوف لا يتم شرح هنا (طراز interoperation الأساسية لا يتطلب أي منها, يتم توفير صواب إضافة بعض التفاعل صواب العينة).

<Window
  xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="WPF_Hosting_Win32_Control.HostWindow"
  Name="mainWindow"
  Loaded="On_UIReady">

  <DockPanel Background="LightGreen">
    <Border Name="ControlHostElement"
    Width="200"
    Height="200"
    HorizontalAlignment="Right"
    VerticalAlignment="Top"
    BorderBrush="LightGray"
    BorderThickness="3"
    DockPanel.Dock="Right"/>
    <StackPanel>
      <Label HorizontalAlignment="Center"
        Margin="0,10,0,0"
        FontSize="14"
        FontWeight="Bold">Control the Control</Label>
      <TextBlock Margin="10,10,10,10" >Selected Text: <TextBlock  Name="selectedText"/></TextBlock>
      <TextBlock Margin="10,10,10,10" >Number of Items: <TextBlock  Name="numItems"/></TextBlock>

      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>

      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Append an Item to the List</Label>
      <StackPanel Orientation="Horizontal">
        <Label HorizontalAlignment="Left"
          Margin="10,10,10,10">Item Text</Label>
        <TextBox HorizontalAlignment="Left"
          Name="txtAppend"
          Width="200"
          Margin="10,10,10,10"></TextBox>
      </StackPanel>

      <Button HorizontalAlignment="Left"
        Click="AppendText"
        Width="75"
        Margin="10,10,10,10">Append</Button>

      <Line X1="0" X2="200"
        Stroke="LightYellow"
        StrokeThickness="2"
        HorizontalAlignment="Center"
        Margin="0,20,0,0"/>

      <Label HorizontalAlignment="Center"
        Margin="10,10,10,10">Delete the Selected Item</Label>

      <Button Click="DeleteText"
        Width="125"
        Margin="10,10,10,10"
        HorizontalAlignment="Left">Delete</Button>
    </StackPanel>
  </DockPanel>
</Window>  

تطبيق على فئة المضيف التحكم Microsoft Win32

الأساسية th هو عينة هو الفئة التي تستضيف عنصر تحكم ControlHost.cs فعلياً. يرث من HwndHost. المنشئ يأخذ معلمتين ، الارتفاع والعرض ، التي تتوافق مع ارتفاع وعرض Border عنصر التي تستضيف عنصر تحكم مربع القائمة. وتستخدم هذه القيم في وقت لاحق للتأكد من أن حجم عنصر التحكم يطابق Border العنصر.

  Public Class ControlHost
      Inherits HwndHost
    Private hwndControl As IntPtr
    Private hwndHost As IntPtr
    Private hostHeight, hostWidth As Integer

    Public Sub New(ByVal height As Double, ByVal width As Double)
            hostHeight = CInt(height)
            hostWidth = CInt(width)
    End Sub
public class ControlHost : HwndHost
{
  IntPtr hwndControl;
  IntPtr hwndHost;
  int hostHeight, hostWidth;

  public ControlHost(double height, double width)
  {
    hostHeight = (int)height;
    hostWidth = (int)width;
  }

هناك أيضاً مجموعة الثوابت. هذه الثوابت كبير مأخوذة من Winuser.h وتسمح صواب استخدام أسماء الاصطلاحية عند استدعاء Win32 دالات.

    Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000, LBS_NOTIFY As Integer = &H00000001, HOST_ID As Integer = &H00000002, LISTBOX_ID As Integer = &H00000001, WS_VSCROLL As Integer = &H00200000, WS_BORDER As Integer = &H00800000
internal const int
  WS_CHILD = 0x40000000,
  WS_VISIBLE = 0x10000000,
  LBS_NOTIFY = 0x00000001,
  HOST_ID = 0x00000002,
  LISTBOX_ID = 0x00000001,
  WS_VSCROLL = 0x00200000,
  WS_BORDER = 0x00800000;

تجاوز BuildWindowCore صواب إنشاء إطار Microsoft Win32

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

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

إنشاء إطار المضيف والتحكم مربع القائمة

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

كشف HWND عنصر التحكم إلى خاصية للقراءة فقط بحيث يمكن استخدامه الصفحة المضيف إرسال رسائل عنصر التحكم.

    Public ReadOnly Property hwndListBox() As IntPtr
      Get
          Return hwndControl
      End Get
    End Property
public IntPtr hwndListBox
{
  get { return hwndControl; }
}

يتم إنشاء عنصر تحكم مربع القائمة وهو تابع من تلك النافذة. يتم تعيين ارتفاع وعرض كل من ويندوز إلى القيم التي تم تمريرها إلى المنشئ ، التي نوقشت اعلاه. يؤكد هذا يماثل حجم الإطار المضيف والتحكم بمساحة محجوزة على الصفحة. بعد إنشاء الإطارات العينة بإرجاع HandleRef الكائن الذي يحتوي على HWND من إطار المضيف.

    Protected Overrides Function BuildWindowCore(ByVal hwndParent As HandleRef) As HandleRef
      hwndControl = IntPtr.Zero
      hwndHost = IntPtr.Zero

      hwndHost = CreateWindowEx(0, "static", "", WS_CHILD Or WS_VISIBLE, 0, 0, hostWidth, hostHeight, hwndParent.Handle, New IntPtr(HOST_ID), IntPtr.Zero, 0)

      hwndControl = CreateWindowEx(0, "listbox", "", WS_CHILD Or WS_VISIBLE Or LBS_NOTIFY Or WS_VSCROLL Or WS_BORDER, 0, 0, hostWidth, hostHeight, hwndHost, New IntPtr(LISTBOX_ID), IntPtr.Zero, 0)

      Return New HandleRef(Me, hwndHost)
    End Function
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
  hwndControl = IntPtr.Zero;
  hwndHost = IntPtr.Zero;

  hwndHost = CreateWindowEx(0, "static", "",
                            WS_CHILD | WS_VISIBLE,
                            0, 0,
                            hostWidth, hostHeight, 
                            hwndParent.Handle,
                            (IntPtr)HOST_ID,
                            IntPtr.Zero,
                            0);

  hwndControl = CreateWindowEx(0, "listbox", "",
                                WS_CHILD | WS_VISIBLE | LBS_NOTIFY
                                  | WS_VSCROLL | WS_BORDER,
                                0, 0,
                                hostWidth, hostHeight, 
                                hwndHost,
                                (IntPtr) LISTBOX_ID,
                                IntPtr.Zero,
                                0);

  return new HandleRef(this, hwndHost);
}
    'PInvoke declarations
    <DllImport("user32.dll", EntryPoint := "CreateWindowEx", CharSet := CharSet.Unicode)>
    Friend Shared Function CreateWindowEx(ByVal dwExStyle As Integer, ByVal lpszClassName As String, ByVal lpszWindowName As String, ByVal style As Integer, ByVal x As Integer, ByVal y As Integer, ByVal width As Integer, ByVal height As Integer, ByVal hwndParent As IntPtr, ByVal hMenu As IntPtr, ByVal hInst As IntPtr, <MarshalAs(UnmanagedType.AsAny)> ByVal pvParam As Object) As IntPtr
    End Function
//PInvoke declarations
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(int dwExStyle,
                                              string lpszClassName,
                                              string lpszWindowName,
                                              int style,
                                              int x, int y,
                                              int width, int height,
                                              IntPtr hwndParent,
                                              IntPtr hMenu,
                                              IntPtr hInst,
                                              [MarshalAs(UnmanagedType.AsAny)] object pvParam);

تنفيذ DestroyWindow و WndProc

بالإضافة إلى BuildWindowCore ، يجب أيضاً تجاوز WndProc و DestroyWindowCore أساليب HwndHost. في هذا المثال، يتم معالجة الرسائل لعنصر التحكم قبل MessageHook معالج وبالتالي التطبيق WndProc و DestroyWindowCore هو المعدل الأدنى. في حالة من WndProc، قم بتعيين handledإلى falseللإشارة إلى أن الرسالة لم تكن hوled و بإرجاع 0. DestroyWindowCore، بساطة إتلاف الإطار.

    Protected Overrides Function WndProc(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
      handled = False
      Return IntPtr.Zero
    End Function

    Protected Overrides Sub DestroyWindowCore(ByVal hwnd As HandleRef)
      DestroyWindow(hwnd.Handle)
    End Sub
protected override IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  handled = false;
  return IntPtr.Zero;
}

protected override void DestroyWindowCore(HandleRef hwnd)
{
  DestroyWindow(hwnd.Handle);
}
    <DllImport("user32.dll", EntryPoint := "DestroyWindow", CharSet := CharSet.Unicode)>
    Friend Shared Function DestroyWindow(ByVal hwnd As IntPtr) As Boolean
    End Function
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);

استضافة التحكم على صفحة

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

يصل العينة معالج MessageHook حدث ControlHost تلقي الرسائل من عنصر التحكم. أرسلت يظهر هذا الحدث عن كل رسالة إلى إطار استضافتها. في هذه الحالة هذه هي الرسائل المرسلة صواب إطار يلتف الفعلي التحكم مربع القائمة, بما في ذلك رسائل الإعلام من عنصر التحكم. يستدعي العينة SendMessage صواب للحصول على معلومات من عنصر التحكم ثم تعديل محتوياته. تفاصيل عن الكيفية التي يتصل الصفحة مع تحكم تمت مناقشتها في المقطع التالي

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

لاحظ أن هناك نوعين PInvoke المقطع تعريفات لإرسال رسالة.يعد ذلك ضروريًا لأن أحد يستخدم wParam لتمرير سلسلة والآخر يستخدمه لتمريرها إلى عدد صحيح.يجب تعريف منفصل لكل توقيع للتأكد من أن تم التنظيم بشكل صحيح.

Partial Public Class HostWindow
    Inherits Window
    Private selectedItem As Integer
    Private hwndListBox As IntPtr
    Private listControl As ControlHost
    Private app As Application
    Private myWindow As Window
    Private itemCount As Integer

    Private Sub On_UIReady(ByVal sender As Object, ByVal e As EventArgs)
        app = System.Windows.Application.Current
        myWindow = app.MainWindow
        myWindow.SizeToContent = SizeToContent.WidthAndHeight
        listControl = New ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth)
        ControlHostElement.Child = listControl
        AddHandler listControl.MessageHook, AddressOf ControlMsgFilter
        hwndListBox = listControl.hwndListBox
        For i As Integer = 0 To 14 'populate listbox
            Dim itemText As String = "Item" & i.ToString()
            SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText)
        Next i
        itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
        numItems.Text = "" & itemCount.ToString()
    End Sub
    public partial class HostWindow : Window
    {
    int selectedItem;
    IntPtr hwndListBox;
    ControlHost listControl;
    Application app;
    Window myWindow;
    int itemCount;

    private void On_UIReady(object sender, EventArgs e)
    {
      app = System.Windows.Application.Current;
      myWindow = app.MainWindow;
      myWindow.SizeToContent = SizeToContent.WidthAndHeight;
      listControl = new ControlHost(ControlHostElement.ActualHeight, ControlHostElement.ActualWidth);
      ControlHostElement.Child = listControl;
      listControl.MessageHook += new HwndSourceHook(ControlMsgFilter);
      hwndListBox = listControl.hwndListBox;
      for (int i = 0; i < 15; i++) //populate listbox
      {
        string itemText = "Item" + i.ToString();
        SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, itemText);
      }
      itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
      numItems.Text = "" +  itemCount.ToString();
    }

Private Function ControlMsgFilter(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
    Dim textLength As Integer

    handled = False
    If msg = WM_COMMAND Then
        Select Case CUInt(wParam.ToInt32()) >> 16 And &HFFFF 'extract the HIWORD
            Case LBN_SELCHANGE 'Get the item text and display it
                selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
                textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero)
                Dim itemText As New StringBuilder()
                SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText)
                selectedText.Text = itemText.ToString()
                handled = True
        End Select
    End If
    Return IntPtr.Zero
End Function
Friend Const LBN_SELCHANGE As Integer = &H1, WM_COMMAND As Integer = &H111, LB_GETCURSEL As Integer = &H188, LB_GETTEXTLEN As Integer = &H18A, LB_ADDSTRING As Integer = &H180, LB_GETTEXT As Integer = &H189, LB_DELETESTRING As Integer = &H182, LB_GETCOUNT As Integer = &H18B

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As Integer, <MarshalAs(UnmanagedType.LPWStr)> ByVal lParam As StringBuilder) As Integer
End Function

<DllImport("user32.dll", EntryPoint:="SendMessage", CharSet:=CharSet.Unicode)>
Friend Shared Function SendMessage(ByVal hwnd As IntPtr, ByVal msg As Integer, ByVal wParam As IntPtr, ByVal lParam As String) As IntPtr
End Function

private IntPtr ControlMsgFilter(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
  int textLength;

  handled = false;
  if (msg == WM_COMMAND)
  {
    switch ((uint)wParam.ToInt32() >> 16 & 0xFFFF) //extract the HIWORD
    {
      case LBN_SELCHANGE : //Get the item text and display it
        selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
        textLength = SendMessage(listControl.hwndListBox, LB_GETTEXTLEN, IntPtr.Zero, IntPtr.Zero);
        StringBuilder itemText = new StringBuilder();
        SendMessage(hwndListBox, LB_GETTEXT, selectedItem, itemText);
        selectedText.Text = itemText.ToString();
        handled = true;
        break;
    }
  }
  return IntPtr.Zero;
}
internal const int
  LBN_SELCHANGE = 0x00000001,
  WM_COMMAND = 0x00000111,
  LB_GETCURSEL = 0x00000188,
  LB_GETTEXTLEN = 0x0000018A,
  LB_ADDSTRING = 0x00000180, 
  LB_GETTEXT = 0x00000189,
  LB_DELETESTRING = 0x00000182,
  LB_GETCOUNT = 0x0000018B;

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       IntPtr wParam,
                                       IntPtr lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern int SendMessage(IntPtr hwnd,
                                       int msg,
                                       int wParam, 
                                       [MarshalAs(UnmanagedType.LPWStr)] StringBuilder lParam);

[DllImport("user32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Unicode)]
internal static extern IntPtr SendMessage(IntPtr hwnd,
                                          int msg,
                                          IntPtr wParam,
                                          String lParam);

تنفيذ الاتصال بين التحكم وعلى الصفحة

تقوم بمعالجة عنصر التحكم عن طريق إرساله Windows الرسائل. يعلمك عنصر التحكم عندما يتفاعل المستخدم عليه عن طريق إرسال إعلامات إلى إطار المضيف الخاص به. يتضمن النموذج استضافة عنصر تحكم ListBox Win32 في نموذج UI يوفر أمثلة عديدة من كيفية عمل ذلك:

  • إلحاق عنصر إلى القائمة.

  • حذف العنصر المحدد من القائمة.

  • عرض نص العنصر المحدد حاليا.

  • عرض عدد العناصر في القائمة.

يمكن للمستخدم أيضا تحديد عنصر في مربع القائمة عن طريق النقر عليه ، تماما كما تفعل بالنسبة للتقليدية Win32 التطبيق. يتم تحديث البيانات المعروضة في كل مرة المستخدم تغيير حالة مربع القائمة عن طريق اختيار واضاف ، أو إلحاق عنصر

إلحاق العناصر ، إرسال رسالة LB_ADDSTRING مربع القائمة. لحذف العناصر أو إرسال LB_GETCURSEL للحصول على فهرس التحديد الحالي ثم LB_DELETESTRING 
 حذف العنصر. النموذج أيضاً إرسال LB_GETCOUNT ويستخدم القيمة التي تم إرجاعها لتحديث العرض الذي يعرض عدد العناصر. استخدم هذه مثيلي ارسال رسالة أحد PInvoke التعريفات التي تمت مناقشتها في المقطع السابق.

Private Sub AppendText(ByVal sender As Object, ByVal args As EventArgs)
    If txtAppend.Text <> String.Empty Then
        SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub
Private Sub DeleteText(ByVal sender As Object, ByVal args As EventArgs)
    selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero)
    If selectedItem <> -1 Then 'check for selected item
        SendMessage(hwndListBox, LB_DELETESTRING, New IntPtr(selectedItem), IntPtr.Zero)
    End If
    itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero)
    numItems.Text = "" & itemCount.ToString()
End Sub
private void AppendText(object sender, EventArgs args)
{
  if (txtAppend.Text != string.Empty)
  {
    SendMessage(hwndListBox, LB_ADDSTRING, IntPtr.Zero, txtAppend.Text);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}
private void DeleteText(object sender, EventArgs args)
{
  selectedItem = SendMessage(listControl.hwndListBox, LB_GETCURSEL, IntPtr.Zero, IntPtr.Zero);
  if (selectedItem != -1) //check for selected item
  {
    SendMessage(hwndListBox, LB_DELETESTRING, (IntPtr)selectedItem, IntPtr.Zero);
  }
  itemCount = SendMessage(hwndListBox, LB_GETCOUNT, IntPtr.Zero, IntPtr.Zero);
  numItems.Text = "" + itemCount.ToString();
}

عندما يقوم المستخدم بتحديد عنصر تغيير التحديد الخاصة بهم صواب بإعلام الإطار المضيف بإرسال رسالة WM_COMMAND رفع MessageHook الحدث للحصول على الصفحة. يتلقى المعالج نفس المعلومات كـ الإجراء الإطار الرئيسي من إطار المضيف. ويمر أيضا إشارة إلى قيمة منطقية ، handled. تعيين handled ألى true تشير إلى أن تتم معالجة الرسالة معالجة لم إضافية مطلوبة.

إرسال WM_COMMAND العديد من الأسباب، لذلك يجب فحص معرّف الإعلام صواب تحديد ما إذا كان أحد أحداث التي ترغب صواب معالجة. يحتوي المعرف في الكلمة العليا wParam معلمة. منذ Microsoft .NETأنه لا يوجد ماكرو HIWORD، يستخدم العينة operaإلىrs المختصة بالبت إلى استخراجها من المعرف. إذا كان مستخدم بإجراء أو قم بتغيير تحديد الخاص بها، سيكون المعرف LBN_SELCHANGE.

عند تلقي LBN_SELCHANGE العينة يحصل فهرس العنصر المحدد عن طريق إرسال عنصر تحكم رسالة LB_GETCURSEL. للحصول على النص "، يجب أولاً إنشاء StringBuilder. قم بإرسال عنصر تحكم رسالة LB_GETTEXT. تمرير فارغة StringBuilder الكائن كما wParam معلمة. عندما أرسل إرجاع الرسالة ، StringBuilder سوف تحتوي على نص العنصر المحدد. يتطلب استخدام هذه ارسال رسالة آخر بعد PInvoke تعريف.

وأخيراً، قم بتعيين handled الى true الى للإشارة معالجة الرسالة.

راجع أيضًا:

المرجع

HwndHost

المبادئ

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

الشروع في استخدام WPF