C# MVVM:按钮保持事件命令

C# MVVM:按钮保持事件命令,c#,wpf,mvvm,C#,Wpf,Mvvm,我希望能够将两个不同的命令分配给按钮: 单击事件命令 Hold事件命令,该命令使用HoldTimeout属性指定保持持续时间 public static readonly DependencyProperty HoldCommandProperty = DependencyProperty.Register( "HoldCommand", typeof(ICommand), typeof(CommandButton), new P

我希望能够将两个不同的
命令
分配给
按钮

  • 单击
    事件
    命令
  • 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); }
    }
    
如何计算单击并按住的时间以及应在何处进行计算?如果使用按钮的“命令”属性,我不确定处理单击事件的位置是否正确

结果XAML应该如下所示:

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

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

查看控件,该控件从单击它到释放它都会重复触发
单击事件


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

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

控制措施如下:

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>

点击并按住

使用事件触发器和秒表怎么样

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

好主意。我想知道如果HoldTimeout设置为2500毫秒,如何获得点击计数参考?谢谢你的完整解决方案。一件小事是,我需要能够使用两个不同的命令:一个用于单击,另一个用于保持。我在SmartButton中添加了另一个命令“ClickAndHoldCommand”。您应该将您的命令绑定到此按钮并启用相应的属性。不需要“EnableClickHold”,因为我希望能够将不同的单击命令和按住命令分配给同一按钮。我发现以下编辑可以做到这一点:private void on PreviewMouseLeftButtonUp(对象发送器,MouseButtonEventArgs e){BoO.SimuleSeleSeEnEnguldTimeOutt= Time.ISTabel;ReSeNANDReaveTimeReMeor(;)/ /将其视为鼠标单击(IsMouSereleSeEngReldTimeOutt)命令。执行(CurrdPosiple);你所做的更改对你有用吗?如果是,你可以编辑我的答案并接受它,以便对其他人也有用。:)是的,这可以工作。不过,感谢你的好主意,它应该在按钮控件中。这是一个按钮控件。
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
}