It is indeed very good question.As you pointed it is ordered by how you registered the eventhandlers.If you manipulate via reflection at runtime and change the handlers order,it could work as it is expected.I prepared a scenerio just as you told above.
here I defined an attribute
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class CustomAttribute : Attribute
{
private int _value;
public int Value
{
get { return _value; }
set { _value = value; }
}
private string _eventName;
public string EventName
{
get { return _eventName; }
set { _eventName = value; }
}
public CustomAttribute()
{
}
}
andI created a custom box extended from TextBox
public class CustomBox : TextBox
{
public CustomBox()
{
this.PreviewTextInput += CustomBox_TextChanged;
this.PreviewTextInput += CustomBox_PreviewTextInput;
}
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
foreach (var item in typeof(CustomBox).GetRuntimeMethods().ToList())
{
var a = item.GetCustomAttributes();
// unsubscribe
foreach (var i in a)
{
if (i.GetType() == typeof(CustomAttribute))
{
if (((CustomAttribute)i).Value > 0)
{
RemoveEvent(((CustomAttribute)i).EventName, item.Name);
}
}
}
}
// subscribe according to your order
var methods = typeof(CustomBox).GetRuntimeMethods()
.Where(m => m.GetCustomAttributes(typeof(CustomAttribute), false).Length > 0)
.ToList();
foreach (var item in methods.OrderBy(m => ((CustomAttribute)m.GetCustomAttribute(typeof(CustomAttribute))).Value))
{
AddEvent(((CustomAttribute)item.GetCustomAttribute(typeof(CustomAttribute))).EventName, item.Name);
}
}
private void RemoveEvent(string eventName, string methodName)
{
EventInfo ev = this.GetType().GetEvent(eventName);
Type tDelegate = ev.EventHandlerType;
MethodInfo miHandler = typeof(CustomBox).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
ev.RemoveEventHandler(this, d);
}
private void AddEvent(string eventName,string methodName)
{
EventInfo ev = this.GetType().GetEvent(eventName);
Type tDelegate = ev.EventHandlerType;
MethodInfo miHandler = typeof(CustomBox).GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Instance);
Delegate d = Delegate.CreateDelegate(tDelegate, this, miHandler);
ev.AddEventHandler(this,d);
}
[CustomAttribute(EventName = "PreviewTextInput",Value = 2)]
private void CustomBox_TextChanged(object sender, TextCompositionEventArgs e)
{
this.Text = e.Text;
e.Handled = true;
}
[CustomAttribute(EventName = "PreviewTextInput", Value = 1)]
private void CustomBox_PreviewTextInput(object sender, TextCompositionEventArgs e)
{
if (e.Text.Contains("e"))
{
e.Handled = true;
}
else e.Handled = false;
}
}
Above, even if someone creates
this.PreviewTextInput += CustomBox_TextChanged;
handler that manipulates
textbox text and change it to unwilling text and blocks another event by e.handle = true;
just before this.PreviewTextInput += CustomBox_PreviewTextInput; is created,
Reflection changes their orders according to how you define.