첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.

728x90
반응형
728x170

TestProject.zip
0.01MB

▶ CustomFocusScope.cs

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
    }
}

 

728x90

 

▶ MainWindow.xaml

<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

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
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요