Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middle click scrolling #2040

Merged
merged 13 commits into from
May 21, 2018

Conversation

Vijay-Nirmal
Copy link
Contributor

Issue: #1795

PR Type

What kind of change does this PR introduce?

  • Feature
  • Documentation content changes
  • Sample app changes

What is the current behavior?

Middle click scrolling is not available

What is the new behavior?

Added an attached property for ScrollViewer (or any ancestor of ScrollViewer) for middle click scrolling

middleclickscrolling

PR Checklist

Please check if your PR fulfills the following requirements:

  • Tested code with current supported SDKs
  • Docs have been added/updated which fit documentation template. (for bug fixes / features)
  • Sample in sample app has been added / updated (for bug fixes / features)
  • Tests for the changes have been added (for bug fixes / features) (if applicable)
  • Header has been added to all new source files (run build/UpdateHeaders.bat)
  • Contains NO breaking changes

Other information

I will add a separate sample for MiddleClickScrolling when multisample for a sample page is available.

Copy link
Member

@michael-hawker michael-hawker left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This and a couple of your other PRs need to be updated to the latest master as well.

...
</ListView>
<ListView Name="listView"
extensions:ScrollViewerEx.VerticalScrollBarMargin="{Binding MinHeight, ElementName=MyHeaderGrid, Converter={StaticResource DoubleTopThicknessConverter}}">
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class is still ScrollViewerExtensions (as it should be), if you want to abbreviate, I usually make the namespace ex: now. So it'd be ex:ScrollViewerExtensions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad. But why ex:ScrollViewerExtensions? We are using extensions:ScrollViewerExtensions in the master branch.

- Cursor number 102, 103, 104, 105, 106, 107, 108, 109 must be the NorthArror, NorthEastArror, EastArror, SouthEastArror, SouthArror, SouthWestArror, WestArror, NorthWestArror respectively
- Every cursor will be automatically attached to the corresponding direction of scrolling

### Attached Properties
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want one Attached Properties section?

Copy link
Contributor Author

@Vijay-Nirmal Vijay-Nirmal May 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This section is already many docs. It will resolve confusion between Attached Properties and Properties in Properties section

### Changing Cursor Type

> [!IMPORTANT]
Resource file must be manually added to change the cursor type when middle click scrolling.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I follow what this means to the developer. Is it required to do these steps to use the extension?

- You need 9 cursor resource in your resource file
- Your cursor number should be 101 to 109
- Cursor number 101 must be the centre cursor
- Cursor number 102, 103, 104, 105, 106, 107, 108, 109 must be the NorthArror, NorthEastArror, EastArror, SouthEastArror, SouthArror, SouthWestArror, WestArror, NorthWestArror respectively
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typos Arrow not Arror


