سؤال

ولدي محرر الجهات الأخرى التي تضم أساسا النص وزر (السيطرة DevExpress ButtonEdit). أريد أن ضربة مفتاح معين ( البديل + أسفل ) محاكاة النقر على زر. من أجل تجنب كتابة هذا مرارا وتكرارا، وتريد أن تجعل من KeyUp معالج حدث عامة التي من شأنها رفع الحدث ButtonClick. للأسف، لا يبدو أن يكون الأسلوب في عنصر التحكم الذي يرفع الحدث 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).

لتفعل ذلك عن طريق التفكير، يمكنك ببساطة بحاجة الى ايجاد مجال مندوب الخاص، والحصول عليها، ثم استدعاء ذلك.

وكتبت امتدادا إلى الطبقات، والذي ينفذ INotifyPropertyChanged لحقن RaisePropertyChange طريقة، حتى أتمكن من استخدامها مثل هذا:

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;
        }
    }
}

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

وP.S. كان اقترض بعض أجزاء من رمز من شخص آخر. عار على لي، وأنني نسيت من أين حصلت عليه. : (

وكما اتضح، لم أستطع القيام بذلك، ولم أكن أدرك أنه:

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

ولكن إذا لم أستطع أن كنت تضطر إلى الخوض في شفرة المصدر والعثور على طريقة أن يثير هذا الحدث.

وشكرا للمساعدة، كل شيء.

من <وأ href = "http://social.msdn.microsoft.com/Forums/en-US/netfxbcl/thread/44b0d573-5c53-47b0-8e85-6056cbae95b0/" يختلط = "نوفولو noreferrer "> رفع حدث عن طريق التفكير ، على الرغم من أنني أعتقد أن الإجابة في VB.NET ، وهذا هو، وظيفتين قبل هذا واحد سوف توفر لك مع النهج العام (على سبيل المثال، ويهمني ان ننظر إلى VB.NET واحد للإلهام على الرجوع إلى نوع لا في نفس الفئة) :

 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. أنا لا يمكن رفع تلك الأحداث إذا أنا لا أريد لاستخلاص نوع جديد لكل نوع عنصر التحكم.

ويبدو أن رمز من تقبل الجواب من ايبي Cnossen يمكن تبسيط هذه الخطوط الملاحية المنتظمة واحد:

((Delegate)source.GetType().GetField(eventName, BindingFlags.Instance | BindingFlags.NonPublic).GetValue(source))
    .DynamicInvoke(source, eventArgs);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top