【问题标题】:WPF scrolling marquee - HandOffBehaviorWPF 滚动选取框 - HandOffBehavior
【发布时间】:2015-11-22 08:30:49
【问题描述】:

我试图弄清楚如何最好地使用 WPF 的 HandOffBehavior 技术。现在,我的应用程序中有一个滚动错误选取框,它会动画打开、滚动错误消息,然后自行关闭。

这周我刚刚开始构建这个 WPF 应用程序。问题是我似乎无法优雅地为这样的场景做准备,比如当用户在很小的连续间隔内单击登录按钮两次或更多次时。我希望看到错误字幕仅在用户使用登录按钮提交此类行为而不是多次重复打开和关闭字幕等时继续在屏幕上发送错误文本。这是相关代码。

MainWindow.xaml.cs:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Data.Entity;
using System.Windows.Media.Animation;
using PasswordHash;

namespace ChatClient
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void logIn(object sender, RoutedEventArgs e)
        {
            string nameRecord = "";
            string passRecord = "";

            if (UsernameField.Text == "" || UserPassField.Password == "")
            {
                openErrorMarquee("Username and password required");
            }
            else
            {
                using (otongadgethubEntities logCheck = new otongadgethubEntities())
                {
                    var userNullCheck = logCheck.users.FirstOrDefault(a => a.username == UsernameField.Text);
                    if (userNullCheck == null)
                    {
                        openErrorMarquee("Username does not exist");
                    }

                    if (userNullCheck != null)
                    {
                        nameRecord = userNullCheck.username;
                    }

                    if (nameRecord == UsernameField.Text)
                    {
                        passRecord = Encrypt.MD5(UserPassField.Password).ToLower();
                        if (passRecord == userNullCheck.password)
                        {
                            //Yay! User logged in!
                        }
                        else
                        {
                            openErrorMarquee("Password invalid");
                        }
                    }
                }
            }
        }

        private void openErrorMarquee(string errorMessage)
        {
            errorMarquee.Visibility = System.Windows.Visibility.Visible;

            DoubleAnimation openMarquee = new DoubleAnimation();
            openMarquee.From = 0;
            openMarquee.To = 17;
            openMarquee.Duration = new Duration(TimeSpan.FromSeconds(1.0));
            openMarquee.Completed += (s, doneEvent) => errorMarqueeScroll(errorMessage);
            errorMarquee.BeginAnimation(Rectangle.HeightProperty, openMarquee, HandoffBehavior.Compose);
        }

        private void errorMarqueeScroll(string errorMessage)
        {
            errorText.Text = errorMessage;
            errorText.Visibility = System.Windows.Visibility.Visible;

            double height = errorCanvas.ActualHeight - errorText.ActualHeight;
            errorText.Margin = new Thickness(0, height / 2, 0, 0);
            DoubleAnimation doubleErrorAnimation = new DoubleAnimation();
            doubleErrorAnimation.From = -errorText.ActualWidth;
            doubleErrorAnimation.To = errorCanvas.ActualWidth;

            //doubleErrorAnimation.RepeatBehavior = RepeatBehavior.Forever;
            doubleErrorAnimation.Completed += new EventHandler(closeErrorMarquee);
            doubleErrorAnimation.Duration = new Duration(TimeSpan.FromSeconds(7.0));
            errorText.BeginAnimation(Canvas.RightProperty, doubleErrorAnimation);
        }

        private void closeErrorMarquee(object sender, EventArgs e)
        {
            DoubleAnimation closeMarquee = new DoubleAnimation();
            closeMarquee.From = 17;
            closeMarquee.To = 0;
            closeMarquee.Duration = new Duration(TimeSpan.FromSeconds(1.0));
            closeMarquee.Completed += (s, doneEvent) => {
                errorMarquee.Visibility = System.Windows.Visibility.Hidden;
                errorText.Visibility = System.Windows.Visibility.Hidden;
            };
            errorMarquee.BeginAnimation(Rectangle.HeightProperty, closeMarquee, HandoffBehavior.Compose);
        }
    }
}

