似乎当WPF应用程序启动时,没有任何焦点。
这真的很奇怪。我使用的每个其他框架都符合您的期望:将初始焦点放在Tab键顺序中的第一个控件上。但我已经确认它是WPF,而不仅仅是我的应用程序 - 如果我创建一个新窗口,只是在其中放置一个TextBox,并运行应用程序,TextBox没有焦点,直到我点击它或按Tab键。呸。
我的实际应用程序比TextBox更复杂。我在UserControls中有几层UserControl。其中一个UserControls有Focusable =“True”和KeyDown / KeyUp处理程序,我希望它在我的窗口打开后立即获得焦点。不过,我仍然是一名WPF新手,而且我很难找到如何做到这一点。
如果我启动我的应用程序并按Tab键,则焦点转到我的可聚焦控件,它会按照我想要的方式开始工作。但我不希望我的用户在开始使用窗口之前必须点击Tab。
我玩过FocusManager.FocusedElement,但是我不确定将它设置为哪个控件(顶级窗口?包含可聚焦控件的父级?可聚焦控件本身?)或者要设置什么它来。
一旦窗口打开,我需要做什么才能使我的深层嵌套控件具有初始焦点?或者更好的是,将第一个可聚焦控件聚焦在Tab键顺序中?
答案 0 :(得分:152)
我有一个聪明的主意,就是通过Reflector来查看Focusable属性的使用位置,并找到了解决这个问题的方法。我只需要将以下代码添加到我的Window的构造函数中:
Loaded += (sender, e) =>
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
这将自动选择Tab键顺序中的第一个控件,因此它是一个通用的解决方案,应该可以放入任何窗口并且Just Work。
答案 1 :(得分:140)
这也有效:
<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">
<DataGrid x:Name="SomeElement">
...
</DataGrid>
</Window>
答案 2 :(得分:57)
基于已作为附加行为实施的已接受answer:
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace UI.Behaviors
{
public static class FocusBehavior
{
public static readonly DependencyProperty FocusFirstProperty =
DependencyProperty.RegisterAttached(
"FocusFirst",
typeof(bool),
typeof(FocusBehavior),
new PropertyMetadata(false, OnFocusFirstPropertyChanged));
public static bool GetFocusFirst(Control control)
{
return (bool)control.GetValue(FocusFirstProperty);
}
public static void SetFocusFirst (Control control, bool value)
{
control.SetValue(FocusFirstProperty, value);
}
static void OnFocusFirstPropertyChanged(
DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
Control control = obj as Control;
if (control == null || !(args.NewValue is bool))
{
return;
}
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) =>
control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
}
}
}
像这样使用:
<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
Behaviors:FocusBehavior.FocusFirst="true">
答案 3 :(得分:14)
我找到了另一种可能的解决方案。 Mark Smith发布了一个FirstFocusedElement markup extension用于FocusManager.FocusedElement。
<UserControl x:Class="FocusTest.Page2"
xmlns:FocusTest="clr-namespace:FocusTest"
FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
答案 4 :(得分:8)
在'WPF初始焦点噩梦'并基于堆栈上的一些答案后,以下证明我是最佳解决方案。
首先,添加App.xaml OnStartup()以下内容:
EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
new RoutedEventHandler(WindowLoaded));
然后在App.xaml中添加'WindowLoaded'事件:
void WindowLoaded(object sender, RoutedEventArgs e)
{
var window = e.Source as Window;
System.Threading.Thread.Sleep(100);
window.Dispatcher.Invoke(
new Action(() =>
{
window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}));
}
必须使用线程问题,因为WPF的初始焦点主要是由于某些框架竞争条件而失败。
我发现以下解决方案最佳,因为它在整个应用程序中全局使用。
希望它有所帮助...
奥兰
答案 5 :(得分:8)
同样的问题通过简单的解决方案解决了它: 在主窗口中:
<Window ....
FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
... />
在用户控件中:
private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
{
targetcontrol.Focus();
this.GotFocus -= UserControl_GotFocus_1; // to set focus only once
}
答案 6 :(得分:8)
您可以轻松地将控件设置为XAML中的聚焦元素。
<Window>
<DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
...
</DataGrid>
</Window>
我从来没有尝试过在用户控件中设置它并看看它是否有效,但它可能会。
答案 7 :(得分:1)
C#6 +的最小版本Mizipzor's answer。
public static class FocusBehavior
{
public static readonly DependencyProperty GiveInitialFocusProperty =
DependencyProperty.RegisterAttached(
"GiveInitialFocus",
typeof(bool),
typeof(FocusBehavior),
new PropertyMetadata(false, OnFocusFirstPropertyChanged));
public static bool GetGiveInitialFocus(Control control) => (bool)control.GetValue(GiveInitialFocusProperty);
public static void SetGiveInitialFocus(Control control, bool value) => control.SetValue(GiveInitialFocusProperty, value);
private static void OnFocusFirstPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
var control = obj as Control;
if (control == null || !(args.NewValue is bool))
return;
if ((bool)args.NewValue)
control.Loaded += OnControlLoaded;
else
control.Loaded -= OnControlLoaded;
}
private static void OnControlLoaded(object sender, RoutedEventArgs e) => ((Control)sender).MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
在您的XAML中使用:
<Window local:FocusBehavior.GiveInitialFocus="True" />
答案 8 :(得分:1)
如果你像我一样,并且你正在使用一些框架,以某种方式,搞乱基本的焦点行为,并使所有解决方案无关紧要,你仍然可以这样做:
1 - 注意获得焦点的元素(无论它是什么!)
2 - 在xxx.xaml.cs后面的代码中添加它
private bool _firstLoad;
3 - 在获得第一个焦点的元素上添加它:
GotFocus="Element_GotFocus"
4 - 在后面的代码中添加Element_GotFocus方法,并指定需要第一个焦点的WPF命名元素:
private void Element_GotFocus(object sender, RoutedEventArgs e)
{
if(_firstLoad)
{
this.MyElementWithFistFocus.Focus();
_firstLoad = false;
}
}
5 - 管理已加载的活动
在XAML中
Loaded="MyWindow_Loaded"
xaml.cs中的
private void MyWindow_Loaded(object sender, RoutedEventArgs e)
{
_firstLoad = true;
this.Element_GotFocus(null, null);
}
希望这将有助于作为最后的解决方案
答案 9 :(得分:0)
我也遇到了同样的问题。我在canvas容器中有三个文本框,并希望在用户控件打开时聚焦第一个文本框。 WPF代码遵循MVVM模式。我创建了一个单独的行为类来聚焦元素并将其绑定到我的视图中。
画布行为代码
public class CanvasLoadedBehavior : Behavior<Canvas>
{
private Canvas _canvas;
protected override void OnAttached()
{
base.OnAttached();
_canvas = AssociatedObject as Canvas;
if (_canvas.Name == "ReturnRefundCanvas")
{
_canvas.Loaded += _canvas_Loaded;
}
}
void _canvas_Loaded(object sender, RoutedEventArgs e)
{
FocusNavigationDirection focusDirection = FocusNavigationDirection.Next;
// MoveFocus takes a TraveralReqest as its argument.
TraversalRequest request = new TraversalRequest(focusDirection);
UIElement elementWithFocus = Keyboard.FocusedElement as UIElement;
if (elementWithFocus != null)
{
elementWithFocus.MoveFocus(request);
}
}
}
视图代码
<Canvas Name="ReturnRefundCanvas" Height="200" Width="1466" DataContext="{Binding RefundSearchViewModel}">
<i:Interaction.Behaviors>
<b:CanvasLoadedBehavior />
</i:Interaction.Behaviors>
<uc:Keyboard Canvas.Left="973" Canvas.Top="111" ToolTip="Keyboard" RenderTransformOrigin="-2.795,9.787"></uc:Keyboard>
<Label Style="{StaticResource Devlbl}" Canvas.Left="28" Content="Return and Refund Search" Canvas.Top="10" />
<Image Height="30" Width="28" Canvas.Top="6" Canvas.Left="5" Source="pack://application:,,,/HomaKiosk;component/images/searchF.png">
<Image.OpacityMask>
<ImageBrush ImageSource="pack://application:,,,/HomaKiosk;component/images/searchF.png"/>
</Image.OpacityMask>
</Image>
<Separator Height="4" Canvas.Left="6" Margin="0" Canvas.Top="35" Width="1007"/>
<ContentControl Canvas.Top="45" Canvas.Left="21"
ContentTemplate="{StaticResource ErrorMsg}"
Visibility="{Binding Error, Converter={c:StringNullOrEmptyToVisibilityConverter}}"
Content="{Binding Error}" Width="992"></ContentControl>
<Label Style="{StaticResource Devlbl}" Canvas.Left="29" Name="FirstName" Content="First Name" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" Canvas.Left="33" ToolTip="First Name" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1001"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding FirstName, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding FirstNameSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
</wpf:AutoCompleteTextBox>
<Label Style="{StaticResource Devlbl}" Canvas.Left="250" Content="Last Name" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" ToolTip="Last Name" Canvas.Left="250" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1002"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding LastName, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding LastNameSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding}"
FontWeight="Bold" />
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
</wpf:AutoCompleteTextBox>
<Label Style="{StaticResource Devlbl}" Canvas.Left="480" Content="Receipt No" Canvas.Top="90" />
<wpf:AutoCompleteTextBox Style="{StaticResource AutoComp}" Height="32" ToolTip="Receipt No" Canvas.Left="480" Canvas.Top="120" Width="205" Padding="10,5" TabIndex="1002"
VerticalAlignment="Top"
Watermark=""
IconPlacement="Left"
IconVisibility="Visible"
Delay="100"
Text="{Binding ReceiptNo, Mode=TwoWay, TargetNullValue=''}"
Provider="{Binding ReceiptIdSuggestions}">
<wpf:AutoCompleteTextBox.ItemTemplate>
<DataTemplate>
<Border Padding="5">
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding}"
FontWeight="Bold">
</TextBlock>
</StackPanel>
</Border>
</DataTemplate>
</wpf:AutoCompleteTextBox.ItemTemplate>
<i:Interaction.Behaviors>
<b:AllowableCharactersTextBoxBehavior RegularExpression="^[0-9]+$" MaxLength="15" />
</i:Interaction.Behaviors>
</wpf:AutoCompleteTextBox>
<!--<Label Style="{StaticResource Devlbl}" Canvas.Left="710" Content="Duration" Canvas.Top="79" />-->
<!--<ComboBox AllowDrop="True" Canvas.Left="710" ToolTip="Duration" Canvas.Top="107" Width="205" TabIndex="1004"
Style="{StaticResource CommonComboBox}"
ItemsSource="{Binding Durations}" DisplayMemberPath="Description" SelectedValuePath="Id" SelectedValue="{Binding SelectedDate, Mode=TwoWay}">
</ComboBox>-->
<Button Content="Search" Style="{StaticResource MyButton}" ToolTip="Search"
Canvas.Top="116" Canvas.Left="710" Cursor="Hand"
Command="{Binding SearchCommand}" TabIndex="2001">
</Button>
<Button Content="Clear" Style="{StaticResource MyButton}" ToolTip="Clear"
Canvas.Top="116" Canvas.Left="840" Cursor="Hand"
Command="{Binding ClearCommand}" TabIndex="2002">
</Button>
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="25" Source="pack://application:,,,/HomaKiosk;component/images/chkpending.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="50" Content="Check Returned and Payment Pending" Canvas.Top="178" />
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="300" Source="pack://application:,,,/HomaKiosk;component/images/chkrepaid.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="325" Content="Repaid" Canvas.Top="178" />
<Image Height="25" Width="25" Canvas.Top="175" Canvas.Left="395" Source="pack://application:,,,/HomaKiosk;component/images/refund.png"/>
<Label Style="{StaticResource LegendLbl}" Canvas.Left="415" Content="Refunded" Canvas.Top="178" />
</Canvas>
答案 10 :(得分:0)
以上解决方案对我来说没有按预期工作,我稍微改变了Mizipzor提出的行为如下:
从这部分
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) =>
control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
}
到此
if ((bool)args.NewValue)
{
control.Loaded += (sender, e) => control.Focus();
}
我没有将这种行为附加到Window或UserControl,而是控制我想要最初聚焦,例如:
<TextBox ui:FocusBehavior.InitialFocus="True" />
哦,对不同的命名,我正在使用附加属性的InitialFocus名称。
这对我有用,也许它可以帮助别人。
答案 11 :(得分:-1)
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">