简体   繁体   English

MVVM:按钮保持事件命令

[英]MVVM: Button Hold event command

I want to be able to assign two different Command to a Button :我希望能够将两个不同的Command分配给Button

  • Click event Command Click事件Command
  • Hold event Command which uses HoldTimeout property to specify the hold duration Hold事件命令,它使用HoldTimeout属性来指定保持持续时间

    public static readonly DependencyProperty HoldCommandProperty = DependencyProperty.Register( "HoldCommand", typeof(ICommand), typeof(CommandButton), new PropertyMetadata(null, CommandChanged)); public ICommand HoldCommand { get { return (ICommand)GetValue(CommandProperty); } set { SetValue(CommandProperty, value); } }

How to calculate the time for click & hold and where should the calculation be done?如何计算点击和保持的时间以及应该在哪里进行计算? I am not sure if handling Click event is the right place if using the 'Command' property of an button.如果使用按钮的“命令”属性,我不确定处理 Click 事件是否合适。

The result XAML should look something like that:结果 XAML 应如下所示:

<CommandButton x:Name="InputButton" 
               Command="{Binding PrimaryCommand}"
               CommandParameter="{Binding}"
               HoldCommand="{Binding SecondaryCommand}"
               HoldCommandParameters="{Binding}"
               HoldTimeout="2000"/>

I have read how to implement double-clicks but this is not exactly it:我已经阅读了如何实现双击,但这不完全是这样:

You need to create a custom control and use DispatcherTimer class to time it.您需要创建一个自定义控件并使用 DispatcherTimer 类对其进行计时。 You can add another boolean and command property to activate this behaviour.您可以添加另一个布尔值和命令属性来激活此行为。

the control is as follows:控制如下:

public class SmartButton : Button
{
    private DispatcherTimer _timer;


    public int MillisecondsToWait
    {
        get { return (int)GetValue(MillisecondsToWaitProperty); }
        set { SetValue(MillisecondsToWaitProperty, value); }
    }

    public DispatcherTimer Timer
    {
        get { return _timer; }
        set { _timer = value; }
    }



    public ICommand ClickAndHoldCommand
    {
        get { return (ICommand)GetValue(ClickAndHoldCommandProperty); }
        set { SetValue(ClickAndHoldCommandProperty, value); }
    }


    public bool EnableClickHold
    {
        get { return (bool)GetValue(EnableClickHoldProperty); }
        set { SetValue(EnableClickHoldProperty, value); }
    }

    // Using a DependencyProperty as the backing store for EnableClickHold.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty EnableClickHoldProperty =
        DependencyProperty.Register("EnableClickHold", typeof(bool), typeof(SmartButton), new PropertyMetadata(false));



    // Using a DependencyProperty as the backing store for ClickAndHoldCommand.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty ClickAndHoldCommandProperty =
        DependencyProperty.Register("ClickAndHoldCommand", typeof(ICommand), typeof(SmartButton), new UIPropertyMetadata(null));



    // Using a DependencyProperty as the backing store for MillisecondsToWait.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty MillisecondsToWaitProperty =
        DependencyProperty.Register("MillisecondsToWait", typeof(int), typeof(SmartButton), new PropertyMetadata(0));


    public SmartButton()
    {
        this.PreviewMouseLeftButtonUp += OnPreviewMouseLeftButtonUp;
        this.PreviewMouseLeftButtonDown += OnPreviewMouseLeftButtonDown;

    }

    private void OnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        if (EnableClickHold)
        {

                bool isMouseReleaseBeforeHoldTimeout = Timer.IsEnabled;
                ResetAndRemoveTimer();
                // Consider it as a mouse click 
                if (isMouseReleaseBeforeHoldTimeout && Command != null)
                {
                    Command.Execute(CommandParameter);
                }
                e.Handled = true;
        }
    }

    private void OnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        if (EnableClickHold)
        {
            Timer = new DispatcherTimer(DispatcherPriority.Normal, this.Dispatcher)
            {
                Interval = TimeSpan.FromMilliseconds(MillisecondsToWait)
            };
            Timer.Tick += Timer_Tick;
            Timer.IsEnabled = true;
            Timer.Start();
            e.Handled = true;
        }
    }

    void Timer_Tick(object sender, EventArgs e)
    {
        if(ClickAndHoldCommand != null)
        {
            this.ClickAndHoldCommand.Execute(this.CommandParameter);
        }

        ResetAndRemoveTimer();
    }

    private void ResetAndRemoveTimer()
    {
        if (Timer == null) return;
        Timer.Tick -= Timer_Tick;
        Timer.IsEnabled = false;
        Timer.Stop();
        Timer = null;
    }
}

The xaml of this should look like这个 xaml 应该看起来像

 <wpfMouseClick:SmartButton x:Name="MySmartButton"
                                   Width="100"
                                   Height="50"
                                   ClickAndHoldCommand="{Binding Path=MyTestCommand,
                                                                 ElementName=MyWindow}"
                                   EnableClickHold="True"
                                   MillisecondsToWait="1000">
            Click and Hold
        </wpfMouseClick:SmartButton>

Look into the RepeatButton control, which fires a Click event repeatedly from the time you click it to the time it is released.查看RepeatButton控件,该控件从您单击它到释放它时重复触发Click事件。

To expand on this, you can control the interval of Click events fired, and keep track of how many will execute in a given time.为了扩展这一点,您可以控制触发Click事件的间隔,并跟踪在给定时间内将执行多少次。 For example, if the Interval property is set to 1000 , it will fire a Click event every second.例如,如果Interval属性设置为1000 ,它将每秒触发一个Click事件。 Keep track of how many are fired with a counter;跟踪有多少被计数器触发; once 5 have fired this means the user held the button down for five seconds and you can put your "Click & Hold" event logic in the RepeatButton Click event handler and then reset the counter.一旦5触发,这意味着用户按住按钮五秒钟,您可以将“单击并按住”事件逻辑放在RepeatButton Click事件处理程序中,然后重置计数器。

How about using EventTriggers and a StopWatch.如何使用 EventTriggers 和 StopWatch。

<UserControl xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <Button>
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="PreviewMouseDown">
                <i:InvokeCommandAction Command="{Binding DownCmd}" />
            </i:EventTrigger>
            <i:EventTrigger EventName="PreviewMouseUp">
                <i:InvokeCommandAction Command="{Binding UpCmd}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </Button>
</UserControl>

This is the C#.这是 C#。 I am using the code in a ViewModel.我在 ViewModel 中使用代码。

Stopwatch _buttonHoldStopWatch;
public DelegateCommand DownCmd { get; set; }
public DelegateCommand UpCmd { get; set; }

// Delegate commands are from the Prism framework but you can switch these out to 
regular ICommands
ResetValueDownCmd = new DelegateCommand(Down);
ResetValueUpCmd = new DelegateCommand(Up);

// User pressed down
private void Down(object dayObject)
{
    _buttonHoldStopWatch.Start(); // start watch
}

// User left go of press
private void Up(object dayObject)
{
    // Did the user hold down the button for 0.5 sec
    if (_buttonHoldStopWatch.ElapsedMilliseconds >= 500)
    {
        // Do something
    }

    _buttonHoldStopWatch.Stop(); // stop watch
    _buttonHoldStopWatch.Reset(); // reset elapsed time
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM