Skip to content

Fix git push error for protected CLA branch #3046

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

Merged
merged 34 commits into from
Apr 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
776259c
Update repair-visual-studio.md
skylarnam Apr 8, 2019
2fed2e8
Request to include code snippets
kendrahavens Apr 8, 2019
a0911cd
Add copyable code snippet
kendrahavens Apr 9, 2019
6771fb3
Delete unneeded snippet
kendrahavens Apr 9, 2019
82952fd
Merge pull request #4404 from kendrahavens/patch-1
tfosmark Apr 9, 2019
01ad6f0
update Update date on Migrate page
TerryGLee Apr 9, 2019
f540c87
Merge pull request #4410 from TerryGLee/tglee-patch6
PRMerger19 Apr 9, 2019
ba17d45
change cloud-first to Git-first, per request
TerryGLee Apr 9, 2019
dedfaec
update MPC values
TerryGLee Apr 9, 2019
52eb37a
Merge pull request #4411 from TerryGLee/tglee-whatsnew
PRMerger8 Apr 9, 2019
73f2414
Merge pull request #4412 from TerryGLee/tglee-installfix
PRMerger10 Apr 9, 2019
cfddd33
Adds PMA documentation for VS extenders
rub8n Apr 9, 2019
cea2211
update MPC examples
TerryGLee Apr 9, 2019
d2279fb
Merge pull request #4414 from TerryGLee/tglee-installfix
PRMerger7 Apr 9, 2019
d495592
Addresses first set of PR comments.
rub8n Apr 9, 2019
97e3e14
Removes english locale reference from link.
rub8n Apr 9, 2019
4272513
Merge pull request #4402 from skylarnam/patch-1
PRMerger6 Apr 9, 2019
7088feb
add 16.0.1 data for preview and release
TerryGLee Apr 9, 2019
5a4b431
Merge pull request #4415 from TerryGLee/tglee-vsrelease
PRMerger17 Apr 9, 2019
582d7be
revise Refactorings text
TerryGLee Apr 9, 2019
f7b3aa3
Merge pull request #4416 from TerryGLee/tglee-whatsnew
PRMerger8 Apr 9, 2019
4b7fdb1
Moves PMA doc from IDE to extensibility
rub8n Apr 9, 2019
438cf65
Merge pull request #4406 from MicrosoftDocs/repo_sync_working_branch
ghogen Apr 9, 2019
0bbfb53
Addresses spelling and grammar feedback from Acrolinx
rub8n Apr 9, 2019
dcee682
Simplifies TOC title
rub8n Apr 10, 2019
2837a91
Moving doc from Extensibility to UX guidelines
rub8n Apr 10, 2019
f3bb572
Fixes image path issue & TOC path issue
rub8n Apr 10, 2019
b4aeb20
Fixing image path
rub8n Apr 10, 2019
0d115f8
sentence capitalization in headings
tfosmark Apr 10, 2019
7cdc606
Merge pull request #4413 from rub8n/master
tfosmark Apr 10, 2019
8454a85
Unity 2018.3 is needed for Visual Studio 2019 support
sailro Apr 10, 2019
1ebfb1f
Merge pull request #4417 from sailro/patch-11
PRMerger15 Apr 10, 2019
0a2fdc2
Merge pull request #4420 from MicrosoftDocs/master
Taojunshen Apr 10, 2019
6c6e210
Merging changes synced from https://github.com/MicrosoftDocs/visualst…
gewarren Apr 10, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ Visual Studio Tools for Unity change log.

- **Integration:**

- Added support for Visual Studio 2019.
- Added support for Visual Studio 2019 (you need at least Unity 2018.3 for being able to use Visual Studio 2019 as an external script editor).

- Adopted the Visual Studio image service and catalog, with full support for HDPI scaling, pixel perfect images and theming.

Expand Down
2 changes: 2 additions & 0 deletions docs/extensibility/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,8 @@
href: ux-guidelines/animations-for-visual-studio.md
- name: Evaluation Tools
href: ux-guidelines/evaluation-tools-for-visual-studio.md
- name: Per-monitor-awareness support
href: ux-guidelines/per-monitor-awareness-extenders.md
- name: Addressing DPI Issues
href: addressing-dpi-issues2.md
- name: Image Service and Catalog
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
220 changes: 220 additions & 0 deletions docs/extensibility/ux-guidelines/per-monitor-awareness-extenders.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
---
title: "Per-Monitor Awareness support for Visual Studio extenders"
titleSuffix: ""
description: "Learn about the new extender support for per-monitor-awareness available in Visual Studio 2019."
ms.date: 04/09/2019
helpviewer_keywords:
- "Visual Studio, PMA, per-monitor-awareness, extenders, Windows Forms"
- "Per-Monitor Awareness support for extenders"
ms.assetid:
author: rub8n
ms.author: rurios
manager: anthc
ms.prod: visual-studio-windows
ms.technology: vs-ide-general
ms.topic: reference
ms.workload:
- "multiple"
---

