2016-11-10 204 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; 反映根據您的定義更改他們的訂單。