Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
282 views
in Technique[技术] by (71.8m points)

c# - Microsoft VSrollBar behavior or bug with touch screen - windows forms

I found a strange behavior with VScrollBar (vertical scrollbar available in Visual Studio tool box). The problem is "if I swipe down on the scrollbar, it moves up. If I swipe up, it moves down".

Steps to replicate Bug or behavior - 1

1) Add VScrollBar as a child to any user control.

2) Swipe up or down on the user control (not on scrollbar). Vertical scrollbar moves in opposite direction even if there isn't any programmatical connection between content and VScrollBar

Steps to replicate Bug or behavior - 2

1) Add VScrollBar as a child to any user control.

2) Swipe on scrollbar, it will move up during swipe up and down during swipe down (correct behavior)

3) Swipe up or down on the user control. Vertical scrollbar moves in opposite direction

4) Now swipe up or down on the vertical scrollbar. Vertical scrollbar starts moving in opposite direction (Buggy behavior, happens only after bug no: 1)

enter image description here

Simple control with vertical scrollbar to replicate this behavior

public class QuickViewer : Control
{
    public QuickViewer()
    {
        // Designer generated code
        // Copy pasted for illustration alone

        this.vScrollBar1 = new System.Windows.Forms.VScrollBar();
        this.SuspendLayout();
        // 
        // vScrollBar1
        // 
        this.vScrollBar1.Location = new System.Drawing.Point(420, 4);
        this.vScrollBar1.Name = "vScrollBar1";
        this.vScrollBar1.Size = new Size(this.vScrollBar1.Width, 292);            
        // 
        // QuickViewer
        //             
        this.Controls.Add(this.vScrollBar1);
        this.Name = "QuickViewer";
        this.Size = new System.Drawing.Size(441, 296);
        this.vScrollBar1.Value = 5;        
        this.ResumeLayout(false);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        //My actual control is different. I prepared a simple control to replicate the buggy behavior of VScrollBar

        //Control border
        Pen borderPen = new Pen(Color.LawnGreen, 5);
        e.Graphics.DrawRectangle(borderPen, ClientRectangle);
        borderPen.Dispose();

        //View area
        Rectangle rect = new Rectangle(ClientRectangle.Location, ClientRectangle.Size);
        rect.Inflate(-25, -10);
        e.Graphics.FillRectangle(Brushes.White, rect);
        e.Graphics.DrawRectangle(Pens.Black, rect);
        this.Font = new System.Drawing.Font("Segoe UI", 12, FontStyle.Bold);
        StringFormat format = new StringFormat() { Alignment = StringAlignment.Center };
        e.Graphics.DrawString("Quick viewer", this.Font, Brushes.Black, rect, format);
        string content = "This is a control created to illustrate the bug in VScrollBar." +
            "
 Control area refers to the area with white background" +
            "
 Control and Vertical Scrollbar are not programatically connected with each other."
            + "But still VScrollBar moves if you swipe on control area";

        Font font = new System.Drawing.Font("Segoe UI", 12, FontStyle.Italic);
        rect.Y += 20;
        e.Graphics.DrawString(content, font, Brushes.Black, rect, format);

        font.Dispose();
        format.Dispose();
        base.OnPaint(e);
    }

    /// <summary> 
    /// Required designer variable.
    /// </summary>
    private System.ComponentModel.IContainer components = null;

    /// <summary> 
    /// Clean up any resources being used.
    /// </summary>
    /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }


    private System.Windows.Forms.VScrollBar vScrollBar1;

}

Question:

Is there any way to overcome this behavior or bug ? I want the scrollbar to move down while swiping down and move up while swiping up. There should not be any scrolling when swiping over the content

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I want the scrollbar to move down while swiping down and move up while swiping up.

As per Hans Passants comment its just a system setting (in the form of a registry key):

enter image description here

The answer is actually over at SuperUser:

https://superuser.com/questions/310681/inverting-direction-of-mouse-scroll-wheel

In C# as you wanted:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Win32;
using System.Diagnostics;
using System.Security.Principal;

namespace WindowsFormsApplication1 {

    public partial class Form1 : Form {
        public Form1() {
            InitializeComponent();
        }
        private Flippable[] flippable;
        private void Form1_Load(object sender, EventArgs e) {
            WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);

            if (!hasAdministrativeRight) {
                RunElevated(Application.ExecutablePath);
                this.Close();
                Application.Exit();
            }

