我正在派生一个WPF TextBox
控件来创建一个只接受美元货币值作为输入的控件。我知道之前已经完成了这项工作,并且我可以使用现有的库,但这更像是一种学习练习,因为尝试使用其中一种现有的库控件失败 - 它不符合我的要求
在这样做时,我试图阻止文本框接受不符合美国货币格式的文本(即可选的主要货币符号,十进制数,可选的组分隔符,可选的小数部分)。我知道有PreviewTextInput
事件。我用google搜索的许多来源建议(得到社区的大力赞同),人们可以通过设置e.Handled = true
来简单地处理此事件并拒绝不需要的输入(暂时搁置这对于复制/粘贴文本不起作用,更新数据绑定或设计时XAML值,仅举几例。
我一直想知道这种方法是否一直有效。鉴于the order that event handlers are called is not guaranteed,我怎么知道我的控件的事件处理程序首先被调用?换句话说:我怎么知道有人的事件处理程序没有先运行,并使用允许我试图禁止的格式然后设置e.Handled = true
的值执行其他操作? OnPreviewTextInput
方法怎么样?我相信它会受到类似的担忧,不是吗?
答案 0 :(得分:0)
这确实是一个非常好的问题。正如你所指出的,它是按照你如何注册eventhandlers的顺序排序的。如果你在运行时通过反射操作并改变处理程序顺序,它可以按预期工作。我准备了一个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()
{
}
}
我创建了一个从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;
}
}
以上,即使有人创建
this.PreviewTextInput + = CustomBox_TextChanged; 操纵的处理程序 文本框文本并将其更改为不愿意的文本,并通过e.handle = true;
阻止另一个事件就在此之前.PreviewTextInput + = CustomBox_PreviewTextInput;被建造, 反射根据您的定义更改订单。