WPF按下回车键如何使按钮看起来被按下

4

好的,这让我很疯狂。我有一个简单的WPF登录应用程序,其中包含一个登录按钮,如果用户按下键盘上的回车键,则希望单击该登录按钮。但是,这里有个问题,当用户按下Enter键时,我希望该按钮看起来像已被按下。

我使用了IsDefault = true; 它会登录,但由于正在处理中,按钮永远不会更改。

xaml:

<Button x:Name="SignInButton" Click="SignInButton_Click" Margin="277,523,265,-125"      MaxWidth="100" MinWidth="100" IsDefault="False"  Style="{StaticResource SignInButton}">
                    <Button.Effect>
                        <DropShadowEffect ShadowDepth="6"
                                              BlurRadius="6"
                                              Opacity="1"
                                              Direction="315"
                                              Color="gray" />
                    </Button.Effect>

                    <TextBlock x:Name="Connect"  TextWrapping="Wrap" Text="Connect" TextAlignment="Center" Padding="0,2,0,0"/>

我甚至尝试仅更改文本:

    private void OnKeyDownHandler(object sender, KeyEventArgs e)
    {
        if (e.Key == Key.Enter)
        {
            Connect.Focus();

            Connect.Text = "Please Wait...";

            SignInButton.IsDefault = true;

        }
    }

再次强调,这个方法可以运行,但是在按钮处理之后才会改变文本。


你是否也在登录按钮上设置了IsDefault属性,还是只在OnKeyDownHandler上设置了它? - Nzall
Nate,我两种方式都尝试了,结果是一样的。 - Hawks1998
1
这是因为您正在主UI线程上执行操作。创建一个“BackgroundWorker”线程来进行处理。 - Saggio
假设您希望文本在用户单击按钮或按下回车键时更新,那么您根本不需要编写OnKeyDownHandler。相反,在SignInButton_Click中完成所有UI工作即可。 - Moby Disk
“until after the button has processed”和“as it is processing”是什么意思? - Peter
3个回答

4

由于默认情况下不会进行可视化更新,只会执行操作,因此您需要模拟此行为。

以下是我如何引发可视化更新:

XAML:

<Window x:Class="WpfAnswer001.Window4"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window4" Height="300" Width="300">
<Window.Resources>
    <Style x:Key="FocusVisual">
        <Setter Property="Control.Template">
            <Setter.Value>
                <ControlTemplate>
                    <Rectangle Margin="2" SnapsToDevicePixels="true" Stroke="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" StrokeThickness="1" StrokeDashArray="1 2"/>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
    <SolidColorBrush x:Key="Button.Static.Background" Color="#FFDDDDDD"/>
    <SolidColorBrush x:Key="Button.Static.Border" Color="#FF707070"/>
    <SolidColorBrush x:Key="Button.MouseOver.Background" Color="#FFBEE6FD"/>
    <SolidColorBrush x:Key="Button.MouseOver.Border" Color="#FF3C7FB1"/>
    <SolidColorBrush x:Key="Button.Pressed.Background" Color="#FFC4E5F6"/>
    <SolidColorBrush x:Key="Button.Pressed.Border" Color="#FF2C628B"/>
    <SolidColorBrush x:Key="Button.Disabled.Background" Color="#FFF4F4F4"/>
    <SolidColorBrush x:Key="Button.Disabled.Border" Color="#FFADB2B5"/>
    <SolidColorBrush x:Key="Button.Disabled.Foreground" Color="#FF838383"/>
    <Style x:Key="ButtonStyle1" TargetType="{x:Type Button}">
        <Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
        <Setter Property="Background" Value="{StaticResource Button.Static.Background}"/>
        <Setter Property="BorderBrush" Value="{StaticResource Button.Static.Border}"/>
        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
        <Setter Property="BorderThickness" Value="1"/>
        <Setter Property="HorizontalContentAlignment" Value="Center"/>
        <Setter Property="VerticalContentAlignment" Value="Center"/>
        <Setter Property="Padding" Value="1"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Button}">
                    <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="#FFDDDDDD" SnapsToDevicePixels="true">
                        <VisualStateManager.VisualStateGroups>
                            <VisualStateGroup x:Name="CommonStates">
                                <VisualStateGroup.Transitions>
                                    <VisualTransition GeneratedDuration="0:0:0.4">
                                        <VisualTransition.GeneratedEasingFunction>
                                            <QuinticEase EasingMode="EaseOut"/>
                                        </VisualTransition.GeneratedEasingFunction>
                                    </VisualTransition>
                                </VisualStateGroup.Transitions>
                                <VisualState x:Name="Normal"/>
                                <VisualState x:Name="MouseOver"/>
                                <VisualState x:Name="Pressed">
                                    <Storyboard>
                                        <ColorAnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.Background).(SolidColorBrush.Color)" Storyboard.TargetName="border">
                                            <EasingColorKeyFrame KeyTime="0" Value="#FFAA3737"/>
                                        </ColorAnimationUsingKeyFrames>
                                    </Storyboard>
                                </VisualState>
                                <VisualState x:Name="Disabled"/>
                            </VisualStateGroup>
                        </VisualStateManager.VisualStateGroups>
                        <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsDefaulted" Value="true">
                            <Setter Property="BorderBrush" TargetName="border" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                        </Trigger>
                        <Trigger Property="IsMouseOver" Value="true">
                            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.MouseOver.Background}"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.MouseOver.Border}"/>
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Background" TargetName="border" Value="{StaticResource Button.Disabled.Background}"/>
                            <Setter Property="BorderBrush" TargetName="border" Value="{StaticResource Button.Disabled.Border}"/>
                            <Setter Property="TextElement.Foreground" TargetName="contentPresenter" Value="{StaticResource Button.Disabled.Foreground}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition/>
        <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top"><Run Text="TextBlock"/></TextBlock>
    <TextBox TextWrapping="Wrap" Text="TextBox" Margin="0,0,26,0" Grid.Column="1"/>
    <TextBlock HorizontalAlignment="Left" TextWrapping="Wrap" VerticalAlignment="Top" Grid.Row="1"><Run Text="TextBlock"/></TextBlock>
    <TextBox TextWrapping="Wrap" Text="TextBox" Margin="0,0,26,0" Grid.Column="1" Grid.Row="1"/>
    <Button x:Name="LoginButton" Content="Login" VerticalAlignment="Top" Grid.Row="2" Grid.Column="1" IsDefault="True" Style="{DynamicResource ButtonStyle1}" Click="Button_Click" />
</Grid>
</Window>

代码后端:

using System;
using System.Threading.Tasks;
using System.Windows;

public partial class Window4 : Window
{
    public Window4()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        UpdateButtonVisualState();
        LoginProcessing();
    }

    private async Task LoginProcessing()
    {
        // Simulating a long background task.
        await Task.Delay(TimeSpan.FromSeconds(5));
    }

    private async Task UpdateButtonVisualState()
    {
        VisualStateManager.GoToState(LoginButton, "Pressed", useTransitions: true);
        await Task.Delay(TimeSpan.FromMilliseconds(200));
        VisualStateManager.GoToState(LoginButton, "Normal", useTransitions: true);
    }
}

无需处理回车键,因为这是默认按钮。

这正是我正在寻找的。非常感谢! - Hawks1998
我只需要UpdateButtonVisualState()方法,而不必更改我的XAML。这太棒了,谢谢! - Zak

0
你能发布一下你的SignInButton_Click事件处理程序的代码吗?
它应该在后台线程上运行长时间运行的任务,否则在此方法完成并更新UI之前,你的按钮将不会更改。

-1
问题在于您正在占用UI线程。设置Connect.Text =“请稍候...”将在UI线程被释放后才会生效,然后它可以执行诸如重新绘制UI之类的工作。您需要显式刷新屏幕或使用某种异步模式来完成工作。我建议使用后者。
有很多关于如何在WPF中进行异步工作的文章。尝试搜索诸如“WPF后台工作者”、“WPF异步等待”或“WPF Task.Factory.StartNew”的术语,很可能仅通过发布此帖子,侧边栏上的“相关”链接栏就会显示一些。
编辑:为您提供一些链接,展示不同的方法。 Async Attempt WPF Blocking 如何从TPL任务更新WPF控件?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接