            //probably only want to flip mice.
            flippable = getFlippable("hid.mousedevice");
            dgv_flippable.DataSource = flippable;
            foreach (var col in dgv_flippable.Columns.OfType<DataGridViewCheckBoxColumn>()) {
                col.TrueValue = true;
                col.FalseValue = false;
                col.IndeterminateValue = null;
            }
        }
        private static bool RunElevated(string fileName)
        {
            //MessageBox.Show("Run: " + fileName);
            ProcessStartInfo processInfo = new ProcessStartInfo();
            processInfo.UseShellExecute = true;
            processInfo.Verb = "runas";
            processInfo.FileName = fileName;
            try
            {
                Process.Start(processInfo);
                return true;
            }
            catch (Win32Exception)
            {
                //Do nothing. Probably the user canceled the UAC window
            }
            return false;
        }

        private Flippable[] getFlippable(string filter) {
            List<Flippable> flips = new List<Flippable>();
            using (RegistryKey hid = Registry.LocalMachine.OpenSubKey(@"SYSTEMCurrentControlSetEnumHID",false)) {
                foreach (string devicekn in hid.GetSubKeyNames()) {
                    using (RegistryKey device = hid.OpenSubKey(devicekn,false)) {
                        foreach (string devicekn2 in device.GetSubKeyNames()) {
                            using (RegistryKey device2 = device.OpenSubKey(devicekn2,false)) {
                                using (RegistryKey devparam = device2.OpenSubKey("Device Parameters",true)) {
                                    if (devparam != null) {
                                        flips.Add(new Flippable(new string[] { devicekn, devicekn2 }, device2, devparam, tmr_popup));
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (filter != null) {
                return flips.Where(f=>f.name.Contains(filter)).ToArray();
            }
            return flips.ToArray();
        }

        private void dgv_flippable_MouseUp(object sender, MouseEventArgs e) {
            dgv_flippable.EndEdit();
        }

        private void button1_Click(object sender, EventArgs e) {
            flippable = getFlippable(null);
            dgv_flippable.DataSource = flippable;
        }

        private void btn_flip_Click(object sender, EventArgs e) {
            foreach (var f in flippable) {
                f.vertical = true;
                f.horizontal = true;
            }
            dgv_flippable.DataSource = null;
            dgv_flippable.DataSource = flippable;
        }

        private void btn_normal_Click(object sender, EventArgs e) {
            foreach (var f in flippable) {
                f.vertical = false;
                f.horizontal = false;
            }
            dgv_flippable.DataSource = null;
            dgv_flippable.DataSource = flippable;
        }

        private void tmr_popup_Tick(object sender, EventArgs e) {
            tmr_popup.Enabled = false;
            notifyIcon1.ShowBalloonTip(99999999);
        }
    }

    public class Flippable {
        public Flippable(string[] keyPath, RegistryKey deviceKey, RegistryKey devparam, Timer timer) {
            this._keyPath = keyPath;
            IEnumerable<bool?> flipValues = Flippable.valueNames
                .Select(v => onlyIntBool(devparam.GetValue(v, null)));
            this.name = (string)deviceKey.GetValue("DeviceDesc");
            this._vertical = flipValues.ElementAt(0);
            this._horizontal = flipValues.ElementAt(1);
            this._timer = timer;
        }
        private bool? onlyIntBool(object value) {
            try {
                return value == null ? null : (bool?)(((int)value) != 0);
            } catch {
                return null;
            }
        }
        public static string[] valueNames = new string[] { "FlipFlopWheel", "FlipFlopHScroll" };

        public string name { get; private set; }
        private string[] _keyPath;
        private bool? _vertical;
        private bool? _horizontal;
        Timer _timer;
        public bool? vertical { set { flip(Flippable.valueNames[0], value); _vertical = value; } get { return _vertical; } }
        public bool? horizontal { set { flip(Flippable.valueNames[1], value); _horizontal = value; } get { return _horizontal; } }

        public void flip(string valueName, bool? value) {
            using (RegistryKey hid = Registry.LocalMachine.OpenSubKey(@"SYSTEMCurrentControlSetEnumHID", false)) {
                using (RegistryKey device = hid.OpenSubKey(_keyPath[0], false)) {
                    using (RegistryKey device2 = device.OpenSubKey(_keyPath[1], false)) {
                        using (RegistryKey devparam = device2.OpenSubKey("Device Parameters", true)) {
                            if (value == null) {
                                devparam.DeleteValue(valueName);
                            } else {
                                devparam.SetValue(valueName, value == true ? 1 : 0);
                                _timer.Enabled = true;
                            }
                        }
                    }
                }
            }
        }

    }
}

REF: https://github.com/jamie-pate/flipflop-windows-wheel/blob/master/Form1.cs

Disclaimer: normally this question would get closed as a duplicate but because there is a bounty on it and the duplicate is over at SuperUser I've chosen to share that answer here. Full credit to the original author: https://superuser.com/users/108033/richard and https://superuser.com/users/132069/jamie-pate


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...