如果我有多个 TextBox 和其他文本插入控件,并且我想创建一些将特殊字符插入到焦点所在的 TextBox 中的按钮,那么最好的控件是什么以及应该设置哪些属性?
按键要求:
- 单击时按钮不会窃取焦点。
- 按钮可以将文本(例如特殊字符)插入到任何接受键盘输入的控件中。
- 光标应该像用户在键盘上输入文本一样移动。
如果#2 不可能,将控件限制为仅文本框就足够了。
注意:我不想让按钮无法聚焦,只是为了让它们在单击时不会窃取焦点。
如果我有多个 TextBox 和其他文本插入控件,并且我想创建一些将特殊字符插入到焦点所在的 TextBox 中的按钮,那么最好的控件是什么以及应该设置哪些属性?
按键要求:
如果#2 不可能,将控件限制为仅文本框就足够了。
注意:我不想让按钮无法聚焦,只是为了让它们在单击时不会窃取焦点。
我不知道单击时没有窃取焦点的任何按钮,但是在按钮单击事件句柄中,您可以将焦点返回给以前的所有者。如果我必须实现这一点,我会创建一个附加到所有特殊文本框的父面板和所有要插入一些文本的按钮的行为。
<StackPanel>
<i:Interaction.Behaviors>
<local:TextBoxStateTracker/>
</i:Interaction.Behaviors>
<TextBox />
<Button Content="description" Tag="?" />
</StackPanel>
为简单起见,我将要插入到文本框中的文本放在 Tag 属性中。
public class TextBoxStateTracker : Behavior<Panel>
{
private TextBox _previouslySelectedElement;
private int _selectionStart;
private int _selectionLength;
protected override void OnAttached()
{
//after control and all its children are created find textboxes and buttons
AssociatedObject.Initialized += (x, y) =>
{
var textBoxElements = FindChildren<TextBox>(AssociatedObject);
foreach (var item in textBoxElements)
{
item.LostFocus += new RoutedEventHandler(item_LostFocus);
}
var buttons = FindChildren<Button>(AssociatedObject);
foreach (var item in buttons)
{
item.Click += new RoutedEventHandler(item_Click);
}
};
}
private void item_Click(object sender, RoutedEventArgs e)
{
if (_previouslySelectedElement == null) return;
//simply replace selected text in previously focused textbox with whatever is in tag property
var button = (Button)sender;
var textToInsert = (string)button.Tag;
_previouslySelectedElement.Text = _previouslySelectedElement.Text.Substring(0, _selectionStart)
+ textToInsert +
_previouslySelectedElement.Text.Substring(_selectionStart + _selectionLength);
_previouslySelectedElement.Focus();
_previouslySelectedElement.SelectionStart = _selectionStart + textToInsert.Length;
}
private void item_LostFocus(object sender, RoutedEventArgs e)
{
//this method is fired when textboxes loose their focus note that this
//might not be fired by button click
_previouslySelectedElement = (TextBox)sender;
_selectionStart = _previouslySelectedElement.SelectionStart;
_selectionLength = _previouslySelectedElement.SelectionLength;
}
public List<TChild> FindChildren<TChild>(DependencyObject d)
where TChild : DependencyObject
{
List<TChild> children = new List<TChild>();
int childCount = VisualTreeHelper.GetChildrenCount(d);
for (int i = 0; i < childCount; i++)
{
DependencyObject o = VisualTreeHelper.GetChild(d, i);
if (o is TChild)
children.Add(o as TChild);
foreach (TChild c in FindChildren<TChild>(o))
children.Add(c);
}
return children;
}
}
这或多或少与您描述的一样,但远非完美,我认为这足以让您入门。
您需要覆盖标签和文本框的模板。
要求 1 和 2 - 可以在充当按钮的标签模板内完成。
要求 3 - 可以在文本框的模板内完成。
这并不容易……
您可能需要学习很多 WPF 样式、XAML 和重写控制模板。甚至可能创建一个自定义控件。