WPF 및 초기 초점
WPF 응용 프로그램이 시작되면 포커스가없는 것 같습니다.
정말 이상합니다. 내가 사용한 다른 모든 프레임 워크는 예상 한대로 수행합니다. 첫 번째 컨트롤에 첫 번째 컨트롤을 탭 순서로 둡니다. 그러나 나는 그것이 내 응용 프로그램뿐만 아니라 WPF임을 확인했습니다. 새 창을 만들고 TextBox를 넣고 응용 프로그램을 실행하면 TextBox는 클릭하거나 Tab 키를 누를 때까지 포커스가 없습니다. . 왝.
내 실제 응용 프로그램은 TextBox보다 더 복잡합니다. UserControls 내에 여러 계층의 UserControl이 있습니다. 이러한 UserControl 중 하나에 Focusable = "True"및 KeyDown / KeyUp 핸들러가 있으며, 창이 열리 자마자 포커스를 갖기를 원합니다. 그래도 여전히 WPF 초보자이지만, 이것을하는 방법을 알아내는 데 많은 운이 없습니다.
앱을 시작하고 Tab 키를 누르면 포커스가 포커스 가능한 컨트롤로 이동하여 원하는 방식으로 작동하기 시작합니다. 그러나 사용자가 창을 사용하기 전에 Tab 키를 누르지 않기를 바랍니다.
FocusManager.FocusedElement를 가지고 놀았지만 컨트롤을 설정할 컨트롤 (최상위 Window 창, 포커스 가능한 컨트롤을 포함하는 부모, 포커스 가능한 컨트롤 자체) 또는 무엇을 설정할지 잘 모르겠습니다.
창을 열 자마자 깊게 중첩 된 컨트롤이 초기 초점을 갖도록하려면 어떻게해야합니까? 또는 탭 순서에서 첫 번째 포커스 가능한 컨트롤에 초점을 맞추는 것이 더 낫습니까?
Focusable 속성이 사용되는 위치를 확인하기 위해 Reflector를 파헤 치고이 솔루션으로가는 길을 찾았습니다. 내 창 생성자에 다음 코드를 추가하면됩니다.
Loaded += (sender, e) =>
MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
이것은 탭 순서에서 첫 번째 컨트롤을 자동으로 선택하므로 모든 창과 Just Work에 놓을 수있는 일반적인 솔루션입니다.
이것도 작동합니다.
<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">
<DataGrid x:Name="SomeElement">
...
</DataGrid>
</Window>
첨부 된 동작으로 구현 된 허용 된 답변을 기반으로합니다 .
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">
다른 가능한 해결책을 찾았습니다. Mark Smith는 FocusManager.FocusedElement와 함께 사용할 FirstFocusedElement 태그 확장 을 게시했습니다 .
<UserControl x:Class="FocusTest.Page2"
xmlns:FocusTest="clr-namespace:FocusTest"
FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
'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 초기 초점이 대부분 실패하므로 스레딩 문제를 사용해야합니다.
전체 앱에 대해 전 세계적으로 사용되는 다음 솔루션을 가장 잘 찾았습니다.
그것이 도움이되기를 바랍니다 ...
오란
동일한 문제로 간단한 해결책으로 해결했습니다. 메인 창에서 :
<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
}
XAML에서 컨트롤 자체를 포커스 된 요소로 쉽게 설정할 수 있습니다.
<Window>
<DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
...
</DataGrid>
</Window>
나는 이것을 usercontrol에서 설정하고 이것이 작동하는지 보지 않았지만 그것이 가능할 수도 있습니다.
C # 6+에 대한 Mizipzor의 최소 버전 .
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" />
당신이 나와 같고 어떻게 든 기본 초점 동작을 망치고 위의 모든 솔루션을 관련시키지 않는 프레임 워크를 사용하는 경우 여전히이 작업을 수행 할 수 있습니다.
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);
}
이것이 최후의 수단으로 도움이되기를 바랍니다.
나는 또한 같은 문제에 직면했다. 캔버스 컨테이너 안에 세 개의 텍스트 상자가 있었고 사용자 정의 컨트롤이 열릴 때 첫 번째 텍스트 상자에 초점을 맞추기를 원했습니다. 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>
위의 솔루션이 예상대로 작동하지 않았으므로 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();
}
ANd이 동작을 Window 또는 UserControl에 첨부하지 않지만 처음에는 다음과 같이 초점을 맞추고 싶습니다.
<TextBox ui:FocusBehavior.InitialFocus="True" />
Oh, sorry for different naming I'm using InitialFocus name for the attached property.
And this is working for me, maybe it could help someone else.
<Window FocusManager.FocusedElement="{Binding ElementName=yourControlName}">
참고URL : https://stackoverflow.com/questions/817610/wpf-and-initial-focus
'Programming' 카테고리의 다른 글
Android Studio 및 Gradle에서 -source 1.7을 설정하는 방법 (0) | 2020.05.20 |
---|---|
Rails 열 유형에 대한 설명서가 있습니까? (0) | 2020.05.20 |
물결표가 표현식 앞에있을 때 어떤 역할을합니까? (0) | 2020.05.20 |
SQL Server 스키마는 무엇입니까? (0) | 2020.05.19 |
고정 값을 가진 JPA의 enum을 매핑 하시겠습니까? (0) | 2020.05.19 |