WinUI ToggleSwitch์— Command ํ™•์žฅ

์‹ ๊ธฐํ•˜๊ฒŒ๋„ WinUI์˜ ToggleSwitch ์ปจํŠธ๋กค์— Command ์†์„ฑ์ด ์—†์Šต๋‹ˆ๋‹ค. Command์˜ ์žฅ์  ์ค‘ ํ•˜๋‚˜๊ฐ€ ์‹คํ–‰ํ•  ์ˆ˜ ์—†๋Š” ์ผ€์ด์Šค์˜ ๊ฒฝ์šฐ ๋น„ํ™œ์„ฑํ™” ํ•˜๋Š” ๊ธฐ๋Šฅ์ธ๋ฐ์š”, ์ด ๊ธฐ๋Šฅ ๋•Œ๋ฌธ์ด๋ผ๋„ Command๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

์‹œํ–‰์ฐฉ์˜ค๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. Command์˜ CanExecuteChanged ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ToggleSwitch ์ปจํŠธ๋กค์˜ ์ธ์Šคํ„ด์Šค๋ฅผ ์ฐพ์•„์•ผ ํ•˜๋Š”๋ฐ Attached Property๋กœ๋Š” ์•Œ ์ˆ˜ ์—†์œผ๋ฏ€๋กœ Behavior๋กœ ๋‹ค์‹œ ๊ตฌํ˜„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. ๊ธ€ ์˜ค๋ฅธ์ชฝ ์ƒ๋‹จ์˜ ์—ฐํ•„ ๋ชจ์–‘์„ ํ†ตํ•ด ์‹œํ–‰์ฐฉ์˜ค๋ฅผ ํ™•์ธํ•˜์„ธ์š”!

Command์™€ CommandParameter ๊ธฐ๋Šฅ์„ ํ™•์žฅํ•˜๋Š” Behavior๋ฅผ ๋‹ค์Œ์ฒ˜๋Ÿผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

| XAML

<ToggleSwitch IsOn="{x:Bind SelectedAttribute.IsKey, Mode=OneWay}">
    <interactivity:Interaction.Behaviors>
        <extensions:ToggleSwitchCommandBehavior Command="{x:Bind TogglePKCommand}" />
    </interactivity:Interaction.Behaviors>
</ToggleSwitch>

| ToggleSwitchCommandBehavior.cs

public class ToggleSwitchCommandBehavior : Behavior<ToggleSwitch>
{
    public readonly static DependencyProperty CommandProperty =
        DependencyProperty.Register(nameof(Command), typeof(ICommand), typeof(ToggleSwitchCommandBehavior),
            new PropertyMetadata(null, OnIsExternalChanged));

    public readonly static DependencyProperty CommandParameterProperty =
        DependencyProperty.Register(nameof(CommandParameter), typeof(object), typeof(ToggleSwitchCommandBehavior),
            new PropertyMetadata(null));

    private bool _isAccessUserInputProperty;

    public ICommand? Command
    {
        get => (ICommand)GetValue(CommandProperty);
        set => SetValue(CommandProperty, value);
    }

    public object? CommandParameter
    {
        get => GetValue(CommandParameterProperty);
        set => SetValue(CommandParameterProperty, value);
    }


    protected override void OnAttached()
    {
        AssociatedObject.PointerReleased += ToggleSwitch_PointerReleased;
        AssociatedObject.PreviewKeyDown += ToggleSwitch_PreviewKeyDown;
        AssociatedObject.Toggled += ToggleSwitch_Toggled;

        if (Command is not null)
        {
            Command_CanExecuteChanged(this, EventArgs.Empty);
        }
    }

    protected override void OnDetaching()
    {
        AssociatedObject.PointerReleased -= ToggleSwitch_PointerReleased;
        AssociatedObject.PreviewKeyDown -= ToggleSwitch_PreviewKeyDown;
        AssociatedObject.Toggled -= ToggleSwitch_Toggled;
    }

    private static void OnIsExternalChanged(object sender, DependencyPropertyChangedEventArgs args)
    {
        if (sender is not ToggleSwitchCommandBehavior @this)
            return;

        if (args.OldValue is ICommand oldCommand)
            oldCommand.CanExecuteChanged -= @this.Command_CanExecuteChanged;

        if (args.NewValue is ICommand newCommand)
        {
            newCommand.CanExecuteChanged += @this.Command_CanExecuteChanged;
            if (@this.AssociatedObject is not null)
                @this.Command_CanExecuteChanged(@this, EventArgs.Empty);
        }
    }

    private void Command_CanExecuteChanged(object? sender, EventArgs e)
    {
        if (Command is null)
            return;

        AssociatedObject.IsEnabled = Command.CanExecute(CommandParameter);
    }

    private void ToggleSwitch_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
    {
        if (e.Key is VirtualKey.Space)
        {
            _isAccessUserInputProperty = true;
        }
    }

    private void ToggleSwitch_PointerReleased(object sender, PointerRoutedEventArgs e)
    {
        _isAccessUserInputProperty = true;
    }

    private void ToggleSwitch_Toggled(object sender, RoutedEventArgs e)
    {
        var toggleSwitch = (ToggleSwitch)sender;

        // ์‚ฌ์šฉ์ž ์ž…๋ ฅ์ผ ๋•Œ๋งŒ ์ฒ˜๋ฆฌํ•˜๋„๋ก ํ•œ๋‹ค.
        if (_isAccessUserInputProperty is false)
            return;
        _isAccessUserInputProperty = false;

        if (Command is null)
            return;

        // ์ปค๋ฉ˜๋“œ์— ์˜ํ•ด ๊ฐ’์ด ๋ณ€ํ•˜๋„๋ก IsOn ๊ฐ’์„ ์›๋ณตํ•œ๋‹ค.
        toggleSwitch.IsOn = !toggleSwitch.IsOn;

        if (Command.CanExecute(CommandParameter))
            Command.Execute(CommandParameter);
    }
}
2๊ฐœ์˜ ์ข‹์•„์š”