if (_oldCursorID != cursorID)
{
RunInUIThread(() =>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the DispatcherHelper?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RunInUIThread is way smaller than DispatcherHelper. Also, It increases readability.

/// </summary>
public static partial class ScrollViewerExtensions
{
private static double _threshold = 50;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested with multiple scrollviewers?

All these static properties and variables means it's tied to a single instance of a scroll viewer. If a page has multiple scrollviewers trying to use this property it could breakdown. It'd be better to make state variables private attached properties to actually store state attached to the scrollviewer that's being manipulated.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. I have a SubscribeMiddleClickScrolling(). This will we resetting every value depend open the currently active ScrolViewer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the static variables are the problem here, but actually the events. They need to be static, so they'll never dispose, and the deregistration of the events is only happening when the EnableMiddleClickScrolling is set to false, which is... never. So this is leaking a reference to the scrollviewer.

{
cursorID = 101;
}
else
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can these all be collapsed in the else if, there's only going to be one cursorid in the end, eh?

Not sure if the compiler would optimize, but you could split out the Abs calculation above as you use it in multiple places.

@Vijay-Nirmal
Copy link
Contributor Author

@michael-hawker ping

@michael-hawker
Copy link
Member

Was able to grab my mouse with a wheel finally. I noticed if I middle-click (vs hold) to enter scroll mode, sometimes the mouse cursor won't change to the cross.

Also, the cursors should be white with the black outline by default for better contrast in more scenarios.

@Vijay-Nirmal
Copy link
Contributor Author

Vijay-Nirmal commented May 12, 2018

I noticed if I middle-click (vs hold) to enter scroll mode, sometimes the mouse cursor won't change to the cross

I think I have fixed it. @michael-hawker Could you check that again?

Copy link
Contributor

@nmetulev nmetulev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Setting the value to False after setting it to True throws an exception

@@ -13,7 +13,8 @@

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView Name="listView"
extensions:ScrollViewerExtensions.VerticalScrollBarMargin="{Binding MinHeight, ElementName=MyHeaderGrid, Converter={StaticResource DoubleTopThicknessConverter}}">
extensions:ScrollViewerExtensions.VerticalScrollBarMargin="{Binding MinHeight, ElementName=MyHeaderGrid, Converter={StaticResource DoubleTopThicknessConverter}}"
extensions:ScrollViewerExtensions.EnableMiddleClickScrolling="True">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be using the sample bind syntax @[EnableMiddleClickScrolling:Bool:True]

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

}

/// <summary>
/// This function will be called for every small intervel by <see cref="Timer"/>
Copy link
Contributor

@nmetulev nmetulev May 14, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: interval

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

_currentPosition = default(Point);
_isDeferredMovingStarted = false;
_oldCursorID = 100;
_timer.Dispose();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_timer could be null here if SubscribeMiddleClickScrolling is not called before

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


// Event to stop deferred scrolling if pointer pressed
Window.Current.CoreWindow.PointerPressed -= CoreWindow_PointerPressed;
Window.Current.CoreWindow.PointerPressed += CoreWindow_PointerPressed;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why subscribe to both CoreWindow and scrollviewer events?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ScrollViewer.PointerPressed is for SubscribeMiddleClickScrolling. CoreWindow.PointerPressed is to stop deferred scrolling. I can't use ScrollViewer.PointerPressed because I should stop scrolling in PointerPressed in the whole app.

### Changing Cursor Type

> [!IMPORTANT]
Resource file must be manually added to change the cursor type when middle click scrolling. If you didn't add then the cursor won't change when middle click scrolling but funcanilaty won't be affected.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo: functionality

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

1. Download [MiddleClickScrolling-CursorType.res](https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI/Extensions/ScrollViewer/MiddleClickScrolling-CursorType.res) file
2. Move this file into your project's folder
2. Open .csproj file of your project in [Visual Studio Code](https://code.visualstudio.com/) or in any other code editor
3. Added `<Win32Resource>MiddleClickScrolling-CursorType.res</Win32Resource>` in the first `<PropertyGroup>`
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: add

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


### Using Your Own Resource File

- You need 9 cursor resource in your resource file
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: 9 cursor resources

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the whole section

2. Open .csproj file of your project in [Visual Studio Code](https://code.visualstudio.com/) or in any other code editor
3. Added `<Win32Resource>MiddleClickScrolling-CursorType.res</Win32Resource>` in the first `<PropertyGroup>`

### Using Your Own Resource File
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there documentation that we can link to for creating custom resource files?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is an old doc for Windows 8 but it is not necessary. We can just edit the existing resource file in Visual Studio.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed the whole section


The HorizontalScrollBarMargin works exactly as VerticalScrollBarMargin.
[ScrollViewerExtensions sample page Source](https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.SampleApp/SamplePages/ScrollViewerExtensions). You can see this in action in [UWP Community Toolkit Sample App](https://www.microsoft.com/store/apps/9NBLGGH4TLCQ).
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change to Windows Community Toolkit Sample App

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will change it

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

/// </summary>
public static partial class ScrollViewerExtensions
{
private static double _threshold = 50;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the static variables are the problem here, but actually the events. They need to be static, so they'll never dispose, and the deregistration of the events is only happening when the EnableMiddleClickScrolling is set to false, which is... never. So this is leaking a reference to the scrollviewer.

_currentPosition = default(Point);
_isDeferredMovingStarted = false;
_oldCursorID = 100;
_timer = new Timer(Scroll, null, 5, 5);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to be extra safe, I would do a _timer?.Dispose() before this line.

Copy link
Contributor Author

@Vijay-Nirmal Vijay-Nirmal May 19, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK


This is reply is for above comment. For some reason, I have no replay section 😄

chrome_2018-05-19_16-25-34

EnableMiddleClickScrolling is set to false, which is... never

Why? Since this is an attached property. Devs can set any value at any time

but actually the events. They need to be static, so they'll never dispose, and the deregistration of the events is only happening when the EnableMiddleClickScrolling is set to false

Deregistration also haves when the user changes the focused ScrollViewer (in multiple ScrollViewer scenario).

@azchohfi azchohfi merged commit 8190e6d into CommunityToolkit:master May 21, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants