1. Introduction
在 WPF 中,有两个与焦点有关的主要概念:键盘焦点和逻辑焦点。
-
键盘焦点与当前接收键盘输入的元素相关。 只能有一个具有键盘焦点的元素。 此具有键盘焦点的元素已 IsKeyboardFocused 设置为
true。 Keyboard.FocusedElement 返回具有键盘焦点的 元素。 -
焦点范围是一个容器元素,用于跟踪其范围内的 FocusManager.FocusedElement。 默认情况下,Window类与 、 ContextMenu和 ToolBar 类一样Menu是焦点范围。 作为焦点范围的元素已 IsFocusScope 设置为
true。
1.1 控件中Focusable = true
- Button
- Calendar
- ComboBox
- DataGrid
- DatePicker
- ListBox
- RichTextBox
- Slider
- TabControl
- TextBox
- TreeView
- Window
1.2 控件中Focusable = false
- Canvas
- DockPanel
- Grid
- Image
- Label
- ProgressBar
- ScrollBar
- Separator
- Shape 类型 (Ellipse, Line, Path, Polygon, Polyline, Rectangle)
- StackPanel
- TextBlock
- UniformGrid
- Viewport3D
- WrapPanel
2. Official Demo
非Prism項目,View直接對應下面的xxx.view.cs文件,很多動作都可以直接操作
Dispatcher.BeginInvoke
(
System.Windows.Threading.DispatcherPriority.Render,
new Action(() => textBox1.Focus())
);
3. Prism Demo
Prism項目將View和ViewModel進行註冊,無法在通過空間x:Name屬性直接操作
而且對應的變數和方法都要加上{Binding xxxxx}
注意:TextChanged事件是有個RoutedEventArgs參數TextChangedEventArgs,假如我們要拿到該TextChangedEventArgs或者是RoutedEventArgs參數裡面的屬性,常規操作不能做到的,這時候我們要用到prism自帶的InvokeCommandAction的TriggerParameterPath屬性,例如我們要在第一個TextBox,顯示我們第二個TextBox輸入的字元串加上觸發該事件的控制項的名字,那麼我們可以用到其父類RoutedEventArgs的Soucre屬性,而激發該事件的控制項就是第二個TextBox
<TextBox Grid.Column="1"
Margin="0,0,100,0"
x:Name="FocusXXXX"
TabIndex="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}">
<i:Interaction.Triggers>
<i:KeyTrigger Key="Return">
<prism:InvokeCommandAction Command="{Binding FocusCommand}"
TriggerParameterPath="Source" />
</i:KeyTrigger>
</i:Interaction.Triggers>
//內容校驗參考另一篇文章
<TextBox.Text>
<Binding Mode="TwoWay"
Path="PalletSN"
UpdateSourceTrigger="LostFocus">
<Binding.ValidationRules>
<rule:InformationCollectionValidationRule>
<rule:InformationCollectionValidationRule.Params>
<rule:ValidationParams Data="{Binding Source={StaticResource BindingProxy},Path=Data.XXXXRule}" />
</rule:InformationCollectionValidationRule.Params>
</rule:InformationCollectionValidationRule>
</Binding.ValidationRules>
</Binding>
</TextBox.Text>
</TextBox>
C#後端通過FocusCommand去解析xaml樹形結構
可以通過在xaml的控件加上x:Name,來進行debug
//第一步最重要,類型是對應的View目錄下的頁面
var parameter = obj as xxxx.Views.xxxxxxView;
var parentControl = parameter.Content as Grid;
var children = parentControl.Children;
foreach (var item in children)
{
if ("System.Windows.Controls.Grid".Equals(item.ToString()))
{
//第二個Grid
var controlItem = item as Grid;
System.Diagnostics.Trace.WriteLine("----Grid name : " + controlItem.Name);
var gridChildren = controlItem.Children;
//找到對應控件
var current = gridChildren[1] as MES.Common.Lib.Custom.CollectArea;
var informationCollection = current.Content as xxxxx;
var informatinGrid = informationCollection.Content as Grid;
var informationChildren = informatinGrid.Children;
foreach (var itemInformationChildren in informationChildren)
{
if ("System.Windows.Controls.StackPanel".Equals(itemInformationChildren.ToString())) {
var stackPanel = itemInformationChildren as StackPanel;
System.Diagnostics.Trace.WriteLine("---StackPanel name : " + stackPanel.Name);
var stackPanelChildren = stackPanel.Children;
foreach (var itemStackPanelChildren in stackPanelChildren)
{
var gridStackPanelChildren = itemStackPanelChildren as Grid;
System.Diagnostics.Trace.WriteLine("---StackPanel Grid name : " + gridStackPanelChildren.Name);
var gridInner = gridStackPanelChildren.Children;
foreach (var itemGridInner in gridInner)
{
System.Diagnostics.Trace.WriteLine("---item grid inner type : " + itemGridInner.ToString());
if ("System.Windows.Controls.TextBox".Equals(itemGridInner.ToString()))
{
var itemBox = itemGridInner as TextBox;
System.Diagnostics.Trace.WriteLine("---StackPanel Grid name : " + itemBox.Name);
}
}
}
}
}
}
}
4. Question
针对第三点扩展
- TriggerParameterPath这个参数只支持TextBox
- Behavior的触发条件不同,返回的数据也不同
4.1 KeyTrigger
返回的是整个xaml页面
<TextBox Grid.Column="1"
Margin="0,0,100,0"
x:Name="FocusXXXX"
TabIndex="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}">
<i:Interaction.Triggers>
<i:KeyTrigger Key="Return">
<prism:InvokeCommandAction Command="{Binding FocusCommand}"
TriggerParameterPath="Source" />
</i:KeyTrigger>
</i:Interaction.Triggers>
</TextBox>
4.2 EventTrigger
返回的是當前控件,包括其它事件,如GotFocus(獲取焦點事件),Loaded(加載事件)等
事件名稱參考 => juejin.cn/post/725963…
<TextBox Grid.Column="1"
Margin="0,0,100,0"
x:Name="FocusXXXX"
TabIndex="1"
Style="{StaticResource MaterialDesignOutlinedTextBox}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<prism:InvokeCommandAction Command="{Binding FocusOriginalCommand}"
TriggerParameterPath="Source" />
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBox>
5. 焦點轉移
5.1 Api
//直接調api
Keyboard.ClearFocus();
5.2 IsEnable
//使用4.2將當前控件傳遞到後端以後,私用TextBox接收
TextBox aaa = xxxx;
aaa.IsEnabled = false;
TextBox bbb = xxxx;
bbb.IsEnabled = true;
bbb.SelectAll();
bbb.Focus();