对于那些也需要查看窗口的人来说,这里是 XAML:

<Window
        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" mc:Ignorable="d" x:Class="ChatClient.MainWindow"
        Title="MainWindow" Height="350" Width="525" Icon="media/favicon.gif" Background="#FF3C3636" Foreground="{x:Null}">
    <Window.Resources>
        <Storyboard x:Key="logolayer2excompsoundfad_mp4"/>
    </Window.Resources>
    <Window.BorderBrush>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="Black" Offset="0"/>
            <GradientStop Color="#FF6F6D95" Offset="1"/>
        </LinearGradientBrush>
    </Window.BorderBrush>
    <Window.Triggers>
        <EventTrigger RoutedEvent="FrameworkElement.Loaded">
            <BeginStoryboard Storyboard="{StaticResource logolayer2excompsoundfad_mp4}"/>
        </EventTrigger>
    </Window.Triggers>
    <Grid>
        <Rectangle x:Name="Menu" Fill="#755E5E83" HorizontalAlignment="Left" Height="273" Margin="35,23,0,0" Stroke="Black" VerticalAlignment="Top" Width="446" RadiusY="27.5" RadiusX="27.5"/>
        <Button Content="Log In" HorizontalAlignment="Left" Height="80" Margin="162,200,0,0" Style="{DynamicResource OTonButtonStyle1}" VerticalAlignment="Top" Width="187" FontFamily="Impact" FontSize="26.667" Foreground="#FF1C045B" Click="logIn"/>
        <TextBox x:Name="UsernameField" HorizontalAlignment="Left" Height="25" Margin="204,57,0,0" TextWrapping="Wrap" Text="[Username]" VerticalAlignment="Top" Width="193" Background="#BD251E1E" UseLayoutRounding="False" FontFamily="Copperplate Gothic Light" FontSize="16">
            <TextBox.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
                    <GradientStop Color="#FF1E2E95" Offset="0.5"/>
                    <GradientStop Color="White" Offset="1"/>
                </LinearGradientBrush>
            </TextBox.Foreground>
        </TextBox>
        <TextBlock HorizontalAlignment="Left" Height="16" Margin="98,57,0,0" TextWrapping="Wrap" Text="Username:" VerticalAlignment="Top" Width="101" FontFamily="Copperplate Gothic Light" FontSize="16">
            <TextBlock.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF0A1D5F" Offset="0.374"/>
                    <GradientStop Color="#FF6E7FB9" Offset="1"/>
                </LinearGradientBrush>
            </TextBlock.Foreground>
        </TextBlock>
        <PasswordBox x:Name="UserPassField" HorizontalAlignment="Left" Height="25" Margin="204,99,0,0" VerticalAlignment="Top" Width="193" Background="#BD251E1E" UseLayoutRounding="False" FontFamily="Copperplate Gothic Light" FontSize="16">
            <PasswordBox.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
                    <GradientStop Color="#FF1E2E95" Offset="0.5"/>
                    <GradientStop Color="White" Offset="1"/>
                </LinearGradientBrush>
            </PasswordBox.Foreground>
        </PasswordBox>
        <TextBlock HorizontalAlignment="Left" Height="16" Margin="98,99,0,0" TextWrapping="Wrap" Text="Password:" VerticalAlignment="Top" Width="101" FontFamily="Copperplate Gothic Light" FontSize="16">
            <TextBlock.Foreground>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FF0A1D5F" Offset="0.374"/>
                    <GradientStop Color="#FF6E7FB9" Offset="1"/>
                </LinearGradientBrush>
            </TextBlock.Foreground>
        </TextBlock>
        <Canvas ClipToBounds="True" Name="errorCanvas" Width="446" Height="17" Margin="36,152,35,151">
            <Rectangle x:Name="errorMarquee" Fill="#FF0A0A0C" HorizontalAlignment="Left" Height="17" Stroke="#FF5B1D1D" VerticalAlignment="Top" Width="446" Canvas.Left="-1" Visibility="Hidden"/>
            <TextBlock x:Name="errorText" HorizontalAlignment="Left" Height="16" TextWrapping="Wrap" Text="TextBlock" VerticalAlignment="Top" Width="690" FontFamily="Copperplate Gothic Bold" FontSize="16" Foreground="#FF7E0202" Visibility="Hidden"/>
        </Canvas>
    </Grid>
