Как связать нажатие клавиши на клавиатуре и анимацию конкретной кнопки
В чем соль: пытаюсь учиться программированию на C# для создания графических приложений под Windows. Вот захотел сделать калькулятор на WPF. Соответственно, хочу сделать все в более или менее приемлемом для меня виде, то есть с хоть какой-нибудь анимацией и т.д. И споткнулся на одном шаге: хочу связать нажатия клавиш и реакцию кнопок на эти нажатия. То есть как в калькуляторе в Windows: нажал на единичку - проигралась анимация нажатия кнопки с цифрой 1. И я не знаю, как связать нажатие клавиши на клавиатуре и проигрывание анимации кнопки, соответствующей клавише клавиатуры.
<Window x:Class="SpaceFly.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SpaceFly"
xmlns:fd="clr-namespace:System.Collections.Generic;assembly=mscorlib"
mc:Ignorable="d"
Title="Калькулятор" Height="600" Width="400"
Background="Black"
KeyDown="Window_KeyDown">
<Window.Resources>
<ControlTemplate x:Key="ButtTemplate" TargetType="Button">
<Border CornerRadius="10" Name="border" DataContext="">
<Border.Background>
<SolidColorBrush Color="#ff8e00"/>
</Border.Background>
<ContentPresenter
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Center"
VerticalAlignment="Center">
</ContentPresenter>
</Border>
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="MouseEnter">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="border"
Duration="0:0:0.05"
Storyboard.TargetProperty="Background.Color"
To="#ee8400">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseLeave">
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="border"
Duration="0:0:0.02"
Storyboard.TargetProperty="Background.Color"
To="#ff8e00">
</ColorAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="MouseDown">
<BeginStoryboard>
<Storyboard>
<ColorAnimationUsingKeyFrames Storyboard.TargetName="border"
Storyboard.TargetProperty="Background.Color"
Duration="0:0:0.2">
<LinearColorKeyFrame Value="#d57700"
KeyTime="0:0:0.1"/>
<LinearColorKeyFrame Value="#ff8e00"
KeyTime="0:0:0.2"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Viewbox Grid.ColumnSpan="4"
Grid.Row="0"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
>
<TextBox BorderThickness="0"
Name="DataText"
IsReadOnly="True"
Background="Black"
MaxLength="16"
FontSize="90"
Foreground="White"
HorizontalContentAlignment="Right"
VerticalContentAlignment="Center"
>
0
</TextBox>
</Viewbox>
<Button x:Name="ButtProcent"
Grid.Row="1"
Grid.Column="0"
Content="%"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Procent"
>
</Button>
<Button x:Name="ButtCE"
Grid.Row="1"
Grid.Column="1"
Content="CE"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Delete"
/>
<Button x:Name="ButtDelete"
Grid.Row="1"
Grid.Column="2"
Content="<-"
Grid.ColumnSpan="2"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
/>
<Button x:Name="ButtTurn"
Grid.Row="2"
Grid.Column="0"
Content="1/x"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Turn"
/>
<Button x:Name="ButtSqr"
Grid.Row="2"
Grid.Column="1"
Content="x^2"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Sqr"
/>
<Button x:Name="ButtSqrt"
Grid.Row="2"
Grid.Column="2"
Content="x^0.5"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
/>
<Button x:Name="ButtDiv"
Grid.Row="2"
Grid.Column="3"
Content="/"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Division"
/>
<Button x:Name="ButtNum1"
Grid.Row="3"
Grid.Column="0"
Content="1"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="1"
/>
<Button x:Name="ButtNum2"
Grid.Row="3"
Grid.Column="1"
Content="2"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="2"
/>
<Button x:Name="ButtNum3"
Grid.Row="3"
Grid.Column="2"
Content="3"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="3"
/>
<Button x:Name="ButtMult"
Grid.Row="3"
Grid.Column="3"
Content="*"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Multiply"
/>
<Button x:Name="ButtNum4"
Grid.Row="4"
Grid.Column="0"
Content="4"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="4"
/>
<Button x:Name="ButtNum5"
Grid.Row="4"
Grid.Column="1"
Content="5"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="5"
/>
<Button x:Name="ButtNum6"
Grid.Row="4"
Grid.Column="2"
Content="6"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="6"
/>
<Button x:Name="ButtDiff"
Grid.Row="4"
Grid.Column="3"
Content="-"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Difference"
/>
<Button x:Name="ButtNum7"
Grid.Row="5"
Grid.Column="0"
Content="7"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="7"
/>
<Button x:Name="ButtNum8"
Grid.Row="5"
Grid.Column="1"
Content="8"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="8"
/>
<Button x:Name="ButtNum9"
Grid.Row="5"
Grid.Column="2"
Content="9"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="9"
/>
<Button x:Name="ButtSum"
Grid.Row="5"
Grid.Column="3"
Content="+"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Sum"
/>
<Button x:Name="ButtPlusOrMin"
Grid.Row="6"
Grid.Column="0"
Content="+/-"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
/>
<Button x:Name="ButtNum0"
Grid.Row="6"
Grid.Column="1"
Content="0"
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="0"
/>
<Button x:Name="ButtPoint"
Grid.Row="6"
Grid.Column="2"
Content=","
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Point"
/>
<Button x:Name="ButtEqual"
Grid.Row="6"
Grid.Column="3"
Content="="
FontSize="30"
Margin="5,5,5,5"
Foreground="White"
Template="{StaticResource ButtTemplate}"
Tag="Equal"
/>
</Grid>
</Window>
Ответы (1 шт):
Небольшой примерчик. Не смог нормально разобраться с анимациями по нажатию клавиши, но заставил работать это через код. Уверен, что существует более адекватное решение.
Поправил анимацию клика. Выбросил часть дублирующего кода.
Получилась такая разметка:
<Window.Resources>
<Storyboard x:Key="StoryboardFocus">
<ColorAnimation Storyboard.TargetName="border"
Duration="0:0:0.05"
Storyboard.TargetProperty="Background.Color"
To="#ffae10"/>
</Storyboard>
<Storyboard x:Key="StoryboardRestore">
<ColorAnimation Storyboard.TargetName="border"
Duration="0:0:0.05"
Storyboard.TargetProperty="Background.Color"
To="#ff8e00"/>
</Storyboard>
<Storyboard x:Key="StoryboardHover">
<ColorAnimation Storyboard.TargetName="border"
Duration="0:0:0.05"
Storyboard.TargetProperty="Background.Color"
To="#ee8400"/>
</Storyboard>
<ControlTemplate x:Key="ButtTemplate" TargetType="Button">
<Border CornerRadius="10" Name="border" Background="#ff8e00" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="Center"
VerticalAlignment="Center"
IsHitTestVisible="False"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.EnterActions>
<StopStoryboard BeginStoryboardName="ButtonFocusBegin"/>
<StopStoryboard BeginStoryboardName="ButtonFocusRestore"/>
<BeginStoryboard Storyboard="{StaticResource StoryboardHover}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Storyboard="{StaticResource StoryboardRestore}"/>
</Trigger.ExitActions>
</Trigger>
<Trigger Property="IsMouseDirectlyOver" Value="True">
<Trigger.EnterActions>
<BeginStoryboard Name="ButtonFocusBegin" Storyboard="{StaticResource StoryboardFocus}"/>
</Trigger.EnterActions>
<Trigger.ExitActions>
<BeginStoryboard Name="ButtonFocusRestore" Storyboard="{StaticResource StoryboardRestore}"/>
</Trigger.ExitActions>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="5"/>
<Setter Property="Foreground" Value="White"/>
<Setter Property="Template" Value="{StaticResource ButtTemplate}"/>
<Setter Property="FontSize" Value="30"/>
<Setter Property="Focusable" Value="False"/>
<EventSetter Event="Click" Handler="Button_Click"/>
</Style>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Viewbox Grid.ColumnSpan="4" HorizontalAlignment="Right">
<TextBox BorderThickness="0"
x:Name="DataText"
IsReadOnly="True"
FontSize="90"
Foreground="White"
HorizontalContentAlignment="Right"
VerticalContentAlignment="Center"
Background="{x:Null}"
Text="0"/>
</Viewbox>
<Button Grid.Row="1" Grid.Column="0" Content="%"/>
<Button Grid.Row="1" Grid.Column="1" Content="CE"/>
<Button Grid.Row="1" Grid.Column="2" Content="<-" Grid.ColumnSpan="2"/>
<Button Grid.Row="2" Grid.Column="0" Content="1/x"/>
<Button Grid.Row="2" Grid.Column="1" Content="x^2"/>
<Button Grid.Row="2" Grid.Column="2" Content="x^0.5"/>
<Button Grid.Row="2" Grid.Column="3" Content="/"/>
<Button Grid.Row="3" Grid.Column="0" Content="1"/>
<Button Grid.Row="3" Grid.Column="1" Content="2"/>
<Button Grid.Row="3" Grid.Column="2" Content="3"/>
<Button Grid.Row="3" Grid.Column="3" Content="*"/>
<Button Grid.Row="4" Grid.Column="0" Content="4"/>
<Button Grid.Row="4" Grid.Column="1" Content="5"/>
<Button Grid.Row="4" Grid.Column="2" Content="6"/>
<Button Grid.Row="4" Grid.Column="3" Content="-"/>
<Button Grid.Row="5" Grid.Column="0" Content="7"/>
<Button Grid.Row="5" Grid.Column="1" Content="8"/>
<Button Grid.Row="5" Grid.Column="2" Content="9"/>
<Button Grid.Row="5" Grid.Column="3" Content="+"/>
<Button Grid.Row="6" Grid.Column="0" Content="+/-"/>
<Button Grid.Row="6" Grid.Column="1" Content="0"/>
<Button Grid.Row="6" Grid.Column="2" Content=","/>
<Button Grid.Row="6" Grid.Column="3" Content="="/>
</Grid>
И вот такой код
public partial class MainWindow : Window
{
private readonly Button[] buttons;
private readonly Storyboard animFocus;
private readonly Storyboard animRestore;
public MainWindow()
{
InitializeComponent();
buttons = ((Grid)Content).Children.OfType<Button>().ToArray();
animFocus = (Storyboard)FindResource("StoryboardFocus");
animRestore = (Storyboard)FindResource("StoryboardRestore");
}
private async void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.IsRepeat) return;
try
{
Key key = e.Key;
if ((key >= Key.D0 && key <= Key.D9) || (key >= Key.NumPad0 && key <= Key.NumPad9))
{
string digit = e.Key.ToString()[^1].ToString();
Button button = buttons.First(b => (string)b.Content == digit);
Task task = BlinkButtonAsync(button);
button.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); // вызов обработчика события
await task;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private async Task BlinkButtonAsync(Button button)
{
FrameworkElement border = (FrameworkElement)button.Template.FindName("border", button);
border.BeginStoryboard(animFocus, HandoffBehavior.SnapshotAndReplace, true);
await Task.Delay(100);
border.BeginStoryboard(animRestore, HandoffBehavior.SnapshotAndReplace, true);
await Task.Delay(50);
animFocus.Remove(border);
animRestore.Remove(border);
}
private void Button_Click(object sender, RoutedEventArgs e)
{
Button btn = (Button)sender;
string text = (string)btn.Content;
Debug.WriteLine(text); // выводит в консоль студии текст с нажатой кнопки
}
}
Здесь я для простоты примера сделал нажатие с клавы только для кнопок 0-9. Остальные уж сами допишите.
Обратите внимание, что ни Tag, не x:Name я не использую. Чтобы различить кнопки, достаточно одного Content.
