實現了一個支持長短按得按鈕組件,單擊可以觸發Click事件,長按可以觸發LongPressed事件,長按鬆開時觸發LongClick事件。還可以和自定義外觀相結合,實現自定義的按鈕外形。 ...
最新內容優先發佈於個人博客:小虎技術分享站,隨後逐步搬運到博客園。
實現了一個支持長短按得按鈕組件,單擊可以觸發Click
事件,長按可以觸發LongPressed
事件,長按鬆開時觸發LongClick
事件。源碼請自取:Github
長按閾值屬性的建立
為了方便在xaml
中使用,我們先配置一個DependencyProperty
叫做LongPressTime
來作為界定長按的閾值
public class LongPressButtonEx : Button
{
public static readonly DependencyProperty LongPressTimeProperty
= DependencyProperty.Register("LongPressTime", typeof(int),
typeof(LongPressButtonEx), new PropertyMetadata(500));
public int LongPressTime
{
set => SetValue(LongPressTimeProperty, value);
get => (int)GetValue(LongPressTimeProperty);
}
}
定義完成後可以在Xaml設計器中使用LongPressTime
這個拓展屬性
<Window x:Class="LongPressButton.MainWindow"
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"
xmlns:local="clr-namespace:LongPressButton"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:LongPressButtonEx Width="96" Height="48" LongPressTime="200">
Button
</local:LongPressButtonEx>
</Grid>
</Window>
長按的定時器判定方法
C#中的4種定時器,在WPF中需要使用Dispater Timer
定義一個DispatcherTimer來監控是否按下達到了長按
private DispatcherTimer _pressDispatcherTimer;
private void OnDispatcherTimeOut(object sender, EventArgs e)
{
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(e);
Debug.WriteLine("Button: Mouse down.");
if (_pressDispatcherTimer == null)
{
_pressDispatcherTimer = new DispatcherTimer();
_pressDispatcherTimer.Tick += OnDispatcherTimeOut;
_pressDispatcherTimer.Interval = new TimeSpan(0, 0, 0, 0, LongPressTime);
_pressDispatcherTimer.Start();
Debug.WriteLine("Button: Timer started");
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(e);
Debug.WriteLine("Button: Mouse up.");
_pressDispatcherTimer?.Stop();
_pressDispatcherTimer = null;
}
現在分別點擊和長按按鈕可以看到調試輸出
...
# 點擊
Button: Mouse down.
Button: Timer started
Button: Mouse up.
# 長按
Button: Mouse down.
Button: Timer started
Timeout 200
Button: Mouse up.
實現長按事件的定義
現在作為一個自定義控制項,我們需要在長按後發出一個RoutedEvent
,並修改部分之前的代碼拋出事件
/// <summary>
/// LongPress Routed Event
/// </summary>
public static readonly RoutedEvent LongPressEvent
= EventManager.RegisterRoutedEvent("LongPress",
RoutingStrategy.Bubble,
typeof(RoutedEventHandler),
typeof(LongPressButtonEx));
public event RoutedEventHandler LongPress
{
add => AddHandler(LongPressEvent, value);
remove => RemoveHandler(LongPressEvent, value);
}
private void OnDispatcherTimeOut(object sender, EventArgs e)
{
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
RaiseEvent(new RoutedEventArgs(LongPressEvent)); // raise the long press event
}
回到窗體的代碼中,添加事件的響應
<local:LongPressButtonEx Height="48" Width="256" LongPressTime="200"
LongPress="LongPressButtonEx_LongPress"
Click="LongPressButtonEx_Click">
Click or Long Press Me!
</local:LongPressButtonEx>
C#代碼如下,長按按鈕會顯示Long Pressed,單擊會是Click
private void LongPressButtonEx_LongPress(object sender, RoutedEventArgs e)
{
if (sender is LongPressButtonEx btn)
{
btn.Content = "Long Pressed";
}
}
private void LongPressButtonEx_Click(object sender, RoutedEventArgs e)
{
if (sender is LongPressButtonEx btn)
{
btn.Content = "Clicked";
}
}
發現Click
和LongPress
都可以響應,但是當鬆開按鈕時又變成了Click
,原因是滑鼠鬆開時響應了預設的Click事件
現在對按鈕控制項預設的OnClick
函數稍作修改,可以讓Click
也不出問題
/// <summary>
/// DependencyProperty for IsLongPress
/// </summary>
public static readonly DependencyProperty IsLongPressProperty
= DependencyProperty.Register("IsLongPress", typeof(bool),
typeof(LongPressButtonEx), new PropertyMetadata(false));
public bool IsLongPress
{
set => SetValue(IsLongPressProperty, value);
get => (bool)GetValue(IsLongPressProperty);
}
private void OnDispatcherTimeOut(object sender, EventArgs e)
{
IsLongPress = true;
_pressDispatcherTimer?.Stop();
Debug.WriteLine($"Timeout {LongPressTime}");
RaiseEvent(new RoutedEventArgs(LongPressEvent)); // raise the long press event
}
protected override void OnClick()
{
if (!IsLongPress)
{
base.OnClick();
}
else
{
RaiseEvent(new RoutedEventArgs(LongPressReleaseEvent)); // raise the long press event
IsLongPress = false;
}
}
之後再進行點擊操作,我們就可以看到符合預期的結果
長按+Style按鈕的展示效果
外觀Style自定義見這篇文章:WPF自定義按鈕外形
參考鏈接
UIElement.MouseLeftButtonDown Event
用戶控制項自定義 DependencyProperty 屬性使用教程
WPF 中 DispatcherTimer 計時器
如何:創建自定義路由事件
WPF 自定義帶自定義參數路由事件
Use WPF Style in another assemble