Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Adding KeyUpCommand #463

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 101 additions & 0 deletions src/Uno.Toolkit.RuntimeTests/Tests/KeyUpCommandTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Threading.Tasks;
using System.Windows.Input;
using Uno.Toolkit.RuntimeTests.Helpers;
using Uno.Toolkit.UI;
using Uno.UI.RuntimeTests;
using Windows.System;
using Windows.UI.Input.Preview.Injection;
#if IS_WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
#endif

namespace Uno.Toolkit.RuntimeTests.Tests;

[TestClass]
[RunsOnUIThread]
internal class KeyUpCommandTests
{
[TestMethod]
public async Task OnKeyUp()
{
var viewModel = new ViewModel();
var page = new Page();
page.DataContext = viewModel;

page.SetBinding(InputExtensions.KeyUpCommandProperty, new Binding
{
Path = new PropertyPath(nameof(viewModel.KeyUpCommand)),
Mode = BindingMode.OneWay
});

await UnitTestUIContentHelperEx.SetContentAndWait(page);

InputInjector? inputInjector = InputInjector.TryCreate();

if (inputInjector != null)
{
var number0 = new InjectedInputKeyboardInfo
{
VirtualKey = (ushort)(VirtualKey.Number0),
KeyOptions = InjectedInputKeyOptions.KeyUp
};

page.Focus(FocusState.Pointer);
inputInjector.InjectKeyboardInput(new[] { number0 });
}

Assert.AreEqual("Number0 pressed", viewModel.Text);
}
}

public class ViewModel
{
public ICommand KeyUpCommand { get; }

public string Text { get; set; } = "Nothing pressed";

public ViewModel()
{
KeyUpCommand = new RelayCommand<VirtualKey>(key => Text = $"{key} pressed");
}
}

public class RelayCommand<T> : ICommand
{
private readonly Action<T> _execute;
private readonly Func<T, bool> _canExecute;

public RelayCommand(Action<T> execute, Func<T, bool>? canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute ?? (_ => true);
}

public bool CanExecute(object? parameter)
{
RaiseCanExecuteChanged();

return _canExecute((T)parameter!);
}

public void Execute(object? parameter)
{
_execute((T)parameter!);
}

public void RaiseCanExecuteChanged()
{
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

public event EventHandler? CanExecuteChanged;
}

Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@

<Import Project="Uno.Toolkit.RuntimeTests.props" />
<Import Project="..\winappsdk-workaround.targets" />
<ItemGroup>
<SourceGeneratorInput Remove="Tests\KeyUpCommandTests.cs" />
</ItemGroup>
</Project>
34 changes: 34 additions & 0 deletions src/Uno.Toolkit.UI/Behaviors/InputExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,40 @@ public static class InputExtensions
{
private static readonly ILogger _logger = typeof(InputExtensions).Log();

#region DependencyProperty: KeyUpCommand

/// <summary>
/// Backing property to trigger a command when a key is released.
/// </summary>
public static DependencyProperty KeyUpCommandProperty { get; } = DependencyProperty.RegisterAttached(
"KeyUpCommand", typeof(ICommand), typeof(InputExtensions), new PropertyMetadata(default(ICommand), OnKeyUpCommandChanged));

public static ICommand GetKeyUpCommand(UIElement element)
=> (ICommand)element.GetValue(KeyUpCommandProperty);

public static void SetKeyUpCommand(UIElement element, ICommand command)
=> element.SetValue(KeyUpCommandProperty, command);

private static void OnKeyUpCommandChanged(DependencyObject snd, DependencyPropertyChangedEventArgs args)
{
if (snd is UIElement elt)
{
elt.KeyUp -= OnKeyUp;
if (args.NewValue is ICommand)
{
elt.KeyUp += OnKeyUp;
}
}
}
private static void OnKeyUp(object snd, KeyRoutedEventArgs e)
{
if (snd is UIElement elt && GetKeyUpCommand(elt) is { } command
&& command.CanExecute(e.Key))
{
command.Execute(e.Key);
}
}
#endregion
#region DependencyProperty: AutoDismiss

/// <summary>
Expand Down