# Per-Monitor Awareness support for Visual Studio extenders

Versions prior to Visual Studio 2019 had their DPI awareness context set to system aware, rather than a per-monitor DPI aware (PMA). Running in System awareness resulted in a degraded visual experience (e.g. blurry fonts or icons) whenever Visual Studio had to render across monitors with different scale factors or remote into machines with different display configurations (e.g. different Windows scaling).

The DPI awareness context of Visual Studio 2019 is set as per-monitor aware, allowing Visual Studio to render according to the configuration of the display where it's hosted rather than a generic system defined configuration. Ultimately translating into a crisp UI for surface areas that implement PMA support.

Refer to the [High DPI Desktop Application Development on Windows](https://docs.microsoft.com/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows) documentation for more information about the terms and overall scenario covered in this document.

## Quickstart
- Ensure Visual Studio is running in PMA mode (See **Enabling PMA**)

- Validate your extension works correctly across a set of common scenarios (See **Testing your extensions for PMA issues**)

- If you find issues, you’ll need to add the new PMA nugget package, diagnose, and fix issues using the strategies & recommendations discussed in this document

## Enabling PMA
To enable PMA in Visual Studio, the following requirements need to be met:
1) Windows 10 April 2018 Update (v1803, RS4) or later
2) .NET Framework 4.8 RTM or greater (currently ships as standalone preview or bundle with recent Windows Insider builds)
3) Visual Studio 2019 with the ["Optimize rendering for screens with different pixel densities"](https://docs.microsoft.com/visualstudio/ide/reference/general-environment-options-dialog-box?view=vs-2019) option enabled

Once these requirements are met, Visual Studio will automatically enable PMA across the process.

## Testing your extensions for PMA issues

Visual Studio officially supports the WPF, Windows Forms, Win32, and HTML/JS UI frameworks. When Visual Studio is put into PMA mode, the different UI stacks behave differently. Therefore, regardless of UI framework, it's recommended that a test pass is performed to ensure all UI is compliant with PMA.

Regardless of the UI framework your extension supports, it's recommended you validate the following common scenarios:

1. Changing the scale factor of a single monitor environment while the application is running*
- This scenario helps test that UI is responding to the dynamic Windows DPI change

2. Docking/undocking a laptop where an attached monitor is set to the primary and the attached monitor has a different scale factor than the primary while the application is running.
- This scenario helps test that UI is responding to the display DPI change as well as handling displays dynamically being added or removed

3. Having multiple monitors with different scale factors and moving the application between them.
- This scenario helps test that UI is responding to the display DPI change

4. Remoting into a machine when the local and remote machines have different scale factors for the primary monitor.
- This scenario helps test that UI is responding to the dynamic Windows DPI change

A good preliminary test for whether UI might have problems is whether or not the code utilizes either the *Microsoft.VisualStudio.Utilities.Dpi.DpiHelper* or *Microsoft.VisualStudio.PlatformUI.DpiHelper* classes. These old DpiHelper classes only support System DPI awareness and won’t always function correctly when the process is PMA.

Typical usage of these DpiHelpers will look like:

```cs
Point screenTopRight = logicalBounds.TopRight.LogicalToDeviceUnits();

POINT screenIntTopRight = new POINT
{
x = (int)screenTopRIght.X,
y = (int)screenTopRIght.Y
}

IntPtr monitor = NativeMethods.MonitorFromPoint(screenIntTopRight, NativeMethods.Monitor_DEFAULTTONEARST);
```

In the previous example, a rectangle representing the logical bounds of a window is converted to device units so that it can be passed to the native method MonitorFromPoint that expects device coordinates in order to return back an accurate monitor pointer.

### Classes of issues

When PMA is enabled for Visual Studio, the UI could replicate issues in several common ways. Most, if not all, of these issues can happen in any of Visual Studios supported UI frameworks. Additionally, these issues can happen even when a piece of UI is being hosted in mixed-mode DPI scaling scenarios (refer to the Windows [documentation](https://docs.microsoft.com/windows/desktop/hidpi/high-dpi-desktop-application-development-on-windows) to learn more).

#### Win32 window creation
When creating windows with CreateWindow() or CreateWindowEx(), a common pattern is to create the window at coordinates 0,0 (the top/left corner of the primary display), then move it to its final position. However, doing so can cause the window to trigger a DPI changed message or event, which can retrigger other UI messages or events, and eventually lead to undesired behavior or rendering.

#### WPF element placement
When moving WPF elements using the old Microsoft.VisualStudio.Utilities.Dpi.DpiHelper, top-left coordinates might not be calculated correctly whenever elements are in the non-primary DPI case.

#### Serialization of UI element sizes or positions
Whenever UI size or position is restored at a different DPI context than what it was stored at, it will be positioned and sized incorrectly. This happens because the logical bounds of a window are converted to device units so that it can be passed to the Win32 method MonitorFromPoint that expects device coordinates in order to return back an accurate monitor pointer.

#### Incorrect scaling
UI elements created on the primary DPI will scale correctly, however when moved to a display with a different DPI, they don't rescale and thus, their content ends up being too large or too small.

#### Incorrect bounding
Similarly, to the scaling problem, UI elements will calculate their bounds correctly on their primary DPI context, however when moved to a non-primary DPI, they won't calculate the new bounds correctly. As such, the content window ends up being too small or too large compared to the hosting UI, which results in empty space or clipping.

#### Drag & drop
Whenever inside mixed-mode DPI scenarios (e.g. different UI elements rendering in both primary and non-primary DPI context), drag and drop coordinates could be miscalculated, resulting in the final drop position end up incorrect.

#### Out-of-process UI
Some UI is created out-of-process and if the creating external process is in a different DPI awareness mode than Visual Studio, this can introduce any of the previous rendering issues.

#### Windows Forms controls, images, or windows not displaying
One of the main causes for this issue is developers trying to reparent a control or window with one DpiAwarenessContext to a different DpiAwarenessContext window.

The following pictures show the current Windows operating system restrictions in parenting windows, unless thread hosting behavior is explicitly changed:

![A screenshot of the correct parenting behavior](../../extensibility/ux-guidelines/media/PMA-parenting-behavior.PNG)

As a result, if you set parent-child relationship between unsupported modes, it will fail, and the control or window may not be rendered as expected.

### Diagnosing issues
There are many factors to consider when identifying PMA-related issues:

1. Does the UI or API expected logical or device values.
- WPF UI and APIs typically use logical values (but not always)
- Win32 UI and APIs typically use device values

2. Where are the values coming from?
- If receiving values from other UI or API, is it passing device or logical values.
- If receiving values from multiple sources, do they all use/expect the same types of values or do conversions need to be mixed and matched?

3. Are UI constants in use and what form are they in?

4. Is the thread in the correct DPI context for the values it's receiving?
- The changes to enable CLMM should generally put code paths in the right context, however, work done outside the main message loop or event flow might execute in the wrong DPI context.

5. Do values cross DPI context boundaries?
- Drag & drop is a common situation where coordinates can cross DPI contexts. Window tries to do the right thing, but in some cases, the host UI may need to do conversion work to ensure matching context boundaries.

### PMA Nugget package
The new DpiAwarness libraries can be found on the Microsoft.VisualStudio.DpiAwareness NuGet package.

### Recommended tools
The following tools can help debug PMA-related issues across some of the different UI stacks supported by Visual Studio.

#### Snoop
Snoop is a XAML debugging tool that has some extra functionality that the built-in Visual Studio XAML tools doesn’t have. Additionally, Snoop doesn’t need to actively debug Visual Studio to be able to view and tweak its WPF UI. The two main ways Snoop can be useful for diagnosing PMA issues is for validating logical placement coordinates or size bounds, and for validating the UI has the right DPI.

#### Visual Studio XAML tools
Like Snoop, the XAML tools in Visual Studio can help diagnose PMA issues. Once a likely culprit is found, you can set breakpoints, and use the Live Visual Tree window as well as the debug windows, to inspect UI bounds and current DPI.

## Strategies for fixing PMA issues

### Replacing DpiHelper calls
In most cases, fixing UI issues in PMA boils down to replacing calls in managed code to the old:
*Microsoft.VisualStudio.Utilities.Dpi.DpiHelper* and *Microsoft.VisualStudio.PlatformUI.DpiHelper* classes, with calls to the new *Microsoft.VisualStudio.Utilities.DpiAwareness* helper class.

For native code, it will entail replacing calls to the old *VsUI::CDpiHelper* class with calls to the new *VsUI::CDpiAwareness* class. The new DpiAwareness and CDpiAwareness classes offer the same conversion helpers as the DpiHelper classes but require an additional input parameter: the UI element to use as a reference for the conversion operation.

The managed DpiAwareness class offers helpers for WPF Visuals, Windows Forms Controls, and Win32 HWNDs and HMONITORs (both in the form of IntPtrs), while the native CDpiAwareness class offers HWND and HMONITOR helpers.

### Windows Forms dialogs, windows, or controls displayed in the wrong DpiAwarenessContext
Even after a successful parenting of windows with different DpiAwarenessContext (because of windows default behavior), users may still see scaling issues as different DpiAwarenessContext windows scale differently. As a result, users may see alignment/blurry text or Image issues on the UI.

The solution is to set the correct DpiAwarenessContext scope for all the windows and controls in the application.

### TLMM dialogs
When creating top-level windows such as modal dialogs, it’s important to make sure the thread is in the correct state prior to the HWND being created. The thread can be put into System awareness by using the CDpiScope helper in native or the DpiAwareness.EnterDpiScope helper in managed. (TLMM should generally be used on non-WPF dialogs/windows.)

### Child-level mixed mode (CLMM)

By default, child windows receive the same DPI-awareness mode as their parents. However, you can use SetThreadDpiHostingBehavior to override it and have child windows run in a different scaling mode than their parent or host.


#### CLMM issues
Most of the UI calculation work that happens as part of the main messaging loop or event chain should already be running in the right DPI context. However, if coordinate or sizing calculations are done outside these main workflows (such as during an idle time task, or off the UI thread, then the current DPI context might be incorrect leading to UI misplacement or mis-sizing issues. Putting the thread into the correct state for the UI work generally fixes the problem.

#### Opting out of CLMM
If a non-WPF tool window is being migrated to fully support PMA, it will need to opt out of CLMM. To do so, a new interface needs to be implemented: IVsDpiAware.

C#:
```cs
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IVsDpiAeware
{
[ComAliasName("Microsoft.VisualStudio.Shell.Interop.VSDPIMode")]
uint Mode {get;}
}
```

C++:
```cplusplus
IVsDpiAware : public IUnknown
{
public:
HRRESULT STDMETHODCALLTYPE get_Mode(__RCP__out VSDPIMODE *dwMode);
};
```


For managed languages, the best place to implement this interface is in the same class that derives from *Microsoft.VisualStudio.Shell.ToolWindowPane*. For C++, the best place to implement this interface is in the same class that implements *IVsWindowPane* from vsshell.h.

The value returned by the Mode property on the interface is a __VSDPIMODE (and cast to a uint in managed):

```cs
enum __VSDPIMODE
{
VSDM_Unaware = 0x01,
VSDM_System = 0x02,
VSDM_PerMonitor = 0x03,
}
```

- Unaware means the tool window needs to handle 96 DPI, Windows will handle scaling it for all other DPIs. Resulting on content being slightly blurry.
- System means the tool window needs to handle the DPI for the primary display DPI. Any display with a matching DPI will look crisp, but if the DPI is different or changes during the session, Windows will handle the scaling and it will be slightly blurry.
- PerMonitor means the tool window needs to handle all DPIs on all displays and whenever the DPI changes.

**NOTE**: Visual Studio only supports PerMonitorV2 awareness, so the PerMonitor enum value translates to the Windows value of DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2.

## Known issues

### Windows Forms

To optimize for the new mixed-mode scenarios, Windows Forms changed how it creates controls and windows whenever their parent was not explicitly set. Earlier, controls without an explicit parent used an internal "Parking Window" as a temporary parent to the control or window being created.

The "Parking Window" gets its DpiAwarenessContext from the process the application is running under. The control inherits the same DpiAwarenessContext as the Parking Window and would then be reparented to the original/expected parent by the application developer. This doesn't work when the intended parent to the control is not the same DpiAwarenessContext as the control being created.

As of .NET 4.8, if the parent is not explicitly set on the control or window, Windows Forms will query for a Parking Window that matches the DpiAwarenessContext of the thread in which the control or window creation is requested and use that as a temporary parent. In other words, upon creation the control is now created with the intended DpiAwarenessContext. The control or window will then be reparented to the expected parent by the application developer.
30 changes: 29 additions & 1 deletion docs/ide/reference/convert-foreach-linq.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,37 @@ This refactoring applies to:
![LINQ query result](media/convert-foreach-to-LINQ-result.png)

![LINQ call form result](media/convert-foreach-to-LINQ-callform-result.png)

### Sample Code

```csharp
using System.Collections.Generic;

public class Class1
{
public void MyMethod()
{
var greetings = new List<string>()
{ "hi", "yo", "hello", "howdy" };

IEnumerable<string> enumerable()
{
foreach (var greet in greetings)
{
if (greet.Length < 3)
{
yield return greet;
}
}

yield break;
}
}
}
```

## See also

- [Refactoring](../refactoring-in-visual-studio.md)
- [Preview Changes](../../ide/preview-changes.md)
- [Tips for .NET Developers](../../ide/visual-studio-2017-for-dotnet-developers.md)
- [Tips for .NET Developers](../../ide/visual-studio-2017-for-dotnet-developers.md)
Loading