MVVM:按钮保持事件命令

时间:2013-12-10 15:18:10

标签: c# wpf mvvm

我希望能够将两个不同的Command分配给Button

  • Click活动Command
  • Hold event使用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); }
    }
    

如何计算点击次数和时间保持并在何处进行计算?如果使用按钮的“命令”属性,我不确定处理Click事件是否正确。

结果XAML看起来应该是这样的:

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

我已经阅读了如何实现双击,但这不完全是:

3 个答案:

答案 0 :(得分:5)

您需要创建自定义控件并使用DispatcherTimer类对其进行计时。您可以添加另一个布尔值和命令属性来激活此行为。

控制如下:

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;
    }
}

这个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>

答案 1 :(得分:3)

查看RepeatButton控件,该控件从您单击它到释放时重复触发Click事件。

要对此进行扩展,您可以控制触发的Click个事件的间隔,并跟踪在给定时间内将执行的事件数。例如,如果Interval属性设置为 1000 ,则会每秒触发Click个事件。跟踪计数器发射的数量;一旦 5 触发,这意味着用户按住按钮五秒钟,您可以将“Click&amp; Hold”事件逻辑放在RepeatButton Click事件处理程序中然后重置计数器。

答案 2 :(得分:1)

如何使用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>

这是C#。我在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
}