WPF中的焦點問題


一、WPF中的焦點

在 WPF 中,有兩個與焦點有關的主要概念:鍵盤焦點和邏輯焦點。 鍵盤焦點指接收鍵盤輸入的元素,而邏輯焦點指焦點范圍中具有焦點的元素。

參與焦點管理的主要類包括 Keyboard 類、 FocusManager 類和基元素類,如 UIElement 和 ContentElement 。

Keyboard類主要與鍵盤焦點相關,並 FocusManager 主要與邏輯焦點相關,但這並不是絕對差別。 具有鍵盤焦點的元素也具有邏輯焦點,但具有邏輯焦點的元素不一定具有鍵盤焦點。

二、鍵盤焦點

鍵盤檢點指當前正在接收鍵盤輸入的元素。在整個桌面上,只有一個具有鍵盤檢點的元素。在WPF中,具有鍵盤焦點的元素將IsKeyboardFocused 設置為 true 。 FocusedElement類上的靜態屬性 Keyboard 獲取當前具有鍵盤焦點的元素。

為了使元素能夠獲取鍵盤焦點, Focusable IsVisible 基本元素上的和屬性必須設置為 true 。 某些類,如 Panel 基類, Focusable 默認情況下將設置為 false ; 因此, Focusable true 如果希望此類元素能夠獲取鍵盤焦點,則必須將設置為。(可見、並可設置焦點)

編碼實現某控件獲取焦點

   Keyboard.Focus(firstButton);

三、邏輯焦點

邏輯焦點引用 FocusManager.FocusedElement 焦點范圍內的。 焦點作用域是跟蹤 FocusedElement 其作用域內的的元素。 鍵盤焦點離開焦點范圍時,焦點元素會失去鍵盤焦點,但保留邏輯焦點。 鍵盤焦點返回到焦點范圍時,焦點元素會再次獲得鍵盤焦點。 這使得鍵盤焦點可在多個焦點范圍之間切換,但確保了焦點返回到焦點范圍時,焦點范圍中的焦點元素重新獲得鍵盤焦點。

 FocusManager 附加屬性設置 IsFocusScope 為,可以在中將元素轉換為焦點范圍 true 。 在代碼中,可以通過調用將元素轉換為焦點范圍 SetIsFocusScope 。

xaml中

<StackPanel Name="focusScope1" 
            FocusManager.IsFocusScope="True"
            Height="200" Width="200">
  <Button Name="button1" Height="50" Width="50"/>
  <Button Name="button2" Height="50" Width="50"/>
</StackPanel>

.cs代碼

StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);

焦點范圍一般是 Window 和的類 MenuItem 、ToolBar 、ContextMenu 、PopUp(獨立焦點)

GetFocusedElement 獲取指定焦點范圍的聚焦元素。 SetFocusedElement 設置指定焦點范圍中的焦點元素。 SetFocusedElement 通常用於設置初始聚焦元素。

// Sets the focused element in focusScope1
// focusScope1 is a StackPanel.
FocusManager.SetFocusedElement(focusScope1, button2);

// Gets the focused element for focusScope 1
IInputElement focusedElement = FocusManager.GetFocusedElement(focusScope1);

四、鍵盤導航

KeyboardNavigation類負責在按下一個導航鍵時實現默認鍵盤焦點導航。 導航鍵包括:Tab、Shift+Tab、Ctrl+Tab、Ctrl+Shift+Tab、向上鍵、向下鍵、向左鍵和向右鍵。

可以通過設置附加的 KeyboardNavigation 屬性、和來更改導航容器的導航行為 TabNavigation ControlTabNavigation DirectionalNavigation 。 這些屬性的類型為 KeyboardNavigationMode ,可能的值為 Continue 、 Local 、 Contained 、 Cycle 、 Once 和 None 。 默認值為 Continue ,這意味着該元素不是導航容器。

 

五、編程方式控制焦點

用於處理焦點的其他 API 為 MoveFocus 和 PredictFocus 。

MoveFocus 將焦點更改為應用程序中的下一個元素。 TraversalRequest用於指定方向。 FocusNavigationDirection傳遞的用於 MoveFocus 指定可以移動的不同方向焦點,如 First 、 Last Up 和 Down 。

// Creating a FocusNavigationDirection object and setting it to a
// local field that contains the direction selected.
FocusNavigationDirection focusDirection = _focusMoveValue;

// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);

// Gets the element with keyboard focus.
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;

// Change keyboard focus.
if (elementWithFocus != null)
{
    elementWithFocus.MoveFocus(request);
}

六、焦點事件

與鍵盤焦點相關的事件為 PreviewGotKeyboardFocus 、 GotKeyboardFocus 和 PreviewLostKeyboardFocus LostKeyboardFocus 。 事件在類上定義為附加事件 Keyboard ,

七、跨進程和窗口控制焦點

win32API

SetFocus(hwnd);

