1

コントロールのイベントを処理するために割り当てられているメソッドを (外部から) 見つけて、別のコントロールの同じイベントを処理するために同じメソッドを割り当てたいと考えています。次の方法を試しましたが、成功しませんでした。

private void ReflectMethods(Control control, Control baseControl, string[] excludedEventNames = null, string[] includedEventNames = null)
{
    Type baseType = baseControl.GetType();
    Type ownType = control.GetType();

    foreach (EventInfo baseEventInfo in baseType.GetEvents())
    {
        if (excludedEventNames != null && excludedEventNames.Contains(baseEventInfo.Name))
            continue;

        if (includedEventNames != null && !includedEventNames.Contains(baseEventInfo.Name))
            continue;

        //
        // Checking if current control has the same event..
        //
        foreach (EventInfo ownEventInfo in ownType.GetEvents())
        {
            if (ownEventInfo.Name == baseEventInfo.Name)
            {
                FieldInfo eventField = baseType.GetField(baseEventInfo.Name, BindingFlags.GetField | BindingFlags.NonPublic | BindingFlags.Instance);

                // The above line always returns null, so I cannot get the handler ???
                EventHandler eventHandler = (EventHandler)eventField.GetValue(baseControl);

                ownEventInfo.AddEventHandler(this, eventHandler);
            }
        }
    }
}
4

1 に答える 1

1

使用しているコントロールが実装されている限り、ソリューションは適切です。これは、コンパイラが、投稿したコードのようにアクセスできる各イベントのフィールドを作成するために発生します。しかし、これが唯一の方法ではありません。プロパティの場合と似ています。通常、プロパティごとにフィールドがありますが、それが唯一の方法ではありません。

コントロールの場合、イベントに関連付けられたデリゲートを取得するには、プロパティ Events を介して EventHandlerList を取得する必要があります。次に、文字列「Event」で構成される名前のフィールドの値を使用して、それにアクセスする適切な EventHandler を取得します。イベントの実際の名前によって (たとえば、Click の場合は、フィールド "EventClick" を探す必要があります)。

ここでは、WinForm コントロールで機能するコードの修正バージョンを見つけることができます。独自に設計されたコントロールでは機能しないことに注意してください。すべての状況を管理するには、2 つのアプローチを組み合わせる必要があります。

    private void ReflectMethods(Control control, Control baseControl, string[] excludedEventNames = null, string[] includedEventNames = null)
    {
        Type baseType = baseControl.GetType();
        Type ownType = control.GetType();

        EventHandlerList events = typeof(Control).GetProperty("Events", BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic).GetValue(baseControl, null) as EventHandlerList;
        foreach (EventInfo baseEventInfo in baseType.GetEvents())
        {
            if (excludedEventNames != null && excludedEventNames.Contains(baseEventInfo.Name))
                continue;

            if (includedEventNames != null && !includedEventNames.Contains(baseEventInfo.Name))
                continue;

            //
            // Checking if current control has the same event..
            //
            foreach (EventInfo ownEventInfo in ownType.GetEvents())
            {
                if (ownEventInfo.Name == baseEventInfo.Name)
                {
                    object eventField = typeof(Control).GetField("Event" + baseEventInfo.Name, BindingFlags.NonPublic | BindingFlags.Static).GetValue(baseControl);
                    Delegate aDel = events[eventField];
                    ownEventInfo.AddEventHandler(control, aDel);
                }
            }
        }
    }
于 2012-11-14T07:39:12.950 に答える