C# 如何为winforms触摸屏应用程序(滚动面板)获得类似智能手机的滚动

C# 如何为winforms触摸屏应用程序(滚动面板)获得类似智能手机的滚动,c#,vb.net,user-controls,scroll,touchscreen,C#,Vb.net,User Controls,Scroll,Touchscreen,在浏览了网上的文章之后,我提出了一个基于winforms的触摸屏应用程序的设计,它需要智能手机般的滚动。该应用程序本身将在平板电脑或触摸屏桌面上运行 我把所有我想滚动的东西都放在面板上 将autoscroll设置为true(将显示滚动条) 现在将整个面板放在一个分组框中 收缩groupbox,直到隐藏滚动条(视觉隐藏,不可见=false) 现在,有趣的部分,我被困在。我想我必须处理面板上的mousedown、mouseup和mousemove来设置autoscrollposition,这样当

在浏览了网上的文章之后,我提出了一个基于winforms的触摸屏应用程序的设计,它需要智能手机般的滚动。该应用程序本身将在平板电脑或触摸屏桌面上运行

  • 我把所有我想滚动的东西都放在面板上
  • 将autoscroll设置为true(将显示滚动条)
  • 现在将整个面板放在一个分组框中
  • 收缩groupbox,直到隐藏滚动条(视觉隐藏,不可见=false)
现在,有趣的部分,我被困在。我想我必须处理面板上的mousedown、mouseup和mousemove来设置autoscrollposition,这样当有人触摸面板并拖动时,它就会执行滚动魔术。请帮助填写以下方法存根中的几行代码。on autoscrollposition非常混乱,因为它返回负数,但需要使用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

    }
鼠标点向下点;
私有void innerpanel_MouseDown(对象发送器,MouseEventArgs e)
{
if(e.Button==MouseButtons.Left)
this.mouseDownPoint=e.位置;
}
私有void innerpanel_MouseMove(对象发送器,MouseEventArgs e)
{
if(e.按钮!=鼠标按钮左)
返回;
if((mouseDownPoint.X==e.Location.X)&(mouseDownPoint.Y==e.Location.Y))
返回;
Point currAutoS=innerpanel.AutoScrollPosition;
if(mouseDownPoint.Y>e.Location.Y)
{
//手指向上滑动
if(currenautos.Y!=0)
currAutoS.Y=Math.Abs(currAutoS.Y)-5;
}
else if(mouseDownPoint.Ye.Location.X)
{
//手指向左滑动
如果(currAutoS.X!=0)
currAutoS.X=Math.Abs(currAutoS.X)-5;
}
else if(mouseDownPoint.X
这是我使用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; }
}
内部类MouseFilter:IMessageFilter
{
私有常量int WM_LBUTTONDOWN=0x0201;
私有常量int WM_LBUTTONUP=0x0202;
私有常量int WM_MOUSEMOVE=0x0200;
/// 
///请把它过滤掉,好吗。
/// 
///这是我的梦想。我的梦想不可能实现。
/// 
///是的,这是一个过滤器和一个过滤器。是的,这是一个过滤器和一个过滤器。
/// 
公共bool预过滤器消息(参考消息m)
{
点鼠标位置=Control.mousePosition;
var args=新的MouseFilterEventArgs(MouseButtons.Left,0,mousePosition.X,mousePosition.Y,0);
开关(m.Msg)
{
案例WM_MOUSEMOVE:
if(MouseFilterMove!=null)
{
MouseFilterMove(Control.FromHandle(m.HWnd),args);
}
打破
案例WM_LBUTTONDOWN:
if(MouseFilterDown!=null)
{
鼠标过滤(Control.FromHandle(m.HWnd),args);
}
打破
案例WM_LBUTTONUP:
if(MouseFilterUp!=null)
{
MouseFilterUp(Control.FromHandle(m.HWnd),args);
}
打破
}
//始终允许消息继续到下一个筛选器控件
返回参数。已处理;
}
/// 
///在[鼠标向上筛选]时发生。
/// 
公共事件MouseFilterEventHandler MouseFilterUp;
/// 
///在[鼠标过滤器关闭]时发生。
/// 
公共事件MouseFilterEventHandler MouseFilterDown;
/// 
///在[鼠标过滤器移动]时发生。
/// 
公共事件MouseFilterMoveEventHandler MouseFilterMove;
}
内部委托void MouseFilterEventHandler(对象发送方,MouseFilterEventArgs args);
内部委托void MouseFilterMoveEventHandler(对象发送方,MouseFilterEventArgs args args);
内部类MouseFilterEventArgs
{
/// 
///初始化类的新实例。
/// 
///鼠标按钮。
///咔嗒声。
///x。
///y。
///三角洲。
公共MouseFilterEventArgs(鼠标按钮、鼠标按钮、整数单击、整数x、整数y、整数增量)
{
按钮=鼠标按钮;
点击=点击;
X=X;
Y=Y;
δ=δ;
已处理=错误;
}
/// 
///获取或设置按钮。
/// 
/// 
///按钮。
/// 
公用鼠标按钮按钮{get;set;}
/// 
///获取或设置一个值,该值指示是否对此进行处理。
/// 
/// 
///如果处理,则为true;否则为false。
/// 
公共布尔处理{get;set;}
/// 
///获取或设置X。
/// 
/// 
///X。
/// 
公共整数X{get;set;}
/// 
///获取或设置Y。
/// 
/// 
///Y。
/// 
公共整数Y{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;
        }
    }
}
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());
    }
}
e.Location 
PointToClient(Cursor.Position) 
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
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
   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
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
        }
    }
}