2016-11-10 94 views
2

我推导出一个WPF TextBox控件来创建一个只接受美元货币值作为输入的控件。我知道这是以前做过的,并且有可以使用的现有库,但这更像是一次学习练习,因为尝试使用其中一种现有库控制失败 - 它不符合我的要求。在这样做时,我试图阻止文本框接受不符合美国货币格式(即可选的主要货币符号,十进制数字,可选组分隔符,可选分数组成部分)的文本。我知道有PreviewTextInput事件。我在Google上搜索的许多消息来源(得到社区的大量认可)表明,只需设置e.Handled = true即可处理此事件并拒绝不需要的输入(暂时不要使用复制/粘贴文本,更新数据绑定,或设计时XAML值,仅举几例)。当派生WPF控件时,是否可以保证控件的事件处理程序首先处理事件?

我一直在想这种方法是否一直工作。鉴于the order that event handlers are called is not guaranteed,我怎么知道我的控件的事件处理程序是第一次被调用?换句话说:我怎么知道某人的事件处理程序不是先运行,而是用允许我试图禁止的格式的值执行其他操作,然后设置e.Handled = true?那么OnPreviewTextInput方法呢?我相信有类似的担忧,不是吗?

+0

如果您创建自定义TextBox,然后使用它,然后创建PreviewTextInput,那么它将在您正在扩展的TextBox内部运行之前运行。我预览了预览键在PreviewTextInput之前运行,你可以在那里处理它。 – adminSoftDK

回答

0

这确实是一个非常好的问题。正如你所指出的,它是按照你如何注册事件处理程序的顺序排列的。如果你在运行时通过反射操作并改变处理程序的顺序,它可以按预期工作。我准备了一个scenerio正如你上面所说的。

这里我定义的属性

[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() 
    { 

    } 
} 

安迪创建自定义文件夹从文本框扩展

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

以上,即使有人创建

this.PreviewTextInput + = CustomBox_TextChanged; 处理程序操纵 文本框文本并将其更改为不愿意的文本并通过e.handle = true阻止另一个事件;

就在this.PreviewTextInput + = CustomBox_PreviewTextInput; 反映根据您的定义更改他们的订单。