문제

기본적으로 텍스트 상자와 버튼 (devexpress buttonedit 컨트롤)으로 구성된 타사 편집기가 있습니다. 특정 키 스트로크를 만들고 싶습니다 (대체 + 아래에) 버튼을 클릭하십시오. 이 글을 반복해서 쓰지 않기 위해 ButtonClick 이벤트를 높이는 일반적인 키 업 이벤트 핸들러를 만들고 싶습니다. 불행히도, 컨트롤에는 버튼 클릭 이벤트를 제기하는 방법이없는 것 같습니다.

반사를 통해 외부 기능에서 이벤트를 어떻게 올리려고합니까?

도움이 되었습니까?

해결책

다음은 제네릭을 사용하는 데모입니다 (오류 확인이 생략 됨) :

using System;
using System.Reflection;
static class Program {
  private class Sub {
    public event EventHandler<EventArgs> SomethingHappening;
  }
  internal static void Raise<TEventArgs>(this object source, string eventName, TEventArgs eventArgs) where TEventArgs : EventArgs
  {
    var eventDelegate = (MulticastDelegate)source.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(source);
    if (eventDelegate != null)
    {
      foreach (var handler in eventDelegate.GetInvocationList())
      {
        handler.Method.Invoke(handler.Target, new object[] { source, eventArgs });
      }
    }
  }
  public static void Main()
  {
    var p = new Sub();
    p.Raise("SomethingHappening", EventArgs.Empty);
    p.SomethingHappening += (o, e) => Console.WriteLine("Foo!");
    p.Raise("SomethingHappening", EventArgs.Empty);
    p.SomethingHappening += (o, e) => Console.WriteLine("Bar!");
    p.Raise("SomethingHappening", EventArgs.Empty);
    Console.ReadLine();
  }
}

다른 팁

일반적으로, 당신은 할 수 없습니다. 이벤트를 기본적으로 쌍으로 생각하십시오 AddHandler/RemoveHandler 방법 (기본적으로 그들이 무엇인지). 그들이 구현하는 방법은 수업에 달려 있습니다. 대부분의 winforms 컨트롤 사용 EventHandlerList 그들의 구현으로서 개인 필드와 키를 가져 오기 시작하면 코드가 매우 부서지기 쉽습니다.

그렇습니다 ButtonEdit 제어 노출 OnClick 전화 할 수있는 방법?

각주 : 실제로 이벤트 ~할 수 있다 따라서 "인상"회원이 있으므로 EventInfo.GetRaiseMethod. 그러나 이것은 결코 C#에 의해 채워지지 않으며 일반적으로 프레임 워크에 있다고 생각하지 않습니다.

일반적으로 다른 수업 이벤트를 제기 할 수 없습니다. 이벤트는 실제로 개인 대의원 필드와 두 개의 액세서 (add_event 및 remove_event)로 저장됩니다.

반사를 통해 그것을하려면 개인 대의원 필드를 찾아서 얻은 다음 호출하면됩니다.

나는 RaisepropertyChange를 주입하기 위해 inotifypropertychanged를 구현하는 클래스에 대한 확장을 썼습니다.u003CT> 방법, 다음과 같이 사용할 수 있습니다.

this.RaisePropertyChanged(() => MyProperty);

모든 기본 클래스에서 메소드를 구현하지 않고. 내 사용을 위해서는 속도가 느려졌지만 소스 코드는 누군가를 도울 수 있습니다.

그래서 여기에 있습니다 :

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.Globalization;

namespace Infrastructure
{
    /// <summary>
    /// Adds a RaisePropertyChanged method to objects implementing INotifyPropertyChanged.
    /// </summary>
    public static class NotifyPropertyChangeExtension
    {
        #region private fields

        private static readonly Dictionary<string, PropertyChangedEventArgs> eventArgCache = new Dictionary<string, PropertyChangedEventArgs>();
        private static readonly object syncLock = new object();

        #endregion

        #region the Extension's

