سؤال

في تطبيق C++، لدي إشارة تشير إلى نافذة قيد التشغيل في عملية تابعة لجهة خارجية.تحتوي هذه النافذة على عناصر تحكم تعمل على توسيع عنصر تحكم COM TreeView.أنا مهتم بالحصول على CheckState لعنصر التحكم هذا.
أستخدم hWnd للحصول على HTREEITEM باستخدام TreeView_GetRoot(hwnd) من commctrl.h

يشير hwnd إلى النافذة وhItem هي القيمة المرجعة من TreeView_GetRoot(hwnd).يتم استخدامها على النحو التالي:

int iCheckState = TreeView_GetCheckState(hwnd,  hItem);
switch (iCheckState)
{
   case 0:
      // (unchecked)
   case 1:
      // checked
   ...
}

إنني أتطلع إلى نقل هذا الرمز إلى تطبيق C# الذي يفعل نفس الشيء (يقوم بإيقاف تشغيل CheckState لعنصر تحكم TreeView).لم أستخدم COM أبدًا وأنا غير مألوف تمامًا.

لقد حاولت استخدام .NET mscomctl ولكن لم أتمكن من العثور على طرق مكافئة لـ TreeView_GetRoot أو TreeView_GetCheckState.أنا عالق تمامًا ولا أعرف كيفية إعادة إنشاء هذا الرمز في C# :(

اقتراحات؟

هل كانت مفيدة؟

المحلول

لدينا هذه التعريفات من CommCtrl.h:

#define TreeView_SetItemState(hwndTV, hti, data, _mask) \
{ TVITEM _ms_TVi;\
  _ms_TVi.mask = TVIF_STATE; \
  _ms_TVi.hItem = (hti); \
  _ms_TVi.stateMask = (_mask);\
  _ms_TVi.state = (data);\
  SNDMSG((hwndTV), TVM_SETITEM, 0, (LPARAM)(TV_ITEM *)&_ms_TVi);\
}

#define TreeView_SetCheckState(hwndTV, hti, fCheck) \
  TreeView_SetItemState(hwndTV, hti, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), TVIS_STATEIMAGEMASK)

يمكننا ترجمة هذا إلى C# باستخدام PInvoc.أولاً ، نقوم بتنفيذ وحدات الماكرو هذه كوظائف ، ثم نضيف أي دعم آخر مطلوب لجعل هذه الوظائف تعمل.هنا هي أول طلقة لي في ذلك.يجب عليك التحقق من الرمز الخاص بي خاصة عندما يتعلق الأمر بحماية الهيكل.علاوة على ذلك ، قد ترغب في نشر الرسائل المتقاطعة بدلاً من استدعاء SendMessage.

أخيرًا ، لست متأكدًا مما إذا كان هذا سيعمل على الإطلاق لأنني أعتقد أن عناصر التحكم المشتركة تستخدم رسائل WM_USER+.عند إرسال هذه الرسائل عبر العمليات ، تكون عناوين معلمة البيانات غير معدلة وقد تتسبب العملية الناتجة في انتهاك للوصول.ستكون هذه مشكلة في أي لغة تستخدمها (C ++ أو C#) ، لذلك ربما أكون مخطئًا هنا (أنت تقول أن لديك برنامج C ++ يعمل).

static class Interop {

public static IntPtr TreeView_SetCheckState(HandleRef hwndTV, IntPtr hti, bool fCheck) {
    return TreeView_SetItemState(hwndTV, hti, INDEXTOSTATEIMAGEMASK((fCheck) ? 2 : 1), (uint)TVIS.TVIS_STATEIMAGEMASK);
}

public static IntPtr TreeView_SetItemState(HandleRef hwndTV, IntPtr hti, uint data, uint _mask) {
    TVITEM _ms_TVi = new TVITEM();
    _ms_TVi.mask = (uint)TVIF.TVIF_STATE;
    _ms_TVi.hItem = (hti);
    _ms_TVi.stateMask = (_mask);
    _ms_TVi.state = (data);
    IntPtr p = Marshal.AllocCoTaskMem(Marshal.SizeOf(_ms_TVi));
    Marshal.StructureToPtr(_ms_TVi, p, false);
    IntPtr r = SendMessage(hwndTV, (int)TVM.TVM_SETITEMW, IntPtr.Zero, p);
    Marshal.FreeCoTaskMem(p);
    return r;
}

private static uint INDEXTOSTATEIMAGEMASK(int i) { return ((uint)(i) << 12); }

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern IntPtr SendMessage(HandleRef hWnd, int msg, IntPtr wParam, IntPtr lParam);

private enum TVIF : uint {
    TVIF_STATE = 0x0008
}

private enum TVIS : uint {
    TVIS_STATEIMAGEMASK = 0xF000
}

private enum TVM : int {
    TV_FIRST = 0x1100,
    TVM_SETITEMA = (TV_FIRST + 13),
    TVM_SETITEMW = (TV_FIRST + 63)
}

private struct TVITEM {
    public uint mask;
    public IntPtr hItem;
    public uint state;
    public uint stateMask;
    public IntPtr pszText;
    public int cchTextMax;
    public int iImage;
    public int iSelectedImage;
    public int cChildren;
    public IntPtr lParam;
}
}

نصائح أخرى

لماذا لا تستخدم عنصر تحكم Windows Forms TreeView؟إذا كنت تستخدم عنصر التحكم هذا، فقم بتعيين خاصية CheckBoxes الخاصة بعنصر التحكم إلى true لتمكين خانات الاختيار، وقم بتعيين الخاصية Checked على العقد التي تريد عرضها محددة.

للحصول على مجموعة العقد الجذرية، استخدم خاصية العقد الخاصة بـ TreeView.يؤدي هذا إلى إرجاع TreeNodeCollection والذي يمكنك بعد ذلك فهرسته أو إضافة عناصر إليه.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top