■ 커스텀 포커스 범위를 사용하는 방법을 보여준다.
▶ CustomFocusScope.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
using System.Windows; using System.Windows.Input; using System.Windows.Media; namespace TestProject { /// <summary> /// 커스텀 포커스 범위 /// </summary> public static class CustomFocusScope { //////////////////////////////////////////////////////////////////////////////////////////////////// Dependency Property ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 커스텀 포커스 스코프 여부 첨부 속성 - IsCustomFocusScopeProperty /// <summary> /// 커스텀 포커스 스코프 여부 첨부 속성 /// </summary> public static readonly DependencyProperty IsCustomFocusScopeProperty = DependencyProperty.RegisterAttached ( "IsCustomFocusScope", typeof(bool), typeof(CustomFocusScope), new UIPropertyMetadata(false, IsCustomFocusScopePropertyChangedCallback) ); #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 커스텀 포커스 범위 여부 구하기 - GetIsCustomFocusScope(element) /// <summary> /// 커스텀 포커스 범위 여부 구하기 /// </summary> /// <param name="element">엘리먼트</param> /// <returns>커스텀 포커스 범위 여부</returns> public static bool GetIsCustomFocusScope(UIElement element) { return (bool)element.GetValue(IsCustomFocusScopeProperty); } #endregion #region 커스텀 포커스 범위 여부 설정하기 - SetIsCustomFocusScope(element, value) /// <summary> /// 커스텀 포커스 범위 여부 설정하기 /// </summary> /// <param name="element">엘리먼트</param> /// <param name="value">커스텀 포커스 범위 여부</param> public static void SetIsCustomFocusScope(UIElement element, bool value) { element.SetValue(IsCustomFocusScopeProperty, value); } #endregion #region 범위 내에서 활성 엘리먼트 포커스 설정하기 - SetFocusOnActiveElementInScope(focusScopeElement) /// <summary> /// 범위 내에서 활성 엘리먼트 포커스 설정하기 /// </summary> /// <param name="focusScopeElement">포커스 범위 엘리먼트</param> public static void SetFocusOnActiveElementInScope(UIElement focusScopeElement) { IInputElement focusedElement = FocusManager.GetFocusedElement(focusScopeElement); if(focusedElement != null) { Keyboard.Focus(focusedElement); } else { focusScopeElement.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } } #endregion //////////////////////////////////////////////////////////////////////////////// Private #region 커스텀 포커스 범위 여부 속성 변경시 콜백 처리하기 - IsCustomFocusScopePropertyChangedCallback(d, e) /// <summary> /// 커스텀 포커스 범위 여부 속성 변경시 콜백 처리하기 /// </summary> /// <param name="d">의존 객체</param> /// <param name="e">이벤트 인자</param> private static void IsCustomFocusScopePropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e) { UIElement element = d as UIElement; if(element == null) { return; } if((bool)e.NewValue) { FocusManager.SetIsFocusScope(element, true); element.GotKeyboardFocus += element_GotKeyboardFocus; } else { FocusManager.SetIsFocusScope(element, false); element.GotKeyboardFocus -= element_GotKeyboardFocus; } } #endregion #region 엘리먼트 키보드 포커스 획득시 처리하기 - element_GotKeyboardFocus(sender, e) /// <summary> /// 엘리먼트 키보드 포커스 획득시 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private static void element_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e) { IInputElement focusedElement = e.NewFocus; for(DependencyObject d = focusedElement as DependencyObject; d != null; d = VisualTreeHelper.GetParent(d)) { if(FocusManager.GetIsFocusScope(d)) { d.SetValue(FocusManager.FocusedElementProperty, focusedElement); if(!(bool)d.GetValue(IsCustomFocusScopeProperty)) { break; } } } } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
<Window x:Class="TestProject.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:TestProject" Width="800" Height="600" Title="커스텀 포커스 범위 사용하기" FontFamily="나눔고딕코딩" FontSize="16"> <Window.Resources> <Style TargetType="GroupBox"> <Setter Property="Background" Value="Transparent" /> <Setter Property="KeyboardNavigation.TabNavigation" Value="Cycle" /> <Setter Property="KeyboardNavigation.ControlTabNavigation" Value="Once" /> </Style> </Window.Resources> <Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="150" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="*" /> </Grid.ColumnDefinitions> <ToolBar Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"> <Button Margin="10 0 0 0" Command="Copy"> 복사 </Button> <Button Margin="10 0 0 0" Command="Cut"> 잘라내기 </Button> <Button Margin="10 0 0 0" Command="Paste"> 붙여넣기 </Button> </ToolBar> <TextBox Grid.Row="1" Grid.ColumnSpan="3" Margin="10" BorderThickness="1" BorderBrush="Black" Padding="10" AcceptsReturn="True"> A free text area </TextBox> <GroupBox Name="groupBox1" Grid.Row="2" Grid.Column="0" Header="포커스 범위 없음"> <StackPanel Margin="10"> <Button Height="30">A</Button> <Button Height="30">B</Button> <Button Height="30">C</Button> <TextBox Margin="0 10 0 0" Height="25" VerticalContentAlignment="Center" /> <CheckBox Margin="0 10 0 0">CheckBox</CheckBox> </StackPanel> </GroupBox> <GroupBox Name="groupBox2" Grid.Row="2" Grid.Column="1" Header="WPF 포커스 범위" FocusManager.IsFocusScope="True"> <StackPanel Margin="10"> <Button Height="30">A</Button> <Button Height="30">B</Button> <Button Height="30">C</Button> <TextBox Margin="0 10 0 0" Height="25" VerticalContentAlignment="Center" /> <CheckBox Margin="0 10 0 0">CheckBox</CheckBox> </StackPanel> </GroupBox> <GroupBox Name="groupBox3" Grid.Row="2" Grid.Column="2" Header="커스텀 포커스 범위" local:CustomFocusScope.IsCustomFocusScope="True"> <StackPanel Margin="10"> <Button Height="30">A</Button> <Button Height="30">B</Button> <Button Height="30">C</Button> <TextBox Margin="0 10 0 0" Height="25" VerticalContentAlignment="Center" /> <CheckBox Margin="0 10 0 0">CheckBox</CheckBox> </StackPanel> </GroupBox> </Grid> </Window> |
▶ MainWindow.xaml.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 |
using System.Reflection; using System.Windows; using System.Windows.Input; namespace TestProject { /// <summary> /// 메인 윈도우 /// </summary> public partial class MainWindow : Window { //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - MainWindow() /// <summary> /// 생성자 /// </summary> public MainWindow() { InitializeComponent(); this.groupBox1.MouseDown += groupBox1_MouseDown; this.groupBox2.MouseDown += groupBox2_MouseDown; this.groupBox3.MouseDown += groupBox3_MouseDown; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Private #region 그룹 박스 1 마우스 DOWN 처리하기 - groupBox1_MouseDown(sender, e) /// <summary> /// 그룹 박스 1 마우스 DOWN 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void groupBox1_MouseDown(object sender, MouseButtonEventArgs e) { object keyboardNavigation = typeof(KeyboardNavigation).InvokeMember ( "Current", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.GetProperty, null, null, null ); object activeElement = typeof(KeyboardNavigation).InvokeMember ( "GetActiveElement", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.InvokeMethod, null, keyboardNavigation, new object[] { this.groupBox1 } ); IInputElement focusedElement = activeElement as IInputElement; if(focusedElement != null) { Keyboard.Focus(focusedElement); } else { this.groupBox1.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } } #endregion #region 그룹 박스 2 마우스 DOWN 처리하기 - groupBox2_MouseDown(sender, e) /// <summary> /// 그룹 박스 2 마우스 DOWN 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void groupBox2_MouseDown(object sender, MouseButtonEventArgs e) { IInputElement focusedElement = FocusManager.GetFocusedElement(this.groupBox2); if(focusedElement != null) { Keyboard.Focus(focusedElement); } else { this.groupBox2.MoveFocus(new TraversalRequest(FocusNavigationDirection.First)); } } #endregion #region 그룹 박스 3 마우스 DOWN 처리하기 - groupBox3_MouseDown(sender, e) /// <summary> /// 그룹 박스 3 마우스 DOWN 처리하기 /// </summary> /// <param name="sender">이벤트 발생자</param> /// <param name="e">이벤트 인자</param> private void groupBox3_MouseDown(object sender, MouseButtonEventArgs e) { CustomFocusScope.SetFocusOnActiveElementInScope(this.groupBox3); } #endregion } } |