        /// <summary>
        /// Verifies the name of the property for the specified instance.
        /// </summary>
        /// <param name="bindableObject">The bindable object.</param>
        /// <param name="propertyName">Name of the property.</param>
        [Conditional("DEBUG")]
        public static void VerifyPropertyName(this INotifyPropertyChanged bindableObject, string propertyName)
        {
            bool propertyExists = TypeDescriptor.GetProperties(bindableObject).Find(propertyName, false) != null;
            if (!propertyExists)
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture,
                    "{0} is not a public property of {1}", propertyName, bindableObject.GetType().FullName));
        }

        /// <summary>
        /// Gets the property name from expression.
        /// </summary>
        /// <param name="notifyObject">The notify object.</param>
        /// <param name="propertyExpression">The property expression.</param>
        /// <returns>a string containing the name of the property.</returns>
        public static string GetPropertyNameFromExpression<T>(this INotifyPropertyChanged notifyObject, Expression<Func<T>> propertyExpression)
        {
            return GetPropertyNameFromExpression(propertyExpression);
        }

        /// <summary>
        /// Raises a property changed event.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="bindableObject">The bindable object.</param>
        /// <param name="propertyExpression">The property expression.</param>
        public static void RaisePropertyChanged<T>(this INotifyPropertyChanged bindableObject, Expression<Func<T>> propertyExpression)
        {
            RaisePropertyChanged(bindableObject, GetPropertyNameFromExpression(propertyExpression));
        }

        #endregion

        /// <summary>
        /// Raises the property changed on the specified bindable Object.
        /// </summary>
        /// <param name="bindableObject">The bindable object.</param>
        /// <param name="propertyName">Name of the property.</param>
        private static void RaisePropertyChanged(INotifyPropertyChanged bindableObject, string propertyName)
        {
            bindableObject.VerifyPropertyName(propertyName);
            RaiseInternalPropertyChangedEvent(bindableObject, GetPropertyChangedEventArgs(propertyName));
        }

        /// <summary>
        /// Raises the internal property changed event.
        /// </summary>
        /// <param name="bindableObject">The bindable object.</param>
        /// <param name="eventArgs">The <see cref="System.ComponentModel.PropertyChangedEventArgs"/> instance containing the event data.</param>
        private static void RaiseInternalPropertyChangedEvent(INotifyPropertyChanged bindableObject, PropertyChangedEventArgs eventArgs)
        {
            // get the internal eventDelegate
            var bindableObjectType = bindableObject.GetType();

            // search the base type, which contains the PropertyChanged event field.
            FieldInfo propChangedFieldInfo = null;
            while (bindableObjectType != null)
            {
                propChangedFieldInfo = bindableObjectType.GetField("PropertyChanged", BindingFlags.Instance | BindingFlags.NonPublic);
                if (propChangedFieldInfo != null)
                    break;

                bindableObjectType = bindableObjectType.BaseType;
            }
            if (propChangedFieldInfo == null)
                return;

            // get prop changed event field value
            var fieldValue = propChangedFieldInfo.GetValue(bindableObject);
            if (fieldValue == null)
                return;

            MulticastDelegate eventDelegate = fieldValue as MulticastDelegate;
            if (eventDelegate == null)
                return;

            // get invocation list
            Delegate[] delegates = eventDelegate.GetInvocationList();

            // invoke each delegate
            foreach (Delegate propertyChangedDelegate in delegates)
                propertyChangedDelegate.Method.Invoke(propertyChangedDelegate.Target, new object[] { bindableObject, eventArgs });
        }

        /// <summary>
        /// Gets the property name from an expression.
        /// </summary>
        /// <param name="propertyExpression">The property expression.</param>
        /// <returns>The property name as string.</returns>
        private static string GetPropertyNameFromExpression<T>(Expression<Func<T>> propertyExpression)
        {
            var lambda = (LambdaExpression)propertyExpression;

            MemberExpression memberExpression;

            if (lambda.Body is UnaryExpression)
            {
                var unaryExpression = (UnaryExpression)lambda.Body;
                memberExpression = (MemberExpression)unaryExpression.Operand;
            }
            else memberExpression = (MemberExpression)lambda.Body;

            return memberExpression.Member.Name;
        }

        /// <summary>
        /// Returns an instance of PropertyChangedEventArgs for the specified property name.
        /// </summary>
        /// <param name="propertyName">
        /// The name of the property to create event args for.
        /// </param>
        private static PropertyChangedEventArgs GetPropertyChangedEventArgs(string propertyName)
        {
            PropertyChangedEventArgs args;

            lock (NotifyPropertyChangeExtension.syncLock)
            {
                if (!eventArgCache.TryGetValue(propertyName, out args))
                    eventArgCache.Add(propertyName, args = new PropertyChangedEventArgs(propertyName));
            }

            return args;
        }
    }
}

원래 코드의 일부를 제거 했으므로 라이브러리의 다른 부분에 대한 언급없이 확장자가 그대로 작동해야합니다. 그러나 실제로 테스트되지 않았습니다.

추신 : 코드의 일부는 다른 사람에게서 빌려 왔습니다. 내가 어디에서 얻었는지 잊어 버린 것을 부끄러워. :(

결과적으로, 나는 이것을 할 수 있었고 그것을 깨닫지 못했습니다.

buttonEdit1.Properties.Buttons[0].Shortcut = new DevExpress.Utils.KeyShortcut(Keys.Alt | Keys.Down);

그러나 내가 할 수 없다면 소스 코드를 탐구하고 이벤트를 제기하는 메소드를 찾아야했을 것입니다.

도와 주셔서 감사합니다.

에서 반사를 통해 이벤트를 제기합니다, 나는 대답을 생각하지만 vb.net, 즉,이 게시물보다 두 개의 게시물이 일반적인 접근 방식을 제공 할 것입니다 (예 : 동일한 클래스가 아닌 유형을 참조 할 때 영감을 얻기 위해 VB.NET ONE을 살펴 보겠습니다).

 public event EventHandler<EventArgs> MyEventToBeFired;

    public void FireEvent(Guid instanceId, string handler)
    {

        // Note: this is being fired from a method with in the same
        //       class that defined the event (that is, "this").

        EventArgs e = new EventArgs(instanceId);

        MulticastDelegate eventDelagate =
              (MulticastDelegate)this.GetType().GetField(handler,
               System.Reflection.BindingFlags.Instance |
               System.Reflection.BindingFlags.NonPublic).GetValue(this);

        Delegate[] delegates = eventDelagate.GetInvocationList();

        foreach (Delegate dlg in delegates)
        {
            dlg.Method.Invoke(dlg.Target, new object[] { this, e });
        }
    }

    FireEvent(new Guid(),  "MyEventToBeFired");

컨트롤이 버튼이라는 것을 알고 있다면 PerformClick() 방법. 다른 이벤트와 같은 문제가 있습니다 OnEnter, OnExit. 각 컨트롤 유형에 대해 새 유형을 도출하고 싶지 않다면 이러한 이벤트를 제기 할 수 없습니다.

코드가있는 것 같습니다 받아 들여진 답변 Wiebe Cnossen 은이 하나의 라이너로 단순화 될 수 있습니다.

((Delegate)source.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(source))
    .DynamicInvoke(source, eventArgs);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top