</Window>

大家有什么建议吗?

【问题讨论】:

    标签: c# wpf xaml blend doubleanimation


    【解决方案1】:

    你可以只用一个标志来检查这个

    private static flag = true;
    private void logIn(object sender, RoutedEventArgs e)
        {
            if(flag){
            flag=false;
            string nameRecord = "";
            string passRecord = "";
    
            if (UsernameField.Text == "" || UserPassField.Password == "")
            {
                openErrorMarquee("Username and password required");
            }
            else
            {
                using (otongadgethubEntities logCheck = new otongadgethubEntities())
                {
                    var userNullCheck = logCheck.users.FirstOrDefault(a => a.username == UsernameField.Text);
                    if (userNullCheck == null)
                    {
                        openErrorMarquee("Username does not exist");
                    }
    
                    if (userNullCheck != null)
                    {
                        nameRecord = userNullCheck.username;
                    }
    
                    if (nameRecord == UsernameField.Text)
                    {
                        passRecord = Encrypt.MD5(UserPassField.Password).ToLower();
                        if (passRecord == userNullCheck.password)
                        {
                            //Yay! User logged in!
                        }
                        else
                        {
                            openErrorMarquee("Password invalid");
                        }
                    }
                }
            }
          }
          else
          {
          openErrorMarquee("you pressed more one time");
           }
         }
    

    【讨论】:

    • 感谢您的回复。我不得不说,由于事件的结构(尤其是当另一个动画完成时调用时,打开选取框矩形,关闭它等),这并不能充分解决问题。它只会导致所有事件再次触发,然后同样的问题仍然会持续存在 - 比应有的更早关闭,即使我只希望它“打开”一次以滚动错误消息等,也会再次打开。我是尝试修复此 UI 中的中断。
    • 如果我以超快的速度按三下登录按钮,整个 errorMarquee 动画行为及其 errorText 将变得混乱,最终 errorText 会隐藏一段时间,字幕打开和打开等.
    【解决方案2】:

    您可以使用秒表检查快速点击。在下面给出的代码示例中,尝试缓慢和快速地按下按钮。

        Stopwatch w = new Stopwatch();
        long milliseconds_prev = 0;
    
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            if (_checkFastClicks())
            {
                Debug.WriteLine("Fast click");
            }
            else
                Debug.WriteLine("Slow click");
        }
    
        bool _checkFastClicks()
        {
            bool result = false;
    
            if (!w.IsRunning)
            {
                w.Start();
            }
            if (w.IsRunning)
            {
                if (w.ElapsedMilliseconds - milliseconds_prev < 500)//imp
                {
                    if (w.ElapsedMilliseconds > 0)
                    {
                        milliseconds_prev = w.ElapsedMilliseconds;
                        result = true;
                    }
                    else
                        result = false;
                }
                else
                {
                    milliseconds_prev = 0;
                    w.Reset();
                    w.Stop();
                    result = false;
                }
            }
    
            return result;
        }
    

    【讨论】:

    • 有趣的想法。稍后我将不得不尝试,也许当我们到达丹佛机场时。谢谢!如果我发现了什么,我会告诉你的
    猜你喜欢
    • 2016-06-25
    • 2013-02-25
    • 1970-01-01
    • 2016-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-23
    相关资源
    最近更新 更多