如何使用交互行为在不同控件之间移动焦点?
How to move focus between different controls using Interactivity Behavior?
我有一个 WPF 应用程序,其中有一个 TextBox
和一个 ListBox
。受 this SO thread 的启发,我实现了一个行为,通过按下向下键,我可以将焦点从 TextBox
移动到 ListBox
。但是,问题是它只发生一次,即 OnIsFocusedChanged
只触发一次。谁能告诉我我遗漏了什么或做错了什么?
查看:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InteractivityTest"
xmlns:beh="clr-namespace:InteractivityTest.Behaviors"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<DataTemplate DataType="{x:Type local:AutoCopmleteTextBoxViewModel}">
<Grid Name="grMain">
<TextBox Name="myTextBox"
Text="{Binding MyText}"
Width="150">
<i:Interaction.Behaviors>
<beh:FocusBehavior IsFocused="{Binding TextBoxHasFocus}" />
</i:Interaction.Behaviors>
<TextBox.InputBindings>
<KeyBinding Key="Down"
Command="{Binding SetFocusToListBoxCommand}" />
</TextBox.InputBindings>
</TextBox>
<Popup Name="puSuggestions"
Placement="Bottom"
Width="{Binding ElementName=myTextBox, Path=ActualWidth}"
MinWidth="0"
PlacementTarget="{Binding ElementName=myTextBox}"
IsOpen="True">
<Border Background="White"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="1">
<ListBox Name="lbSuggestions"
ItemsSource="{Binding SuggestionCol}"
BorderThickness="0"
Background="White">
<i:Interaction.Behaviors>
<beh:FocusBehavior IsFocused="{Binding ListBoxHasFocus}" />
</i:Interaction.Behaviors>
</ListBox>
</Border>
</Popup>
</Grid>
</DataTemplate>
</ResourceDictionary>
ViewModel:
Imports System.ComponentModel
Public Class AutoCopmleteTextBoxViewModel
Implements INotifyPropertyChanged
Private _SuggestionCol As List(Of String)
Private _ListBoxHasFocus As Boolean
Private _TextBoxHasFocus As Boolean
Public Property SuggestionCol As List(Of String)
Get
Return New List(Of String) From {"A", "AB", "ABC", "ABCD"}
End Get
Set
_SuggestionCol = Value
NotifyPropertyChanged(NameOf(SuggestionCol))
End Set
End Property
Public Property ListBoxHasFocus As Boolean
Get
Return _ListBoxHasFocus
End Get
Set
_ListBoxHasFocus = Value
NotifyPropertyChanged(NameOf(ListBoxHasFocus))
End Set
End Property
Public Property TextBoxHasFocus As Boolean
Get
Return _TextBoxHasFocus
End Get
Set
_TextBoxHasFocus = Value
NotifyPropertyChanged(NameOf(TextBoxHasFocus))
End Set
End Property
Public Property SetFocusToListBoxCommand As ICommand
Sub New()
SetFocusToListBoxCommand = New Command(AddressOf Me.OnKeyDownOnTextBox, Nothing)
End Sub
Private Sub OnKeyDownOnTextBox(parameter As Object)
ListBoxHasFocus = True
TextBoxHasFocus = False
End Sub
#Region "Property Changed"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub NotifyPropertyChanged(info As [String])
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
#End Region
End Class
行为:
Imports System.Windows.Interactivity
Namespace Behaviors
Public Class FocusBehavior
Inherits Behavior(Of Control)
Public Property IsFocused As Boolean
Get
Return CBool(GetValue(IsFocusedProperty))
End Get
Set(ByVal value As Boolean)
SetValue(IsFocusedProperty, value)
End Set
End Property
Public Shared ReadOnly IsFocusedProperty As DependencyProperty =
DependencyProperty.Register(NameOf(IsFocused), GetType(Boolean),
GetType(FocusBehavior),
New PropertyMetadata(New PropertyChangedCallback(Sub(d, e)
OnIsFocusedChanged(d, e)
End Sub)))
Private Shared Sub OnIsFocusedChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
If CBool(e.NewValue) Then
CType(d, FocusBehavior).GotFocus()
End If
End Sub
Private Sub GotFocus()
Me.AssociatedObject.Focus()
Keyboard.Focus(Me.AssociatedObject)
If TypeOf Me.AssociatedObject Is TextBox Then
Dim tmpTextBox = TryCast(Me.AssociatedObject, TextBox)
tmpTextBox.CaretIndex = tmpTextBox.Text.Length
ElseIf TypeOf Me.AssociatedObject Is ListBox Then
Dim tmpListBox = TryCast(Me.AssociatedObject, ListBox)
If Not tmpListBox.Items.Count = 0 Then
tmpListBox.SelectedItem = tmpListBox.Items(0)
Dim tmpListBoxItem = TryCast(tmpListBox.ItemContainerGenerator.ContainerFromItem(tmpListBox.SelectedItem), ListBoxItem)
tmpListBoxItem.Focus()
End If
End If
End Sub
End Class
End Namespace
当依赖项 属性 的值设置为 new 值时,您正在调用 OnIsFocusedChanged
并且它似乎只设置为新的在您的 OnKeyDownOnTextBox
方法中值一次。
您需要更改 ListBoxHasFocus
和 TextBoxHasFocus
源属性的值,以便在 TextBox
或 ListBox
实际接收到焦点时重置它们。
我有一个 WPF 应用程序,其中有一个 TextBox
和一个 ListBox
。受 this SO thread 的启发,我实现了一个行为,通过按下向下键,我可以将焦点从 TextBox
移动到 ListBox
。但是,问题是它只发生一次,即 OnIsFocusedChanged
只触发一次。谁能告诉我我遗漏了什么或做错了什么?
查看:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:InteractivityTest"
xmlns:beh="clr-namespace:InteractivityTest.Behaviors"
xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity">
<DataTemplate DataType="{x:Type local:AutoCopmleteTextBoxViewModel}">
<Grid Name="grMain">
<TextBox Name="myTextBox"
Text="{Binding MyText}"
Width="150">
<i:Interaction.Behaviors>
<beh:FocusBehavior IsFocused="{Binding TextBoxHasFocus}" />
</i:Interaction.Behaviors>
<TextBox.InputBindings>
<KeyBinding Key="Down"
Command="{Binding SetFocusToListBoxCommand}" />
</TextBox.InputBindings>
</TextBox>
<Popup Name="puSuggestions"
Placement="Bottom"
Width="{Binding ElementName=myTextBox, Path=ActualWidth}"
MinWidth="0"
PlacementTarget="{Binding ElementName=myTextBox}"
IsOpen="True">
<Border Background="White"
BorderBrush="Gray"
BorderThickness="1"
CornerRadius="1">
<ListBox Name="lbSuggestions"
ItemsSource="{Binding SuggestionCol}"
BorderThickness="0"
Background="White">
<i:Interaction.Behaviors>
<beh:FocusBehavior IsFocused="{Binding ListBoxHasFocus}" />
</i:Interaction.Behaviors>
</ListBox>
</Border>
</Popup>
</Grid>
</DataTemplate>
</ResourceDictionary>
ViewModel:
Imports System.ComponentModel
Public Class AutoCopmleteTextBoxViewModel
Implements INotifyPropertyChanged
Private _SuggestionCol As List(Of String)
Private _ListBoxHasFocus As Boolean
Private _TextBoxHasFocus As Boolean
Public Property SuggestionCol As List(Of String)
Get
Return New List(Of String) From {"A", "AB", "ABC", "ABCD"}
End Get
Set
_SuggestionCol = Value
NotifyPropertyChanged(NameOf(SuggestionCol))
End Set
End Property
Public Property ListBoxHasFocus As Boolean
Get
Return _ListBoxHasFocus
End Get
Set
_ListBoxHasFocus = Value
NotifyPropertyChanged(NameOf(ListBoxHasFocus))
End Set
End Property
Public Property TextBoxHasFocus As Boolean
Get
Return _TextBoxHasFocus
End Get
Set
_TextBoxHasFocus = Value
NotifyPropertyChanged(NameOf(TextBoxHasFocus))
End Set
End Property
Public Property SetFocusToListBoxCommand As ICommand
Sub New()
SetFocusToListBoxCommand = New Command(AddressOf Me.OnKeyDownOnTextBox, Nothing)
End Sub
Private Sub OnKeyDownOnTextBox(parameter As Object)
ListBoxHasFocus = True
TextBoxHasFocus = False
End Sub
#Region "Property Changed"
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub NotifyPropertyChanged(info As [String])
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(info))
End Sub
#End Region
End Class
行为:
Imports System.Windows.Interactivity
Namespace Behaviors
Public Class FocusBehavior
Inherits Behavior(Of Control)
Public Property IsFocused As Boolean
Get
Return CBool(GetValue(IsFocusedProperty))
End Get
Set(ByVal value As Boolean)
SetValue(IsFocusedProperty, value)
End Set
End Property
Public Shared ReadOnly IsFocusedProperty As DependencyProperty =
DependencyProperty.Register(NameOf(IsFocused), GetType(Boolean),
GetType(FocusBehavior),
New PropertyMetadata(New PropertyChangedCallback(Sub(d, e)
OnIsFocusedChanged(d, e)
End Sub)))
Private Shared Sub OnIsFocusedChanged(ByVal d As DependencyObject, ByVal e As DependencyPropertyChangedEventArgs)
If CBool(e.NewValue) Then
CType(d, FocusBehavior).GotFocus()
End If
End Sub
Private Sub GotFocus()
Me.AssociatedObject.Focus()
Keyboard.Focus(Me.AssociatedObject)
If TypeOf Me.AssociatedObject Is TextBox Then
Dim tmpTextBox = TryCast(Me.AssociatedObject, TextBox)
tmpTextBox.CaretIndex = tmpTextBox.Text.Length
ElseIf TypeOf Me.AssociatedObject Is ListBox Then
Dim tmpListBox = TryCast(Me.AssociatedObject, ListBox)
If Not tmpListBox.Items.Count = 0 Then
tmpListBox.SelectedItem = tmpListBox.Items(0)
Dim tmpListBoxItem = TryCast(tmpListBox.ItemContainerGenerator.ContainerFromItem(tmpListBox.SelectedItem), ListBoxItem)
tmpListBoxItem.Focus()
End If
End If
End Sub
End Class
End Namespace
当依赖项 属性 的值设置为 new 值时,您正在调用 OnIsFocusedChanged
并且它似乎只设置为新的在您的 OnKeyDownOnTextBox
方法中值一次。
您需要更改 ListBoxHasFocus
和 TextBoxHasFocus
源属性的值,以便在 TextBox
或 ListBox
实际接收到焦点时重置它们。