[英]how to get smartphone like scrolling for a winforms touchscreen app ( scrolling panel )
在網上搜索完文章后,我想出了一個基於winforms的觸摸屏應用程序的設計,需要像滾動一樣的智能手機。 該應用程序本身將在平板電腦或觸摸屏桌面上運行。
現在我被困在了有趣的部分。 我想我必須在面板上處理mousedown,mouseup和mousemove以設置自動滾動位置,以便當有人觸摸面板並拖動時,它會滾動魔術。 請幫助填寫以下方法存根中的幾行代碼。 autoscrollposition上的msdn doc非常令人困惑,因為它返回負數,但需要設置為abs,而不是。
Point mouseDownPoint;
Point mouseUpPoint;
Point mouseDragPoint;
private void myPanel_MouseDown(object sender, MouseEventArgs e)
{
this.mouseDownPoint = e.Location;
Console.WriteLine("Mouse down at {0}", e.location);
}
private void myPanel_MouseUp(object sender, MouseEventArgs e)
{
this.mouseUpPoint = e.Location;
this.mouseDownPoint = new Point(); //will set for IsEmpty check
Console.WriteLine("Mouse Up at {0}", e.location);
}
private void myPanel_MouseMove(object sender, MouseEventArgs e)
{
Console.WriteLine("Mouse at {0}", e.location);
if (mouseDownPoint.IsEmpty()) //finger is off the touchscreen
return;
myPanel.Autocrollposition = ??
}
謝謝
//更新 - 下面我有試用和錯誤工作和測試代碼。 (沒有重構)。 如果有人有更優雅的解決方案,請發布。
Point mouseDownPoint;
private void innerpanel_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.mouseDownPoint = e.Location;
}
private void innerpanel_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
if ((mouseDownPoint.X == e.Location.X) && (mouseDownPoint.Y == e.Location.Y))
return;
Point currAutoS = innerpanel.AutoScrollPosition;
if (mouseDownPoint.Y > e.Location.Y)
{
//finger slide UP
if (currAutoS.Y != 0)
currAutoS.Y = Math.Abs(currAutoS.Y) - 5;
}
else if (mouseDownPoint.Y < e.Location.Y)
{
//finger slide down
currAutoS.Y = Math.Abs(currAutoS.Y) + 5;
}
else
{
currAutoS.Y = Math.Abs(currAutoS.Y);
}
if (mouseDownPoint.X > e.Location.X)
{
//finger slide left
if (currAutoS.X != 0)
currAutoS.X = Math.Abs(currAutoS.X) - 5;
}
else if (mouseDownPoint.X < e.Location.X)
{
//finger slide right
currAutoS.X = Math.Abs(currAutoS.X) + 5;
}
else
{
currAutoS.X = Math.Abs(currAutoS.X);
}
innerpanel.AutoScrollPosition = currAutoS;
mouseDownPoint = e.Location; //IMPORTANT
}
作為一個組件:
public partial class TouchableFlowLayoutPanel : FlowLayoutPanel
{
private bool _doTouchScroll;
private Point _mouseStartPoint = Point.Empty;
private Point _panelStartPoint = Point.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
/// </summary>
public TouchableFlowLayoutPanel()
{
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Initializes a new instance of the <see cref="TouchableFlowLayoutPanel" /> class.
/// </summary>
/// <param name="container">The container.</param>
public TouchableFlowLayoutPanel(IContainer container)
{
container.Add(this);
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Handles the MouseFilterDown event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterDown(object sender, MouseFilterEventArgs e)
{
if (!_doTouchScroll && e.Button == MouseButtons.Left)
{
_mouseStartPoint = new Point(e.X, e.Y);
_panelStartPoint = new Point(-AutoScrollPosition.X,
-AutoScrollPosition.Y);
}
}
/// <summary>
/// Handles the MouseFilterMove event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!_mouseStartPoint.Equals(Point.Empty))
{
int dx = (e.X - _mouseStartPoint.X);
int dy = (e.Y - _mouseStartPoint.Y);
if (_doTouchScroll)
{
AutoScrollPosition = new Point(_panelStartPoint.X - dx,
_panelStartPoint.Y - dy);
}
else if (Math.Abs(dx) > 10 || Math.Abs(dy) > 10)
{
_doTouchScroll = true;
}
}
}
}
/// <summary>
/// Handles the MouseFilterUp event of the mouseFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterUp(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_doTouchScroll && !AutoScrollPosition.Equals(_panelStartPoint) &&
!_panelStartPoint.Equals(Point.Empty))
{
// don't fire Click-Event
e.Handled = true;
}
_doTouchScroll = false;
_mouseStartPoint = Point.Empty;
_panelStartPoint = Point.Empty;
}
}
}
internal class MouseFilter : IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_MOUSEMOVE = 0x0200;
/// <summary>
/// Filters a message before sending it
/// </summary>
/// <param name="m">The message to be sent.This message can not be changed.</param>
/// <returns>
/// true to filter the message and prevent it from being sent. false to allow the message to be sent to the next filter or control.
/// </returns>
public bool PreFilterMessage(ref Message m)
{
Point mousePosition = Control.MousePosition;
var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (MouseFilterMove != null)
{
MouseFilterMove(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONDOWN:
if (MouseFilterDown != null)
{
MouseFilterDown(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONUP:
if (MouseFilterUp != null)
{
MouseFilterUp(Control.FromHandle(m.HWnd), args);
}
break;
}
// Always allow message to continue to the next filter control
return args.Handled;
}
/// <summary>
/// Occurs when [mouse filter up].
/// </summary>
public event MouseFilterEventHandler MouseFilterUp;
/// <summary>
/// Occurs when [mouse filter down].
/// </summary>
public event MouseFilterEventHandler MouseFilterDown;
/// <summary>
/// Occurs when [mouse filter move].
/// </summary>
public event MouseFilterMoveEventHandler MouseFilterMove;
}
internal delegate void MouseFilterEventHandler(object sender, MouseFilterEventArgs args);
internal delegate void MouseFilterMoveEventHandler(object sender, MouseFilterEventArgs args);
internal class MouseFilterEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MouseFilterEventArgs" /> class.
/// </summary>
/// <param name="mouseButton">The mouse button.</param>
/// <param name="clicks">The clicks.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="delta">The delta.</param>
public MouseFilterEventArgs(MouseButtons mouseButton, int clicks, int x, int y, int delta)
{
Button = mouseButton;
Clicks = clicks;
X = x;
Y = y;
Delta = delta;
Handled = false;
}
/// <summary>
/// Gets or sets the button.
/// </summary>
/// <value>
/// The button.
/// </value>
public MouseButtons Button { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MouseFilterEventArgs" /> is handled.
/// </summary>
/// <value>
/// <c>true</c> if handled; otherwise, <c>false</c>.
/// </value>
public bool Handled { get; set; }
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>
/// The X.
/// </value>
public int X { get; set; }
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>
/// The Y.
/// </value>
public int Y { get; set; }
/// <summary>
/// Gets or sets the clicks.
/// </summary>
/// <value>
/// The clicks.
/// </value>
public int Clicks { get; set; }
/// <summary>
/// Gets or sets the delta.
/// </summary>
/// <value>
/// The delta.
/// </value>
public int Delta { get; set; }
}
static class Program
{
public static MouseFilter mouseFilter = new MouseFilter();
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.AddMessageFilter(mouseFilter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
這是我使用IMessageFilter的方式。 適合所有尋求解決方案的人。 首先,您必須實現一個將偵聽所有應用程序事件的過濾器:
internal class MouseFilter : IMessageFilter
{
private const int WM_LBUTTONDOWN = 0x0201;
private const int WM_LBUTTONUP = 0x0202;
private const int WM_MOUSEMOVE = 0x0200;
/// <summary>
/// Filtert eine Meldung, bevor sie gesendet wird.
/// </summary>
/// <param name="m">Die zu sendende Meldung. Diese Meldung kann nicht geändert werden.</param>
/// <returns>
/// true, um die Meldung zu filtern und das Senden zu verhindern. false, um das Senden der Meldung bis zum nächsten Filter oder Steuerelement zu ermöglichen.
/// </returns>
public bool PreFilterMessage(ref Message m)
{
Point mousePosition = Control.MousePosition;
var args = new MouseFilterEventArgs(MouseButtons.Left, 0, mousePosition.X, mousePosition.Y, 0);
switch (m.Msg)
{
case WM_MOUSEMOVE:
if (MouseFilterMove != null)
{
MouseFilterMove(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONDOWN:
if (MouseFilterDown != null)
{
MouseFilterDown(Control.FromHandle(m.HWnd), args);
}
break;
case WM_LBUTTONUP:
if (MouseFilterUp != null)
{
MouseFilterUp(Control.FromHandle(m.HWnd), args);
}
break;
}
// Always allow message to continue to the next filter control
return args.Handled;
}
/// <summary>
/// Occurs when [mouse filter up].
/// </summary>
public event MouseFilterEventHandler MouseFilterUp;
/// <summary>
/// Occurs when [mouse filter down].
/// </summary>
public event MouseFilterEventHandler MouseFilterDown;
/// <summary>
/// Occurs when [mouse filter move].
/// </summary>
public event MouseFilterMoveEventHandler MouseFilterMove;
}
internal delegate void MouseFilterEventHandler(object sender, MouseFilterEventArgs args);
internal delegate void MouseFilterMoveEventHandler(object sender, MouseFilterEventArgs args);
internal class MouseFilterEventArgs
{
/// <summary>
/// Initializes a new instance of the <see cref="MouseFilterEventArgs" /> class.
/// </summary>
/// <param name="mouseButton">The mouse button.</param>
/// <param name="clicks">The clicks.</param>
/// <param name="x">The x.</param>
/// <param name="y">The y.</param>
/// <param name="delta">The delta.</param>
public MouseFilterEventArgs(MouseButtons mouseButton, int clicks, int x, int y, int delta)
{
Button = mouseButton;
Clicks = clicks;
X = x;
Y = y;
Delta = delta;
Handled = false;
}
/// <summary>
/// Gets or sets the button.
/// </summary>
/// <value>
/// The button.
/// </value>
public MouseButtons Button { get; set; }
/// <summary>
/// Gets or sets a value indicating whether this <see cref="MouseFilterEventArgs" /> is handled.
/// </summary>
/// <value>
/// <c>true</c> if handled; otherwise, <c>false</c>.
/// </value>
public bool Handled { get; set; }
/// <summary>
/// Gets or sets the X.
/// </summary>
/// <value>
/// The X.
/// </value>
public int X { get; set; }
/// <summary>
/// Gets or sets the Y.
/// </summary>
/// <value>
/// The Y.
/// </value>
public int Y { get; set; }
/// <summary>
/// Gets or sets the clicks.
/// </summary>
/// <value>
/// The clicks.
/// </value>
public int Clicks { get; set; }
/// <summary>
/// Gets or sets the delta.
/// </summary>
/// <value>
/// The delta.
/// </value>
public int Delta { get; set; }
}
然后你必須向你注冊這個過濾器程序:
static class Program
{
public static MouseFilter mouseFilter = new MouseFilter();
/// <summary>
/// Der Haupteinstiegspunkt für die Anwendung.
/// </summary>
[STAThread]
static void Main()
{
Application.AddMessageFilter(mouseFilter);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MainForm());
}
}
現在,您可以監聽全局鼠標事件並滾動可滾動面板,如下所示:
public partial class MainForm : Form
{
private bool _doTouchScroll;
private Point _mouseStartPoint = Point.Empty;
private Point _yourScrollablePanelStartPoint = Point.Empty;
/// <summary>
/// Initializes a new instance of the <see cref="MainForm" /> class.
/// </summary>
public MainForm()
{
InitializeComponent();
Program.mouseFilter.MouseFilterDown += mouseFilter_MouseFilterDown;
Program.mouseFilter.MouseFilterMove += mouseFilter_MouseFilterMove;
Program.mouseFilter.MouseFilterUp += mouseFilter_MouseFilterUp;
}
/// <summary>
/// Handles the MouseFilterDown event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterDown(object sender, MouseFilterEventArgs e)
{
if (!_doTouchScroll && e.Button == MouseButtons.Left)
{
_mouseStartPoint = new Point(e.X, e.Y);
_yourScrollablePanelStartPoint = new Point(-yourScrollablePanel.AutoScrollPosition.X,
-yourScrollablePanel.AutoScrollPosition.Y);
}
}
/// <summary>
/// Handles the MouseFilterMove event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterMove(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (!_mouseStartPoint.Equals(Point.Empty))
{
int dx = (e.X - _mouseStartPoint.X);
int dy = (e.Y - _mouseStartPoint.Y);
if (_doTouchScroll)
{
yourScrollablePanel.AutoScrollPosition = new Point(_yourScrollablePanelStartPoint.X - dx,
_yourScrollablePanelStartPoint.Y - dy);
}
else if (Math.Abs(dx) > 10 || Math.Abs(dy) > 10)
{
_doTouchScroll = true;
}
}
}
}
/// <summary>
/// Handles the MouseFilterUp event of the mudmFilter control.
/// </summary>
/// <param name="sender">The source of the event.</param>
/// <param name="e">
/// The <see cref="MouseFilterEventArgs" /> instance containing the event data.
/// </param>
private void mouseFilter_MouseFilterUp(object sender, MouseFilterEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (_doTouchScroll && !yourScrollablePanel.AutoScrollPosition.Equals(_yourScrollablePanelStartPoint) &&
!_yourScrollablePanelStartPoint.Equals(Point.Empty))
{
// dont fire Click-Event
e.Handled = true;
}
_doTouchScroll = false;
_mouseStartPoint = Point.Empty;
_yourScrollablePanelStartPoint = Point.Empty;
}
}
}
我使用OP發布的代碼,但發現如果面板中有像標簽這樣的東西,它就無法工作。 為了使這項工作更順利,我改變了。
e.Location
至
PointToClient(Cursor.Position)
然后讓面板內的所有對象也調用mousedown和mousemove事件。 這種方式無論你點擊它應該移動。
7年后,但對於那些正在尋找干凈整潔的winforms解決方案的人來說:
using System;
using System.Drawing;
using System.Windows.Forms;
/// <summary>
/// Pass the panel into constructor and the control will be turned into a touch scrollable control.
/// </summary>
public class TouchScroll
{
private Point mouseDownPoint;
private Panel parentPanel;
/// <summary>
/// pass in the panel you would like to be touch scrollable and it will be handled here.
/// </summary>
/// <param name="panel">The root panel you need to scroll with</param>
public TouchScroll(Panel panel)
{
parentPanel = panel;
AssignEvents(panel);
}
private void AssignEvents(Control control)
{
control.MouseDown += MouseDown;
control.MouseMove += MouseMove;
foreach (Control child in control.Controls)
AssignEvents(child);
}
private void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
this.mouseDownPoint = Cursor.Position;
}
private void MouseMove(object sender, MouseEventArgs e)
{
if (e.Button != MouseButtons.Left)
return;
Point pointDifference = new Point(Cursor.Position.X - mouseDownPoint.X, Cursor.Position.Y - mouseDownPoint.Y);
if ((mouseDownPoint.X == Cursor.Position.X) && (mouseDownPoint.Y == Cursor.Position.Y))
return;
Point currAutoS = parentPanel.AutoScrollPosition;
parentPanel.AutoScrollPosition = new Point(Math.Abs(currAutoS.X) - pointDifference.X, Math.Abs(currAutoS.Y) - pointDifference.Y);
mouseDownPoint = Cursor.Position; //IMPORTANT
}
}
}
到原帖,考慮便宜的葬禮答案。
這個版本更簡單,觸摸更流暢(考慮手指移動速度,但不考慮移除手指后仍然滾動的效果,如移動但速度下降(也許我會這樣做,我有時間))
適用於面板或FlowLayoutPanel
創建一個表單並在其上插入FlowLayoutPanel。
表格代碼:
Public Class Form1
Private Function GenerateButton(pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = FlowPanel.Width
.Height = 100
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
Dim i As Integer
For i = 1 To 100
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(sender As Object, e As MouseEventArgs) Handles FlowPanel.MouseDown
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(sender As Object, e As MouseEventArgs) Handles FlowPanel.MouseMove
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
提示:要隱藏flowlayoutpanel(或面板)的滾動,請創建一個繼承自flowlayoutpanel(或面板)的usercontrol,並且:
Imports System.Runtime.InteropServices
Public Class FlowLayoutPanelExt
Inherits FlowLayoutPanel
<DllImport("user32.dll")> _
Private Shared Function ShowScrollBar(hWnd As IntPtr, wBar As Integer, bShow As Boolean) As <MarshalAs(UnmanagedType.Bool)> Boolean
End Function
Private Enum ScrollBarDirection
SB_HORZ = 0
SB_VERT = 1
SB_CTL = 2
SB_BOTH = 3
End Enum
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If Me.Visible Then
ShowScrollBar(Me.Handle, CInt(ScrollBarDirection.SB_BOTH), False)
MyBase.WndProc(m)
End If
End Sub
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Me.AutoScroll = True
End Sub
End Class
這個解決方案似乎是最好的解決方案之一,也是最普遍接受的解決方案 - 但是,如果你滾動到底部並觸摸按鈕后面的實際流量控制(我試圖這樣做,以便有空的空間),你然后必須雙擊並按住按鈕才能恢復滾動。 重新啟動應用程序可恢復類似手機的滾動功能。 我想知道是否有其他人已經看到這個或想出來 - 嘗試與您的應用程序,看看是否也是如此。 我修改了上面的代碼段,以便您可以啟動一個新項目,將其復制並粘貼到form1的代碼中,然后點擊運行。
Public Class Form1
Dim FlowPanel As New FlowLayoutPanel
Private Function GenerateButton(ByVal pName As String) As Button
Dim mResult As New Button
With mResult
.Name = pName
.Text = pName
.Width = 128
.Height = 128
.Margin = New Padding(0)
.Padding = New Padding(0)
.BackColor = Color.CornflowerBlue
AddHandler .MouseDown, AddressOf Button_MouseDown
AddHandler .MouseMove, AddressOf Button_MouseMove
End With
Return mResult
End Function
Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
Me.Width = 806
Me.Height = 480
FlowPanel.Padding = New Padding(0)
FlowPanel.Margin = New Padding(0)
' FlowPanel.ColumnCount = Me.Width / (128 + 6)
FlowPanel.Dock = DockStyle.Fill
FlowPanel.AutoScroll = True
Me.Controls.Add(FlowPanel)
Dim i As Integer
For i = 1 To 98
FlowPanel.Controls.Add(GenerateButton("btn" & i.ToString))
Next
End Sub
Dim myMouseDownPoint As Point
Dim myCurrAutoSMouseDown As Point
Private Sub Button_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs)
myMouseDownPoint = PointToClient(Cursor.Position)
myCurrAutoSMouseDown = FlowPanel.AutoScrollPosition
End Sub
Private Sub Button_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs)
If e.Button = Windows.Forms.MouseButtons.Left Then
Dim mLocation As Point = PointToClient(Cursor.Position)
If myMouseDownPoint <> mLocation Then
Dim mCurrAutoS As Point
Dim mDeslocation As Point = myMouseDownPoint - mLocation
mCurrAutoS.X = Math.Abs(myCurrAutoSMouseDown.X) + mDeslocation.X
mCurrAutoS.Y = Math.Abs(myCurrAutoSMouseDown.Y) + mDeslocation.Y
FlowPanel.AutoScrollPosition = mCurrAutoS
End If
End If
End Sub
End Class
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.