我有一个ListBox
带有可编辑的项目。首次编辑项目时,编辑控件(在此最小示例中为TextBox
)最初具有键盘焦点。第二次编辑项目时,TextBox
没有键盘焦点。如果您测试代码,则通过选择项目并按F2或Return将其置于编辑模式。
是否有任何合理且直接的方法使TextBox
在可见时始终获得键盘焦点?如果不这样做,是否存在不合理或间接的可靠方式?
始终使用编辑模板是不可行的,因为实际的编辑模板包括许多内容,例如300 px高的ListBox
和一千个选项,以及TextBox
用来过滤ListBox
的内容。我尝试使用 DevExpress GridControl 的CellTemplate
来执行此操作,但是出于各种原因,那是一罐蠕虫。
我交替显示/隐藏两个内容控件的原因是,当我仅将不同的模板交换到ListBox.ItemTemplate
中时,焦点便移交给了窗口。
XAML:
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<ListBox
ItemsSource="{Binding Items}"
>
<ListBox.Resources>
<DataTemplate x:Key="DisplayTemplate">
<Label Content="{Binding Value}" />
</DataTemplate>
<DataTemplate x:Key="EditTemplate">
<WrapPanel FocusManager.FocusedElement="{Binding ElementName=TextBox}" Focusable="False">
<Label>Editing:</Label>
<TextBox Margin="4,2,2,2" Text="{Binding Value}" x:Name="TextBox" />
</WrapPanel>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ContentControl x:Name="Display" Content="{Binding}" ContentTemplate="{StaticResource DisplayTemplate}" />
<ContentControl x:Name="Edit" Content="{Binding}" ContentTemplate="{StaticResource EditTemplate}" Visibility="Collapsed" />
</Grid>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsEditing}" Value="True">
<Setter TargetName="Edit" Property="Visibility" Value="Visible" />
<Setter TargetName="Display" Property="Visibility" Value="Collapsed" />
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<EventSetter Event="KeyDown" Handler="ListBoxItem_KeyDown" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
</Grid>
ViewModels.cs
public class ViewModel : ViewModelBase
{
public ViewModel()
{
Items = new ObservableCollection<ItemViewModel>(
new[] { "ytesadamy", "ugexudunamo", "wovaxatytol", "imuq" }.Select(s => new ItemViewModel() { Value = s }));
}
public ObservableCollection<ItemViewModel> Items { get; private set; }
}
public class ItemViewModel : ViewModelBase
{
#region Value Property
private String _value = default(String);
public String Value
{
get { return _value; }
set
{
if (value != _value)
{
_value = value;
OnPropertyChanged();
}
}
}
#endregion Value Property
#region IsEditing Property
private bool _isEditing = default(bool);
public bool IsEditing
{
get { return _isEditing; }
set
{
if (value != _isEditing)
{
_isEditing = value;
OnPropertyChanged();
}
}
}
#endregion IsEditing Property
}
#region ViewModelBase Class
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propName = null) =>
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName));
#endregion INotifyPropertyChanged
}
#endregion ViewModelBase Class
答案 0 :(得分:1)
我通常通过以下行为来做到这一点:
public static class FocusOnVisibleBehavior
{
public static readonly DependencyProperty FocusProperty = DependencyProperty.RegisterAttached(
"Focus",
typeof(bool),
typeof(FocusOnVisibleBehavior),
new PropertyMetadata(false, OnFocusChange));
public static void SetFocus(DependencyObject source, bool value)
{
source.SetValue(FocusProperty, value);
}
public static bool GetFocus(DependencyObject source)
{
return (bool)source.GetValue(FocusProperty);
}
private static void OnFocusChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var element = d as FrameworkElement;
DependencyPropertyChangedEventHandler handler = (sender, args) =>
{
if ((bool)args.NewValue)
{
// see http://stackoverflow.com/questions/13955340/keyboard-focus-does-not-work-on-text-box-in-wpf
element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate()
{
element.Focus(); // Set Logical Focus
Keyboard.Focus(element); // Set Keyboard Focus
//element.SelectAll();
}));
}
};
if (e.NewValue != null)
{
if ((bool)e.NewValue)
{
element.IsVisibleChanged += handler;
element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate ()
{
element.Focus(); // Set Logical Focus
Keyboard.Focus(element); // Set Keyboard Focus
//element.SelectAll();
}));
}
else
{
element.IsVisibleChanged -= handler;
}
}
// e.OldValue is never null because it's initialized to false via the PropertyMetadata()
// Hence, the effect here is that regardless of the value that's set, we first add the
// handler and then immediately remove it.
//if (e.NewValue != null)
//{
// element.IsVisibleChanged += handler;
// element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(delegate ()
// {
// element.Focus(); // Set Logical Focus
// Keyboard.Focus(element); // Set Keyboard Focus
// //element.SelectAll();
// }));
//}
//if (e.OldValue != null)
// element.IsVisibleChanged -= handler;
}
不记得是我自己编写此代码还是从其他地方获得此代码,无论您是这样使用它的:
<TextBox behaviors:FocusOnVisibleBehavior.Focus="True" ... etc ... />