سؤال

الخلفية: أنا أستخدم WPF و C # (3.5) وأنا أعمل على تطبيق يسمح للمستخدم بعرض نموذج / نافذة / Usercontrol هذا بالفعل جزء من مجموعة مجمعة. عندما ينظرون إليها، يجب أن يكونوا قادرين على النقر فوق أي عنصر تحكم (أزرار وصنوات نصية، وحتى التسميات)، يجب أن يظهر محرر منبثق صغير من خلال عنصر التحكم حيث يمكنهم بعد ذلك اكتبها في تلميح الأدوات، والمساعدة، وما إلى ذلك، لهذا التحكم.

الطويلة وقصيرة منه: أحتاج إلى تقليد عرض التصميم الأساسي في WPF. مما يعني أنني بحاجة إلى القيام بما يلي على الأقل:

  • قم بتحميل UserControl / Window من مجموعة معينة (لا مشكلة)
  • إرساء انها usercontrol / النافذة (لا مشكلة)
  • مسح جميع الأحداث المشتركةين لجميع عناصر التحكم
  • تعيين الخاص بي "Showeditorpopup" EventHandler إلى كل عنصر تحكم (لا ينبغي أن يكون مشكلة)

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

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

<Button Name="someButton" Click="someButton_Click"/>

إليك الرمز (يمكنك تشغيله من EventButhandler إذا كنت تريد):

public void SomeFunction()
{
// Get the control's Type
Type someButtonType = ((UIElement)someButton).GetType();

// Dig out the undocumented (yes, I know, it's risky) EventHandlerStore
// from the control's Type
PropertyInfo EventHandlersStoreType =  
        someButtonType.GetProperty("EventHandlersStore",  
        BindingFlags.Instance | BindingFlags.NonPublic);

// Get the actual "value" of the store, not just the reflected PropertyInfo
Object EventHandlersStore = EventHandlersStoreType.GetValue(someButton, null);

// Get the store's type ...
Type storeType = EventHandlersStore.GetType();

// ... so we can pull out the store's public method GetRoutedEventHandlers
MethodInfo GetEventHandlers =  
        storeType.GetMethod("GetRoutedEventHandlers",  
        BindingFlags.Instance | BindingFlags.Public);

// Reflector shows us that the method's sig is this:
// public RoutedEventHandlerInfo[] GetRoutedEventHandlers(RoutedEvent routedEvent);

// So set up the RoutedEvent param
object[] Params = new object[] { ButtonBase.ClickEvent as RoutedEvent };
// I've also seen this for the param, but doesn't seem to make a difference:
// object[] Params = new object[] { someButton.ClickEvent };

// And invoke it ... and watch it crash!
GetEventHandlers.Invoke(someButton, Params);
}

يعمل ما يصل إلى الدعارة، والتي تعود: الكائن لا يتطابق مع نوع الهدف (أي، فإن معاييري أو كائن الهدف صواب). لقد وجدت أنه يمكنك حل هذا مع:

GetEventHandlers.Invoke(Activator.CreateInstance(someButton.GetType()), Params);
// Also doesn't work...

عندما قمت بتعيين ساعة على GetEventhAndlers MethodInfo، فإنه يبدو رائعا، بل لا يعجبه فقط ما أقوم به عندما أتصل بالدعح

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

أي أدلة؟ مرة أخرى، إذا كان هناك طريقة أفضل / أسهل للقيام بالمهمة بشكل عام، اسمحوا لي أن أعرف :)

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

المحلول

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

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

نصائح أخرى

إذا كنت تستخدم GetEventHandlers.Invoke(EventHandlersStore , Params) يبدو أن العمل جيدا ولا تحطم.

باستخدام الكود الخاص بك من أعلى أنا فعلت هذا:

// Get the control's Type
Type controlViewType = ((UIElement)control).GetType();

// Dig out the undocumented (yes, I know, it's risky) EventHandlerStore
// from the control's Type
PropertyInfo EventHandlersStoreType =
controlViewType.GetProperty("EventHandlersStore",
BindingFlags.Instance | BindingFlags.NonPublic);

// Get the actual "value" of the store, not just the reflected PropertyInfo
Object EventHandlersStore = EventHandlersStoreType.GetValue(tree, null);
var miGetRoutedEventHandlers 
EventHandlersStore.GetType().GetMethod("GetRoutedEventHandlers", 
BindingFlags.Public | BindingFlags.Instance);
RoutedEventHandlerInfo[] res =   
(RoutedEventHandlerInfo[])miGetRoutedEventHandlers.Invoke(EventHandlersStore, 
new object[] { CheckedTreeViewItem.CheckedEvent });

بمجرد أن يكون لديك المشكلة الوحيدة هي أن لديك الآن معلومات الطريقة، لذلك تحتاج إلى الحصول على مثيل للكائن الذي ينفذ هذه الطريقة. عادة ما يتم تعريف معالجات الأحداث على كائن النافذة أو الصفحة. حتى تحصل عليه: var الوالد = visualtreehelper.getparent (التحكم)؛ بينما (! (عنصر التحكم هو نافذة) &&! (التحكم في الصفحة)) {penter = visualtreehelper.getparent (الوالد)؛ }

ومع هذه الحالة، يمكنك بعد ذلك استدعاء الحدث WTIH:

res.[0].Handler.Method.Invoke(parent, new object[] { control, new RoutedEventArgs() }
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top