八、復合控件的焦點控制

1、         自定義控件

  • 在UserControl標記中
<UserControl KeyboardNavigation.ControlTabNavigation="Local" IsTabStop="False">

KeyboardNavigation.ControlTabNavigation="Local" 設置焦點導航的方式,local可以把自定義控件中的子控件當做是引用窗體中的同級控件一樣對待。

IsTabStop="False" 防止焦點中斷,為了保證封裝性,建議在這里設置。

  • 子控件的TabIndex從父控件中獲取
<TextBox x:Name="txt2" TabIndex="{Binding Path=TabIndex, RelativeSource={RelativeSource AncestorType={x:Type local:CustomControl}}}"/>

CustomControl是自定義控件的名稱。

如果有多個子控件,建議調整標簽的前后順序。

2、 窗體

設置控件的TabIndex屬性,也可以使用KeyboardNavigation.TabIndex。

九、

<TextBox Height="30" Name="txtUserName" Text="{Binding UserNme}">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Triggers>
<DataTrigger Binding="{Binding IsFocus}" Value="True">
<Setter Property="FocusManager.FocusedElement" Value="{Binding ElementName=txtUserName}"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBox.Style>
</TextBox>
<TextBox x:Name="txt"   >
   <TextBox.Style>
       <Style TargetType="TextBox">
            <Setter Property="Template">
                 <Setter.Value>
                       <ControlTemplate TargetType="TextBox">
                           <Grid FocusManager.FocusedElement="{Binding ElementName=btn123}">
                              <Button x:Name="btn123" Content="123" Margin="10"/>
                             </Grid>
                        </ControlTemplate>
                   </Setter.Value>
             </Setter>
       </Style>
    </TextBox.Style>
 </TextBox>

Combobox.focus()獲取焦點

xt1.TabIndex = -1;就失去了焦點

十、焦點樣式

焦點視覺樣式的用途

焦點視覺樣式功能提供一種通用“對象模型”,用於基於任何 UI 元素的鍵盤導航來引入視覺用戶反饋。 即使未向控件應用新模板,或者不知道具體的模板組合,這也是可能的。

但是,正因為焦點視覺樣式功能可以在不知道控件模板的情況下工作,所以必須限制可針對使用焦點視覺樣式的控件顯示的視覺反饋。 此功能實際執行的操作是在控件通過模板進行呈現來創建可視化樹時在其上覆蓋另一可視化樹(裝飾器)。 使用填充屬性的樣式定義此單獨的可視化樹 FocusVisualStyle 。

默認焦點視覺樣式行為

焦點視覺樣式僅在焦點操作由鍵盤啟動時才起作用。 任何鼠標操作或者通過編程實現的焦點更改都會禁用焦點視覺樣式模式。 有關焦點模式間區別的詳細信息,請參閱焦點概述

控件的主題包括默認焦點視覺樣式行為,該焦點視覺樣式成為主題中所有控件的焦點視覺樣式。 此主題樣式由靜態鍵的值標識 FocusVisualStyleKey 。 當在應用程序級聲明自己的焦點視覺樣式時,將替換主題中的這一默認樣式行為。 或者,如果要定義整個主題,那么應同樣使用這個鍵來為整個主題的默認行為定義樣式。

在主題中,默認焦點視覺樣式通常非常簡單。 下面是一個近似的焦點視覺樣式:

<Style x:Key="{x:Static SystemParameters.FocusVisualStyleKey}">  
  <Setter Property="Control.Template">  
    <Setter.Value>  
      <ControlTemplate>  
        <Rectangle StrokeThickness="1"  
          Stroke="Black"  
          StrokeDashArray="1 2"  
          SnapsToDevicePixels="true"/>  
      </ControlTemplate>  
    </Setter.Value>  
  </Setter>  
</Style>  

 

何時使用焦點視覺樣式

從概念上來說,應用於控件的焦點視覺樣式的外觀在所有控件上應該是一致的。 確保一致性的一種方法是僅在創作整個主題時才更改焦點視覺樣式,這樣主題中定義的每個控件都要么獲得完全相同的焦點視覺樣式,要么獲得在視覺上與控件具有相關性的某一樣式的變體。 或者,可能使用相同的樣式(或類似的樣式)來設置頁面或 UI 中每個可通過鍵盤獲得焦點的元素的樣式。

十一、利用焦點事件更改顏色

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="{x:Type Button}">
      <Setter Property="Height" Value="20"/>
      <Setter Property="Width" Value="250"/>
      <Setter Property="HorizontalAlignment" Value="Left"/>
    </Style>
  </StackPanel.Resources>
  <Button
      GotFocus="OnGotFocusHandler"
      LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyboard Focus</Button>
  <Button
      GotFocus="OnGotFocusHandler"
      LostFocus="OnLostFocusHandler">Click Or Tab To Give Keyborad Focus</Button>
</StackPanel>

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM