【6月日新计划28】WPF入门-焦點Focus

308 阅读3分钟

1. Introduction

在 WPF 中,有两个与焦点有关的主要概念:键盘焦点和逻辑焦点。

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文件,很多動作都可以直接操作

图片.png

   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();