# Technical Documentation: dotnet/winforms

> ℹ️ **Provenance:** Multi-Tier Ingestion · [CodeWiki Reference](https://codewiki.google/github.com/dotnet/winforms)

### Overview (`README.md`)

# Windows Forms

[](https://github.com/dotnet/winforms/blob/main/LICENSE.TXT)

Windows Forms (WinForms) is a UI framework for building Windows desktop applications. It is a .NET wrapper over Windows user interface libraries, such as User32 and GDI+. It also offers controls and other functionality that is unique to Windows Forms.

Windows Forms also provides one of the most productive ways to create desktop applications based on the visual designer provided in Visual Studio. It enables drag-and-drop of visual controls and other similar functionality that make it easy to build desktop applications.

## Windows Forms Out-Of-Process Designer

For information about the WinForms Designer supporting the .NET runtime and the changes between the .NET Framework Designer (supporting .NET Framework up to version 4.8.1) vs. the .NET Designer (supporting .NET 6, 7, 8, 9+), please see [Windows Forms Designer Documentation](https://learn.microsoft.com/dotnet/desktop/winforms/controls-design/designer-differences-framework?view=netdesktop-8.0).

**Important:** As a Third Party Control Vendor, when you migrate controls from .NET Framework to .NET, your control libraries _at runtime_ are expected to work as before in the context of the respective new TFM (special modernization or security changes in the TFM kept aside, but those are rare breaking changes). Depending on the richness of your control's design-time support, the migration of control designers from .NET Framework to .NET might need to take a series of areas with breaking changes into account. The provided link points out additional resources which help in that migration process.

## Relationship to .NET Framework

This codebase is a fork of the Windows Forms code in the .NET Framework 4.8. 
We started the migration process by targeting .NET Core 3.0, when we've strived to bring the two runtimes to a parity. Since then, we've done a number of changes, including [breaking changes](https://docs.microsoft.com/dotnet/core/compatibility/winforms), which diverged the two. For more information about breaking changes, see the [Porting guide][porting-guidelines].

## The bar for innovation and new features

WinForms is a technology which was originally introduced as a part of .NET Framework 1.0 on February 13th, 2002. It's primary focus was and is to be a Rapid Application Tool for Windows based Apps, and that principal sentiment has not changed over the years. WinForms at the time addressed developer's requests for

* A framework for stable, monolithic Line of Business Apps, even with extremely complicated and complex domain-specific workflows
* The ability to easily provide rich user interfaces
* A safe and - over the first 3 versions of .NET Framework - increasingly performant way to communicate across process boundaries via various Windows Communication Services, or access on-site databases via ADO.NET providers.
* A very easy to use, visual what-you-see-is-what-you-get designer, which requires little ramp-up time, and was primarily focused to support 96 DPI resolution-based, pixel-coordinated drag & drop design strategies.
* A flexible, .NET reflection-based Designer extensibility model, utilizing the .NET Component Model.
* Visual Controls and Components, which provide their own design-time functionality through Control Designers

Over time, and with a growing need to address working scenarios with multi-monitor, high resolution monitors, significantly more powerful hardware, and much more, WinForms has continued to be modernized.

And then there is the evolution of Windows: When new versions of Windows introduce new or change existing APIs or technologies - WinForms needs to keep up and adjust their APIs accordingly.

And  **that** is still the primary motivation for once to modernize and innovate, but also the bar to reach for potential innovation areas we either need or want to consider:

* Areas, where for example for security concerns, the Windows team needed to take an depending area out-of-proc, and we see and extreme performance hit in WinForms Apps running under a new Service Pack or a new Windows Version
* New features to comply with updated industry standards for accessibility.
* HighDPI and per Monitor V2-Scenarios.
* Picking up changed or extended Win32 Control functionality, to keep controls in WinForms working the way the Windows team wants them to be used.
* Addressing Performance and Security issues
* Introducing ways to support asynchronous calls interatively, to enable apps to pick up migration paths via Windows APIs projection/Windows Desktop Bridge, enable scenarios for async WebAPI, SignalR, Azure Function, etc. calls, so WinForms backends can modernized and even migrated to the cloud.

What would not make the bar: 
* New functionality which modern Desktop UIs like WPF or WinUI clearly have already
* Functionality, which would "stretch" a Windows Desktop App to be a mobile, Multi-Media or IoT app.
* Domain-specific custom controls, which are already provided by the vast variety of third party control vendors

**A note about Visual Basic**: Visual Basic .NET developers make up about 20% of WinForms developers. We welcome changes that are specific to VB if they address a bug in a customer-facing scenario. Issues and PRs should describe the customer-facing scenario and, if possible, include images showing the problem before and after the proposed changes. Due to limited bandwidth, we cannot prioritize VB-specific changes that are solely for correctness or code cleanliness. However, VB remains important to us, and we aim to fix any critical issues that arise.

## Please note

:warning: This repository contains only implementations for Windows Forms for [.NET platform](https://github.com/dotnet/core).<br />
It does not contain either:
* The .NET Framework variant of Windows Forms. Issues with .NET Framework, including Windows Forms, should be filed on the [Developer Community](https://developercommunity.visualstudio.com/spaces/61/index.html) or [Product Support](https://support.microsoft.com/contactus?ws=support) websites. They should not be filed on this repository.
* The Windows Forms Designer implementations. Issues with the Designer can be filed via VS Feedback tool (top right-hand side icon in Visual Studio) or be filed in this repo using the Windows Forms out-of-process designer issue template.

# How can I contribute?

We welcome contributions! Many people all over the world have helped make this project better.

* [Contributing][contributing] explains what kinds of changes we welcome
* [Developer Guide][developer-guide] explains how to build and test
* [Get Up and Running with Windows Forms .NET][getting-started] explains how to get started building Windows Forms applications.


## How to Engage, Contribute, and Provide Feedback

Some of the best ways to contribute are to try things out, file bugs, join in design conversations, and fix issues.

* The [contributing guidelines][contributing] and the more general [.NET contributing guide][net-contributing] define contributing rules.
* The [Developer Guide][developer-guide] defines the setup and workflow for working on this repository.
* If you have a question or have found a bug, [file an issue](https://github.com/dotnet/winforms/issues/new?template=bug_report.md).
* Use [daily builds][developer-guide] if you want to contribute and stay up to date with the team.

## Reporting security issues

Security issues and bugs should be reported privately via email to the Microsoft Security Response Center (MSRC) <secure@microsoft.com>. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the [Security TechCenter](https://www.microsoft.com/msrc/faqs-report-an-issue). Also see info about related [Microsoft .NET Core and ASP.NET Core Bug Bounty Program](https://www.microsoft.com/msrc/bounty-dot-net-core).

## Code of Conduct

This project uses the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct) to define expected conduct in our community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at conduct@dotnetfoundation.org.

## License

.NET (including the Windows Forms repository) is licensed under the [MIT license](LICENSE.TXT).

## .NET Foundation

.NET Windows Forms is a [.NET Foundation](https://www.dotnetfoundation.org/projects) project.<br />
See the [.NET home repository](https://github.com/Microsoft/dotnet) to find other .NET-related projects.

[contributing]: CONTRIBUTING.md
[developer-guide]: docs/developer-guide.md
[getting-started]: docs/getting-started.md
[net-contributing]: https://github.com/dotnet/runtime/blob/master/CONTRIBUTING.md
[porting-guidelines]: docs/porting-guidelines.md

---

### Overview (`docs/designer/readme.md`)

# Windows Forms Out-Of-Process Designer

The Windows Forms out-of-process designer is currently available as a preview Visual Studio feature in [Visual Studio 2019 or later](https://visualstudio.microsoft.com/vs/preview/). It can be enabled in **Tools -> Options -> Environment -> Preview Features** dialog by checking the **Use the preview Windows Forms out-of-process designer for .NET apps** checkbox.
 Releases of .NET Windows Forms Designer are tied to Visual Studio Preview releases, so update to the latest Visual Studio Preview version to get the newest designer features.

:heavy_exclamation_mark: `Visual Studio 2022 v17.12 Preview 3` announces a change in the OOP designer support. [Upgrade Your Windows Forms .NET Projects to the Latest .NET Version for Enhanced Security](https://devblogs.microsoft.com/visualstudio/upgrade-your-windows-forms-net-projects-to-the-latest-net-version-for-enhanced-security/)

For the news on the designer please refer to [the series of blogs](https://devblogs.microsoft.com/search?query=winforms&blog=%2Fdotnet%2F):
* [Modernization of code-behind generation](./modernization-of-code-behind-in-OOP-designer/modernization-of-code-behind-in-oop-designer.md)
* [Custom Controls for WinForms' Out-Of-Process Designer](https://devblogs.microsoft.com/dotnet/custom-controls-for-winforms-out-of-process-designer/)
* [Visual Basic WinForms Apps in .NET 5 and Visual Studio 16.8](https://devblogs.microsoft.com/dotnet/visual-basic-winforms-apps-in-net-5-and-visual-studio-16-8/)
* [Databinding with the OOP Windows Forms Designer](https://devblogs.microsoft.com/dotnet/databinding-with-the-oop-windows-forms-designer/)
* [State of the Windows Forms Designer for .NET Applications as of 01/13/2022](https://devblogs.microsoft.com/dotnet/state-of-the-windows-forms-designer-for-net-applications/)

### WinForms out of process designer SDK

For more information about creating custom control libraries, including sample code and templates refer to the [WinForms Designer Extensibility Repo](https://github.com/microsoft/winforms-designer-extensibility/). Details about how to use the WinForms Designer Extensibility SDK and structure a control library nuget package can be found there as well. Download the Extensibility SDK from [NuGet](https://www.nuget.org/packages/Microsoft.WinForms.Designer.SDK).

### Reporting bugs in the WinForms Designer

To make bug reports visible to the large number of users and let them comment and vote on bugs, please use the [Visual Studio bug reporting feature](https://learn.microsoft.com/visualstudio/ide/how-to-report-a-problem-with-visual-studio?view=vs-2022). This tooling provides secure dump and screenshot upload options.

## Table of Content

* [How to use .NET Framework designer for .NET applications](net-inproc-designer.md)
* [How to troubleshoot the out-of-process designer](troubleshooting.md)

---

### Overview (`eng/ApiCompatibility/README.md`)

### Mark Shipped Tool
========

This tool should be run after every supported release that has API changes. It will 
merge the collection of PublicApi.Shipped.txt files with the PublicApi.Unshipped.txt 
versions.  This will take into account `*REMOVED*` elements when updating the files.

Usage:

``` cmd
mark-shipped.cmd
```

---

### Overview (`eng/common/README.md`)

# Don't touch this folder

                uuuuuuuuuuuuuuuuuuuu
              u" uuuuuuuuuuuuuuuuuu "u
            u" u$$$$$$$$$$$$$$$$$$$$u "u
          u" u$$$$$$$$$$$$$$$$$$$$$$$$u "u
        u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
      u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
    u" u$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$u "u
    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
    $ $$$" ... "$...  ...$" ... "$$$  ... "$$$ $
    $ $$$u `"$$$$$$$  $$$  $$$$$  $$  $$$  $$$ $
    $ $$$$$$uu "$$$$  $$$  $$$$$  $$  """ u$$$ $
    $ $$$""$$$  $$$$  $$$u "$$$" u$$  $$$$$$$$ $
    $ $$$$....,$$$$$..$$$$$....,$$$$..$$$$$$$$ $
    $ $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ $
    "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
      "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
        "u "$$$$$$$$$$$$$$$$$$$$$$$$$$$$" u"
          "u "$$$$$$$$$$$$$$$$$$$$$$$$" u"
            "u "$$$$$$$$$$$$$$$$$$$$" u"
              "u """""""""""""""""" u"
                """"""""""""""""""""

!!! Changes made in this directory are subject to being overwritten by automation !!!

The files in this directory are shared by all Arcade repos and managed by automation. If you need to make changes to these files, open an issue or submit a pull request to https://github.com/dotnet/arcade first.

---

### Overview (`pkg/Microsoft.Dotnet.WinForms.ProjectTemplates/readme.md`)

# Windows Forms Projects Templates

We provide the following templates:
* [Windows Forms app (C#)](./content/WinFormsApplication-CSharp)
* [Windows Forms app (VB)](./content/WinFormsApplication-VisualBasic)
* [Windows Forms class library (C#)](./content/WinFormsLibrary-CSharp)
* [Windows Forms class library (VB)](./content/WinFormsLibrary-VisualBasic)
* [Windows Forms control library (C#)](./content/WinFormsControlLibrary-CSharp)
* [Windows Forms control library (VB)](./content/WinFormsControlLibrary-VisualBasic)

# Item templates are located in the VSProject repo
* [VB](https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/vsproject/Templates/Windows/VisualBasic/ItemTemplates/WindowsForms&version=GBmain&_a=contents)
* [C#](https://devdiv.visualstudio.com/DevDiv/_git/VS?path=/src/vsproject/Templates/Windows/CSharp/ItemTemplates&version=GBmain&_a=contents)

## Testing Templates

Before submitting a change to any of the templates please make sure to test them locally.

1. Install the required template with `dotnet` tool (e.g. `WinFormsApplication-CSharp`).<br />
In the command prompt of your choice run the following command:
    ```
    > dotnet new -i <path to the repo>\winforms\pkg\Microsoft.Dotnet.WinForms.ProjectTemplates\content\WinFormsApplication-CSharp
    ```

2. To confirm that the template is correctly installed run the following command and look for your template:
    ```
    > dotnet new -u
    ```
    

3. Create an app from your template:
    ```
    > dotnet new winforms -n testapp1
    ```

4. Verify the app behaves as expected. <br />
If necessary, tweak the template and create new apps.

5. Once you are happy with the template, you can uninstall it to revert to the original by running the command given in `dotnet new -u` output; e.g.
    ```
    > dotnet new -u <path to the repo>\winforms\pkg\Microsoft.Dotnet.WinForms.ProjectTemplates\content\WinFormsApplication-CSharp
    ````

---

### Overview (`pkg/Microsoft.Private.Windows.Core/readme.md`)

# Microsoft Private Windows Core Package

It is an internal only package. Public consumption is not supported.

---

### Overview (`pkg/Microsoft.Private.Winforms/README.md`)

## Overview

This is a transport package consumed by [WPF](https://github.com/dotnet/wpf/) and [WindowsDesktop](https://github.com/dotnet/windowsdesktop/). Some packaging configurations are defined in this project, and others are defined in \<repo root\>\eng\packageContent.targets.


## `sdk\dotnet-windowsdesktop` folder

This folder contains props and targets used to ingest our assemblies into the [Windows Desktop SDK](https://github.com/dotnet/windowsdesktop/), bundling the correct set of assemblies into either the Microsoft.WindowsDesktop.App.Ref pack or Microsoft.WindowsDesktop.App.Runtime pack.

* [`System.Windows.Forms.FileClassification.props`](sdk\dotnet-windowsdesktop\System.Windows.Forms.FileClassification.props) contains a manifest for the "WindowsForms" SDK[&#x00B9;](#ref1), i.e. a list of our assemblies that form it.
The file is imported by [Microsoft.WindowsDesktop.App.Ref project](https://github.com/dotnet/windowsdesktop/blob/main/src/windowsdesktop/src/sfx/Microsoft.WindowsDesktop.App.Ref.sfxproj).<br/>
The manifest will need to be rebuilt if there are changes in the solution with respect to the SDK assemblies, e.g. a new assembly is added or an existing assembly is removed.

### How to update System.Windows.Forms.FileClassification.props

The existing `System.Windows.Forms.FileClassification.props` is be compared against the list of assemblies in `Microsoft.Private.Winforms.[version].nuspec`[&#x00B2;](#ref2) generated as part of the `pack` command.

If the content of these files differ - the build will fail.

:warning: The process is purposefully made manual to ensure changes in the manifest are made consciously.

To update the manifest run the following command and check in the updated files manifest:

```
.\build.cmd -pack /p:_GenerateManifest=true
```

To debug the script run the following command:

```
dotnet build .\pkg\Microsoft.Private.Winforms\Microsoft.Private.Winforms.csproj /t:UpdateTransportPackage /p:_GenerateManifest=true /v:m /bl /p:CommonLibrary_NativeInstallDir=$env:UserProfile\.netcoreeng\native\
```




## `sdk\dotnet-wpf` folder

This folder contains props and targets that are part of [Windows Desktop SDK](https://github.com/dotnet/wpf/blob/main/packaging/Microsoft.NET.Sdk.WindowsDesktop/) (which is hosted and assembled in [dotnet/wpf](https://github.com/dotnet/wpf/)).
These files are referenced  the [Microsoft.NET.Sdk.WindowsDesktop project](https://github.com/dotnet/wpf/blob/main/packaging/Microsoft.NET.Sdk.WindowsDesktop/Microsoft.NET.Sdk.WindowsDesktop.ArchNeutral.csproj)'s props and targets located [here](https://github.com/dotnet/wpf/blob/main/packaging/Microsoft.NET.Sdk.WindowsDesktop/targets). When this project is being built, it copies the files from our transport NuGet package to a Microsoft.NET.Sdk.WindowsDesktop bundle.

* [`Microsoft.NET.Sdk.WindowsDesktop.WindowsForms.props`](sdk\dotnet-wpf\Microsoft.NET.Sdk.WindowsDesktop.WindowsForms.props) contains various Windows Forms specific configurations, such as  our default `using` imports.

* [`Microsoft.NET.Sdk.WindowsDesktop.WindowsForms.targets`](sdk\dotnet-wpfp\Microsoft.NET.Sdk.WindowsDesktop.WindowsForms.targets) contains various Windows Forms specific targets.

* [`System.Windows.Forms.Analyzers.props`](sdk\dotnet-wpf\System.Windows.Forms.Analyzers.props) contains a list of properties required by our source generators.


<br/>
<br/>

----

<a name="ref1"></a>1. Except for `Accessibility.dll` which is [noted explicitly](https://github.com/dotnet/windowsdesktop/blob/f497549de5c2dba4d296c3311de71e12db808c65/pkg/windowsdesktop/sfx/Microsoft.WindowsDesktop.App.Ref.sfxproj#L18).

<a name="ref2"></a>2. Generated in .\winforms\artifacts\obj\Microsoft.Private.Winforms\\[Debug|Release].

---

### Overview (`src/Accessibility/readme.md`)

# Accessibility

This directory contains source files used to build Accessibility.dll, the managed wrapper for COM accessibility interface.

See https://docs.microsoft.com/dotnet/api/accessibility

Source in this directory is generated by a tool and **should not be modified directly**.

To produce the IL source the following process is used:
1. Use https://aka.ms/tlbimp to generate an assembly for oleacc.dll

```cmd
tlbimp c:\windows\system32\oleacc.dll /out:Accessibility.dll
```

2. Use ildasm to disassemble that assembly.

```cmd
ildasm Accessibility.dll /out=Accessibility.il
```

3. Replace the desktop assembly references with their corresponding .NETCore assemblies (since .NETCore doesn't provide a version of tlbimp.exe yet)
    - replace `[mscorlib]System.Runtime.InteropServices` with `[INTEROP_ASSEMBLY]System.Runtime.InteropServices`
    - replace `[mscorlib]` with `[CORE_ASSEMBLY]`
    - review the diff

4. Add assembly level attributes to the IL

---

### Overview (`src/System.Drawing.Common/README.md`)

# System.Drawing.Common
This assembly provides access to GDI+ basic graphics functionality via types such as [`Bitmap`](https://learn.microsoft.com/dotnet/api/system.drawing.bitmap) and [`Font`](https://learn.microsoft.com/dotnet/api/system.drawing.font).

Note that `System.Drawing.Common` is only supported on Windows: https://learn.microsoft.com/dotnet/core/compatibility/core-libraries/6.0/system-drawing-common-windows-only.

Documentation can be found at https://learn.microsoft.com/dotnet/api/system.drawing.

## Contribution Bar
- [x] We consider new features, new APIs and performance changes
- [x] We consider PRs that target this library for new source code analyzers
- [ ] We don't accept refactoring changes due to new language features

See the [Help Wanted](https://github.com/dotnet/winforms/labels/help%20wanted) issues.

## Deployment
`System.Drawing.Common` is provided as a [NuGet package](https://www.nuget.org/packages/System.Drawing.Common) and part of the `Microsoft.WindowsDesktop.App` shared framework.

---

### Overview (`src/System.Windows.Forms.PrivateSourceGenerators/README.md`)

This project contains source generators that are used during the build of the Windows Forms SDK.
For example, to emit code that validates enum arguments.

---

### Overview (`src/System.Windows.Forms.Analyzers/tests/README.md`)

# Extending WinForms analyzers

Analyzer tests use Roslyn's native C# and Visual Basic test types through the thin, language-neutral
`AnalyzerTestCase` and `AnalyzerTestFactory` helpers in `UnitTests`. Keep analyzer behavior in the
language project and reusable descriptors, resources, and semantic facts in the shared project.

## Adding a diagnostic

1. Reserve a WFO ID in
   `src\System.Windows.Forms.Analyzers\src\System\Windows\Forms\Analyzers\Diagnostics\DiagnosticIDs.cs`.
2. Add the localized title and message to `src\System.Windows.Forms.Analyzers\src\Resources\SR.resx`,
   then build so the XLF files are synchronized.
3. Add a descriptor to the shared or language-specific descriptor class.
4. Implement the analyzer under the applicable C# or Visual Basic `src\Analyzers` tree. Put common
   semantic detection in the shared analyzer project; keep syntax APIs language-specific.
5. Track the rule in `AnalyzerReleases.Unshipped.md` and document it in the applicable
   `docs\analyzers\WinFormsCSharpAnalyzers.Help.md` or
   `docs\analyzers\WinFormsVisualBasicAnalyzers.Help.md` file.
6. Add exact diagnostic ID, argument, path, and span assertions to the applicable test project.
   Document why a rule is language-specific when no equivalent syntax exists.

Do not add a code fix unless the transformation is safe and deterministic.

## Writing tests

Use inline `AnalyzerTestSource` values for focused behavior. Use named fixture files under a
`TestData` directory when a realistic source set would obscure the assertion. For Designer rules,
always provide both the user file and its `.Designer.cs` or `.Designer.vb` counterpart, and derive the
partial type from `Form`, `UserControl`, another `Control` type, or
`System.ComponentModel.Component`. Include negative cases with same-named types in unrelated
namespaces. For VB, use realistic `WithEvents`/`Handles` fixtures and distinguish member events from
`GenerateMember=False` local-variable wiring. Never modernize generated `Dispose` fixtures merely
to match restrictions that apply only to `InitializeComponent`.

Create the language-native Roslyn test through `AnalyzerTestFactory`; do not add another test base
class or block asynchronous calls:

```csharp
AnalyzerTestCase testCase = new(
    ReferenceAssemblies.Net.Net90Windows,
    new AnalyzerTestSource("Form1.cs", mainSource),
    new AnalyzerTestSource("Form1.Designer.cs", designerSource));

await AnalyzerTestFactory.CreateCSharpAnalyzerTest<MyAnalyzer>(testCase)
    .RunAsync(TestContext.Current.CancellationToken);
```

Use `AnalyzerConfigFiles` for `.editorconfig` or `.globalconfig` cases, `AdditionalFiles` for
non-source analyzer inputs, and `AdditionalReferences` for metadata paths. Tests that need the latest
WinForms API surface should use `CurrentReferences.NetCoreAppReferences` and add
`CurrentReferences.WinFormsRefPath`, following the existing WFO2001 tests.
The helper reads the configured SDK's runtime metadata and requires its exact reference pack; an
SDK version is not a runtime-pack version, and another installed preview is not a safe substitute.

Designer diagnostics must include a concise supported repair in the emitted message, not only in
the help page. Test representative rendered messages under an invariant culture as well as IDs,
arguments, paths, spans, suppression, and absence of analyzer exceptions. Preserve separate IDs for
independently repairable constructs.

## Syntax coverage boundary

The existing expression rules remain enforced because their constructs cannot round-trip through
the designer's CodeDOM contract. WFO3000 also covers structural `using`/`Using` and `await`/`Await`,
and the C# variants include expression-bodied initialization and deconstructing `foreach`. WFO3007
includes coalescing assignment.

Do not infer support for all C# or VB syntax from this list. Standalone patterns, tuples/deconstruction,
implicit object creation, object/collection initializers, queries, VB `With`, XML/anonymous objects,
and unstructured error handling are not additional rules in this change. Some require source-parser
lowering evidence outside this repository before an accurate restriction and mitigation can be
defined. Unlisted does not mean supported. The current Roslyn package is 4.12; syntax from newer
compiler versions also needs explicit compatibility work rather than guessed syntax matching.

## Targeted validation

Run these from the repository root:

```powershell
dotnet test src\System.Windows.Forms.Analyzers\tests\UnitTests\System.Windows.Forms.Analyzers.Tests.csproj -nologo
dotnet test src\System.Windows.Forms.Analyzers.CSharp\tests\UnitTests\System.Windows.Forms.Analyzers.CSharp.Tests.csproj -nologo
dotnet test src\System.Windows.Forms.Analyzers.VisualBasic\tests\UnitTests\System.Windows.Forms.Analyzers.VisualBasic.Tests\System.Windows.Forms.Analyzers.VisualBasic.Tests.vbproj -nologo
```

Before reporting the change as build-clean, run the repository-supported `.\build.cmd`; a plain
solution build does not apply all CI analyzers and warning settings.

---

### Overview (`src/test/integration/DesignSurface/README.md`)

# DesignSurface (DemoConsole)

- [Debugging Native Code in This Project](#debugging-native-code-in-this-project)
  - [1. Enable Native Code Debugging](#1.-enable-native-code-debugging)
  - [2. Configure Symbol Server for Native Debugging (Symweb)](<#2.-configure-symbol-server-for-native-debugging-(symweb)>)
- [Running the Project Against .NET Framework](#running-the-project-against-.net-framework)

## Debugging Native Code in This Project

To fully enable debugging in this project (including native code and symbol resolution), perform the following two steps:

### 1. Enable Native Code Debugging

This allows Visual Studio to step into native code

**Option A – Using Visual Studio GUI:**

1. Right-click the project in Solution Explorer and select **Properties**.
2. Go to the **Debug** then **Open debug launch profiles UI**.
3. Check the box **Enable native code debugging**.
4. Save and rebuild the project.

> This setting is saved in a user-specific `.csproj.user` file.

**Option B – Editing `launchSettings.json`:**

1. Open the file `Properties\launchSettings.json`.
2. Under the `"profiles"` section, locate the profile matching your project name.
3. Add or update the property `"nativeDebugging": true`.

Example:

```json
{
  "profiles": {
    "YourProjectName": {
      "commandName": "Project",
      "nativeDebugging": true
    }
  }
}
```

---

### 2. Configure Symbol Server for Native Debugging (Symweb)

To resolve native symbols when stepping through native code, configure the Symweb server:

1. Go to **Debug > Options** from the Visual Studio toolbar.
2. In the left pane, select **Debugging > Symbols**.
3. Under **Symbol file (.pdb) locations**, click the **➕** (plus) button.
4. Enter the following URL:

```
https://symweb
```

5. Press **Enter** or click **OK** to save.

---

After completing both steps above, Visual Studio will be able to debug both managed and native parts of the application, using symbols downloaded from Symweb as needed.

## Running the Project Against .NET Framework

This project targets multiple frameworks, including .NET Framework 4.8.1. To run or debug it against the .NET Framework instead of .NET (e.g., net11.0-windows), follow the steps below:

1. In Visual Studio, locate the Debug dropdown on the top toolbar (next to the green **Start** button).
2. Click the small downward arrow next to the active configuration. You will see the currently selected framework (typically something like `Framework (net11.0-windows)`).
3. Click the displayed framework name to open a submenu showing all target frameworks for this project.
4. Select **net481** from the list.
5. Build and run the project using any of the usual commands:
   - **Build**: `Ctrl + Shift + B`
   - **Start Without Debugging**: `Ctrl + F5`
   - **Start With Debugging**: `F5`

This configuration change ensures that Visual Studio builds and runs the project using the .NET Framework target.

---

### Overview (`src/test/integration/System.Windows.Forms.Maui.IntegrationTests/readme.md`)

# Porting a Winforms Maui test to xUnit

## Summary

This document details how to port an existing WinForms Maui test to xUnit so it can be run as part of our continuous integration builds. 

If you run into any problems, please contact Adam Yoblick.

## Cloning and building source code

1. If you have not already done so, clone or fork the repo at https://github.com/dotnet/winforms

1. Checkout a new branch for your work with the following command:
        
        git checkout -b <your-new-branch-name>

1. Run a build and execute integration tests with the following command:

        .\build -integrationTest /m:1

1. If the above step fails, **STOP**.

    See https://github.com/dotnet/winforms/tree/main/Documentation for more verbose instructions on how to build this repo.

## Porting the maui test

See the pull request at https://github.com/dotnet/winforms/pull/1240 for an example of how to do this.

1. Browse to .\src\System.Windows.Forms\tests\IntegrationTests\MauiTests. All Maui tests live under this folder, each in their own folder.
	
1. Create a copy of the existing MauiButtonTest folder in the same directory

    1. Rename the new folder to something more appropriate for the test you are porting (`MauiComboBoxTest`, for example)
    1. Browse into the new folder and rename the .csproj to the name you chose in step 3 (`MauiComboBoxTest.csproj`, for example)
    1. Delete the existing MauiButtonTest.cs file

1. Find the source code for the test you are porting and copy it into the new folder you created in the previous step

1. Clean up the Maui test source:

    1. Rename the file appropriately (`MauiComboBoxTest.cs`, for example)
    1. Add `using System.Windows.Forms.IntegrationTests.Common;` to the using directives.
    1. Change the namespace to `System.Windows.Forms.IntegrationTests.MauiTests`
    1. Rename the class appropriately (`MauiComboBoxTest`, for example)
    1. Add the following line as the first command in the constructor:
    
            this.BringToForeground();

    1. Add the following line as the first command in Main():
    
            Thread.CurrentThread.SetCulture("en-US");

    1. Make sure each scenario method has the `[Scenario(true)]` attribute
    1. Remove the entire `[Scenarios]` section at the bottom of the file
    1. Make sure each scenario method’s name describes what the test is actually doing. 
    
        For example, the button scenario methods are named as follows:
            
            Click_Fires_OnClick()
            Hotkey_Fires_OnClick()
            Hotkey_DoesNotFire_OnClick()

    1. Clean up the code style, following visual studio suggestions (we will catch these in a PR, but it is good to clean up beforehand). For example:
        1. Use implicit types (var) whenever possible
        1. All fields should have access modifiers
        1. Prefer built-in types instead of classes (“string” is preferred to “String”)
        1. Only use “this” when necessary
        1. Etc...

## Update the WinForms solution

1. Open `.\Winforms.sln` in Visual Studio
1. In the solution explorer, browse to `tests\integration\maui`
1. Right-click on the maui folder and click on `Add -> Existing Project...`
1. Add the csproj you created in the previous section

## Run the maui test manually

1. Open a command prompt and browse to the root of your repo.
1. Build the source code (including the test you just ported):

        .\build-local.ps1
	
1. Browse to `.\artifacts\bin\<your-test-name>\Debug\net6.0`
1. Double click on `<your-test-name>.exe`
1. Check the results.log in the same directory to make sure everything passed
1. If anything shows as a failure in the log, **STOP**. 

    Figure out why the scenario  is failing and fix it before moving on.

## Run the maui test through the local build

1. Browse to `.\src\System.Windows.Forms\tests\IntegrationTests\System.Windows.Forms.Maui.IntegrationTests`
1. Copy `WinformsMauiButtonTest.cs` to a new file in the same directory
1. Rename the new file according to the Maui test you added in the earlier section (`WinformsMauiComboBoxTest.cs`, for example)
1. Rename the class to the same thing (`WinformsMauiComboBoxTest`, for example)
1. Change the ProjectName string to match the name of the Maui test project you added in the earlier section (`MauiComboBoxTest`, for example)

    **Note that this must EXACTLY MATCH the project name for the test runner to find your Maui test executable**
	
1. Change the name of the single test method to match the name of your project (`MauiComboBoxTest`, for example)
1. Open a command prompt and browse to the root of your repo.
1. Run the following command:

        .\build -integrationTest /m:1
	
1. Verify all the integration tests pass. If there is a failure, the following files may help:
    - xUnit test results summary can be found at `.\artifacts\TestResults\Debug\System.Windows.Forms.Maui.IntegrationTests_net6.0_x64.html`
    - xUnit test outputs can be found at `.\artifacts\log\Debug\System.Windows.Forms.Maui.IntegrationTests_net6.0_x64.log`
    - The results.log for your individual Maui test can be found at `.\artifacts\bin\<your-test-name>\Debug\net6.0\results.log`

## Run the maui test through the CI build

1. Create a pull request from your new branch (or fork) to the winforms main at https://github.com/dotnet/winforms/compare
1. Once the PR is created (and every time new files are pushed to the PR), the build will kick off
1. You can see the result of the build by scrolling down to the checks section and clicking on Show All Checks
1. If the build is not successful, try to investigate the failure
    1. Click on Details next to the dotnet-winforms CI check
    1. Examine the build output. You can also click on the Summary tab and download build artifacts, which will include the same logs you examined locally

---

### Overview (`src/test/integration/DesignSurface/DemoConsole/README.md`)

# DesignSurface (DemoConsole)

- [Debugging Native Code in This Project](#debugging-native-code-in-this-project)
  - [1. Enable Native Code Debugging](#1.-enable-native-code-debugging)
  - [2. Configure Symbol Server for Native Debugging (Symweb)](<#2.-configure-symbol-server-for-native-debugging-(symweb)>)
- [Running the Project Against .NET Framework](#running-the-project-against-.net-framework)

## Debugging Native Code in This Project

To fully enable debugging in this project (including native code and symbol resolution), perform the following two steps:

### 1. Enable Native Code Debugging

This allows Visual Studio to step into native code

**Option A – Using Visual Studio GUI:**

1. Right-click the project in Solution Explorer and select **Properties**.
2. Go to the **Debug** then **Open debug launch profiles UI**.
3. Check the box **Enable native code debugging**.
4. Save and rebuild the project.

> This setting is saved in a user-specific `.csproj.user` file.

**Option B – Editing `launchSettings.json`:**

1. Open the file `Properties\launchSettings.json`.
2. Under the `"profiles"` section, locate the profile matching your project name.
3. Add or update the property `"nativeDebugging": true`.

Example:

```json
{
  "profiles": {
    "YourProjectName": {
      "commandName": "Project",
      "nativeDebugging": true
    }
  }
}
```

---

### 2. Configure Symbol Server for Native Debugging (Symweb)

To resolve native symbols when stepping through native code, configure the Symweb server:

1. Go to **Debug > Options** from the Visual Studio toolbar.
2. In the left pane, select **Debugging > Symbols**.
3. Under **Symbol file (.pdb) locations**, click the **➕** (plus) button.
4. Enter the following URL:

```
https://symweb
```

5. Press **Enter** or click **OK** to save.

---

After completing both steps above, Visual Studio will be able to debug both managed and native parts of the application, using symbols downloaded from Symweb as needed.

## Running the Project Against .NET Framework

This project targets multiple frameworks, including .NET Framework 4.8.1. To run or debug it against the .NET Framework instead of .NET (e.g., net11.0-windows), follow the steps below:

1. In Visual Studio, locate the Debug dropdown on the top toolbar (next to the green **Start** button).
2. Click the small downward arrow next to the active configuration. You will see the currently selected framework (typically something like `Framework (net11.0-windows)`).
3. Click the displayed framework name to open a submenu showing all target frameworks for this project.
4. Select **net481** from the list.
5. Build and run the project using any of the usual commands:
   - **Build**: `Ctrl + Shift + B`
   - **Start Without Debugging**: `Ctrl + F5`
   - **Start With Debugging**: `F5`

This configuration change ensures that Visual Studio builds and runs the project using the .NET Framework target.

---

### Overview (`src/System.Windows.Forms/System/Windows/Forms/Controls/Unsupported/readme.md`)

### History
WinForms had documented some NETFX 1.1 APIs as obsolete in NETFX 2.0, but didn't decorate them with the [Obsolete] attributes. We shipped them in .NET3.0, then removed them completely in .NET3.1 - https://learn.microsoft.com/dotnet/core/compatibility/winforms#removed-controls.
The reason to remove these types was that replacement types have been implemented in .NET Framework 2.0 and we had stopped maintaining these classes. Meanwhile, they fell befind in support of the modern features and particularly they don't comply with the accessibility requirements.

### Problem
Since then we received 2 requests to re-introduce the public surface in order to facilitate migration from the .NET Framework. Consider an application that supports extensibility plug ins compiled against the .NET Framework. .NET application can load .NET Framework assemblies if .NET Framework types can be forwarded to the .NET implementations, even if those implementations do nothing. Such plug-ins would load and work if they avoid the unsupported code. However, if the unsupported code is executed, the JIT throws a MissingMemberException that is hard to catch and handle.

### Solution
We are re-adding the previously removed types as "hollow" types to provide binary compatibility. This "implementation" is copied from the .NET Framework 4.8.1 reference assembly. These types can't be executed, as they should be replaced with the modern counterparts as users migrate their applications. The main advantage is that now the above mentioned plugin would load and would throw PlatformNotSupportedException when the problematic code is executed instead of the missing member exceptions at JIT time. And the developer has an option for conditionally avoid calling the hollow methods.
We should not modify code in this folder.

#### Description of changes:
* None of the re-added types can be constructed, all constructors throw new PlatformNotSupportedException(), default constructors are suppressed by introducing throwing public constructors if needed.
* All attributes that have been present on the .NET Framework types, are preserved, as they are accessible by reflection.
* All re-introduced types are decorated with [EditorBrowsable(EditorBrowsableState.Never)] attribute that hides them from the intellisense. Type names can be typed in by the developer manually and intellisense would show the same members as it did for .NET Framework projects.
* All re-introduced types are decorated with the ObsoleteAttribute that results in a compile time warning. All types share a single deprecation warning Id, to simplify suppression, but have different explanation messages.
* All re-introduced types are decorated with [Browsable(false)] attribute to not show custom control properties of these types in the property browser.
* All public members are re-introduced with their metadata, except for the private attributes.
* Members inherited from the base classes (Control, for example) are not re-introduced even if they had been overridden in the past because they are not required for binary compatibility, unless they are decorated with different attributes.
* Members that are re-added to the existing types (Form and Control) are returning defaults or doing nothing.
* Non-void public or protected instance members on the restored types `throw null`, not the `PlatformNotSupportedException` to save space.
* Void public or protected instance members do nothing.
* Public or protected fields return default values.
* Nullability is disabled for all re-added classes, structs and delegates for compatibility with the .NET Framework.

### Use Case
.NET applications can reference .NET Framework 3rd party libraries that use these types. Code will JIT and if the unsupported code is executed, it will throw an exception that can be caught instead of JIT throwing a missing member exception. For example:

```cs
if (control.ContextMenu is not null)
{
    control.ShowContextMenu();
} 
else
{
    // show a ContextMenuStrip
}

try
{
    LegacyControl.ShowContextMenu();
}
catch (PlatformNotSupportedException)
{
    // create a new ContextMenuStrip
}
```

---

### Getting Started (`docs/getting-started.md`)

# Getting started with Windows Forms for .NET

This document describes the experience of using Windows Forms on .NET. The [Developer Guide](developer-guide.md) describes how to develop features and fixes for Windows Forms.

## Installation

Choose one of these options:

1. [.NET 7.0 SDK (recommended)][.net-7.0-sdk]

1. [.NET 8.0 daily build (latest changes, could be less stable)][.net-daily]

## Creating new applications

You can create a new WinForms application with `dotnet new` command, using the following commands:

```cmd
dotnet new winforms -o MyWinFormsApp
cd MyWinFormsApp
dotnet run
```

## Designing Forms

You can try the Windows Forms Core Designer Visual Studio extension, see [Windows Forms Designer documentation](designer-releases/readme.md). As an alternative, you can use [this workaround](winforms-designer.md).

## Samples

Check out the [.NET Windows Forms samples][.net-samples] for both basic and advanced scenarios. Additionally, there is a collection of [Windows Forms sample applications on Microsoft Learn][MSDN-winforms-samples].

## Porting existing applications

To port your existing Windows Forms application from .NET Framework to .NET 6 or .NET 7, refer to our [porting guidelines](porting-guidelines.md).

[comment]: <> (URI Links)

[.net-7.0-sdk]: https://dotnet.microsoft.com/download/dotnet/7.0
[.net-daily]: https://github.com/dotnet/installer/blob/master/README.md#installers-and-binaries
[.net-samples]: https://github.com/dotnet/samples/tree/main/windowsforms
[MSDN-winforms-samples]: https://learn.microsoft.com/samples/browse/?terms=windows%20forms

---

### Net11Api 03 ImproveControlRendering.HighRiskReview (`docs/Net11Api_03_ImproveControlRendering.HighRiskReview.md`)

# Net11Api_03 ImproveControlRendering High-Risk Review

This document records a review finding that needs native lifecycle investigation before it can be patched safely.

## Deferred reveal is not activated during initial display

Reviewed merge base: `8b618e7f5`
Reviewed branch tip: `1ee2b58a6`

The deferred-reveal implementation attempts to cloak a form from `OnHandleCreated`, while `ShouldUseDeferredAppearanceCloak` requires both `IsHandleCreated` and `Visible`. During `Show`, `ShowDialog`, and `Application.Run(form)`, the handle is created while evaluating `HWND`, before `ShowWindow` makes the form visible. The visibility state changes later while processing `WM_SHOWWINDOW`, and there is no subsequent cloak attempt. The intended initial-display cloak therefore does not activate on the normal display path.

A safe correction requires selecting a one-shot point after handle creation but before the first compositor presentation. Moving the operation into `WM_SHOWWINDOW` could cloak later hide/show cycles, while removing the visibility check could cloak hidden forms whose handles are created for unrelated reasons.

Before implementation, document and verify the state timeline for:

- `Show`, `ShowDialog`, and `Application.Run`;
- hidden forms with pre-created handles;
- handle recreation;
- hide/show cycles;
- owned forms and splash screens;
- DWM composition or cloak-call failure.

The selected design should define a one-shot invariant and explicitly reject stale state after handle recreation. Native verification should inspect the DWM cloak state before first paint and after reveal. Automated tests should cover all display paths and preserve a clear rollback path if compositor timing differs across supported Windows versions.

---

### Net11Api 04 KioskManagerComponent.HighRiskReview (`docs/Net11Api_04_KioskManagerComponent.HighRiskReview.md`)

# Net11Api_04 KioskModeManager High-Risk Review

This document records review findings that require an API or lifecycle design decision before they can be patched safely.

## FullScreen requested state and actual state differ

`KioskModeManager.FullScreen` currently returns `true` when fullscreen has been requested but no target form is available. `FullScreenChanged`, however, is raised only when the resolved form actually enters or exits fullscreen. This creates two observable state models:

- The property reports requested state through `_pendingFullScreen || _isFullScreen`.
- The event reports actual window state through changes to `_isFullScreen`.

Consequently, setting `FullScreen = true` without a resolved form changes the property without raising the event. When a form later becomes available, the event is raised even though the property value remains `true`.

Before changing this behavior, decide whether `FullScreen` represents requested state or actual window state. The decision must cover:

- initialization and delayed parenting;
- missing, replaced, reparented, and disposed container controls;
- event ordering and two-way data binding;
- `ToggleFullScreen` behavior while a request is pending;
- disposal and failed fullscreen transitions;
- compatibility for applications already observing the property or event.

Tests should define the complete transition matrix for requested, pending, entered, exited, reparented, and disposed states.

---

### Net11Api 05 VisualStylesMode.HighRiskReview (`docs/Net11Api_05_VisualStylesMode.HighRiskReview.md`)

# Net11Api_05 VisualStylesMode High-Risk Review

This document records animation infrastructure findings that require architecture and lifecycle decisions before they can be patched safely.

## VisualStylesMode transition impact dispatch

`Control.OnVisualStylesModeChanged` now owns impact processing for effective renderer changes. Overrides that
call `base` inherit preferred-size cache clearing, style/non-client frame refresh, invalidation, and deferred
layout for metric-affecting changes. The transition carries immutable old/new effective modes through the
existing `EventArgs` virtual shape; nested property changes cannot overwrite an outer transition, and stale
child cascades are suppressed.

Metric layout requests are collected while the complete affected subtree transitions, then coalesced to one
layout per container. This is required so a container measures only fully updated children and so
`AutoSize = false` text boxes still trigger parent remeasurement. `TextBoxBase` treats only crossings between
classic/disabled and Net11-or-later rendering as metric changes; Net11-to-Latest shares its preferred-height
and non-client padding metrics and repaints only.

`SystemVisualSettings` High Contrast transitions enter the same dispatcher with immutable old/new snapshots.
Every affected control compares its own effective mode, so locally configured descendants are included, while
effective-equality controls bypass visual-styles events, invalidation, and layout. The shared transition state
preserves existing reentrant-change suppression and layout coalescing.

## System visual settings renderer composition

Animated renderers subscribe only to their owning control's instance settings cascade. Accent transitions clear
their cached accent color; the control cascade repaints the tree. Disabling client-area animation completes an
active transition at progress 1 and unregisters it from the per-thread manager. Re-enabling does not restart a
completed transition; a later state change starts a new one.

`TextBoxBase` derives modern focus-border thickness and focus-band height from the system focus-border metrics,
text-scale factor, and device DPI. These metrics affect only modern chrome. The existing never-invert client
carve, small-control flat fallback, and classic-mode metrics remain unchanged.

## GroupBox content geometry

The Net11 `FlatStyle.Standard` GroupBox renders its caption above a borderless rectangular surface. Its
`DisplayRectangle` therefore starts lower and is shorter than the classic etched-frame rectangle. This is the
largest compatibility lever in the GroupBox change: the mode is opt-in, the paint and layout paths share the
same metrics, and the VisualStylesMode impact dispatcher remeasures AutoSize containers when the effective
renderer crosses the classic/modern boundary. The caption aligns to the control Padding, and the smaller bottom
content inset preserves separation when GroupBoxes are stacked. `FlatStyle.Flat` uses a rounded Windows-accent
outline; `FlatStyle.Popup` uses a Windows-accent header. `FlatStyle.System` remains native and does not use these
metrics.

## ComboBox adapter routing

Net11 routes `FlatStyle.Standard` ComboBox controls through the WinForms adapter path for the first time so the
field can share TextBoxBase's rounded chrome metrics and color scheme. `Flat` uses the same scheme with a
square-corner border; `Popup` keeps the rounded Standard geometry but uses the Windows accent color for its
border. All three styles add one logical pixel of framework inset on top of the now-designer-visible public
Padding. The adapter changes preferred height across the classic/modern boundary; `FlatStyle.System` remains
native and bypasses the adapter.

## Animation timing and thread ownership

The timer now uses an absolute `Stopwatch` schedule with a high-resolution waitable timer on supported Windows
versions and a coarse 30 Hz fallback. It no longer changes process-wide timer resolution, and residual spinning is
bounded to the sub-millisecond remainder. Registration/start/stop transitions are generation-owned, callback
dispatch is allocation-free in steady state, and stale generations cannot dispatch after replacement.

`AnimationManager` is now per UI thread. Each manager captures that thread's synchronization context, derives
animation progress from the timer tick timeline, and is disposed when its message loop exits. A renderer fault
quarantines that renderer without stopping unrelated animations on the same thread.

The remaining power risk is idle registration lifetime: after a UI thread starts its first animation, its manager
keeps one timer registration until `Application.ThreadExit`, even when no renderer is currently running. The pacer
therefore continues waking and dispatching an empty frame callback. A future optimization can make manager
registration lazy while preserving the generation and thread-ownership invariants established by the rework.

---

### Building (`docs/building.md`)

# Building Windows Forms

## Prerequisites

Follow the prerequisites listed at [Developer Guide](developer-guide.md).

## Building

### Building from command line (Preferred)

* Run `.\build.cmd` from the repository root. This builds the `Winforms.sln` using the default config (Debug|Any CPU).
* To specify a build configuration, add `-configuration` followed by the config such as `.\build -configuration Release`.

Note that this does **not** build using your machine-wide installed version of the dotnet sdk. It builds using the repo-local .NET SDK specified in the global.json in the repository root.

### Building from Visual Studio

1. .NET 6.0 and above branches need VisualStudio 2022 to build.
2. Run `.\restore.cmd` from the repository root.
3. Run `.\start-vs.cmd` from the repository root. This will prepend the repo-local .NET SDK to the path, and open `Winforms.sln` in Visual Studio.
4. You should now be able to build as you normally would.

### Building from Visual Studio Code

1. (Optional) Run `.\restore.cmd` from the repository root.
1. Run `.\start-code.cmd` from the repository root. This will prepend the repo-local .NET SDK to the path, and open `Winforms.sln` in Visual Studio Code.
1. You should now be able to build and test as you normally would from command line (or VS Code, if you have set it).

## Build outputs

* All build outputs are generated under the `artifacts` folder.
* Binaries are under `artifacts\bin`.
  * For example, `System.Windows.Forms.dll` can be found under `artifacts\bin\System.Windows.Forms\Debug\net6.0`.
* Logs are found under `artifacts\log`.
* Packages are found under `artifacts\packages`.

## Running apps from VS

1. Right click on the project you wish to run and select 'Set as startup project'.
2. <kbd>F5</kbd>.

## Running apps from command line

1. Build the solution: `.\build.cmd`
2. Navigate to the project you wish to run, e.g. to run AccessibilityTests test app:
    ```
    winforms> pushd .\src\System.Windows.Forms\tests\AccessibilityTests
    winforms\src\System.Windows.Forms\tests\AccessibilityTests> dotnet run
    ```
3. (Alternatively) Navigate to `.\artifacts\bin\AccessibilityTests\Debug\net6.0` and run the app manually.

## Troubleshooting build errors

* Most build errors are compile errors and can be dealt with accordingly.
* Other error may be from MSBuild tasks. You need to examine the build logs to investigate.
  * The logs are generated at `.\artifacts\log\Debug\Build.binlog`
  * The file format is an MSBuild Binary Log. Install the [MSBuild Structured Log Viewer][msbuild-log-viewer] to view them.
* Windows Forms uses Visual Studio MSBuild but for certain features we require the latest MSBuild from .NET Core/.NET SDK. If you are on an official version of [Visual Studio][VS-download] (i.e. not a Preview version), then you may need to enable previews for .NET Core/.NET SDKs in VS.
  * you can do this in VS under Tools->Options->Environment->Preview Features->Use previews of the .Net Core SDK (Requires restart)

## Creating a package

To create the Microsoft.Private.Winforms package, run `.\build -pack`

## Localization

If you need to add a new localization string or update an existing one, follow these steps:

- Modify `Resource\SR.resx` file adding or updating necessary strings in the project that contains the said strings. (It is often faster/easier to open SR.resx in an XML editor).
- Regenerate the localization files by rebuilding the solution/project from Visual Studio, or by executing `.\build.cmd` command. You can also build just the modified project by running  `dotnet build` from the project's root.

[comment]: <> (URI Links)

[corefx-windows-instructions]: https://github.com/dotnet/corefx/blob/master/Documentation/building/windows-instructions.md
[latest-core-build]: https://github.com/dotnet/core/blob/master/daily-builds.md
[msbuild-log-viewer]: https://msbuildlog.com/
[VS-download]: https://visualstudio.microsoft.com/downloads/

---

### Coding Style (`docs/coding-style.md`)

# Coding Style

Our coding style is informed by the [.NET Runtime coding style](https://github.com/dotnet/runtime/blob/master/docs/coding-guidelines/coding-style.md) and the latest ["Framework Design Guidelines"](https://www.informit.com/store/framework-design-guidelines-conventions-idioms-and-9780135896464) (currently third edition).

When we establish guidelines we consider how they impact the ability to comprehend the code. The easier the code is to understand, the easier it is to maintain. There are a few core guiding principles:

- Code should be clear and unambiguous.
- Code should be efficient and concise, using the minimum amount of code necessary to achieve the desired functionality without sacrificing readability or maintainability (and as such we lean into new C# language features).
- Guidelines are mutable where they inhibit our guiding principles.

There are a few key things we strive for to attain our clarity goals:

- Minimal code block nesting.
- Minimal scrolling for code blocks (almost no horizontal and limited vertical).
- Minimal code visibility (via access modifiers, type nesting, and local functions).
- All context captured in source (via code or comments).

Windows Forms dates back to the mid 1990s (originally [Windows Foundation Classes](https://web.archive.org/web/20050915003238/http://msdn.microsoft.com/library/vjcore98/html/vjconintroductiontowfcprogramming.asp)). It has seen over 25 years of language and coding evolution. We believe that updating the code to modern style makes the code easier to maintain and update in the longer term. While we do not update everything as the style guidelines evolve, we do make continual investments in cleaning the codebase as an engineering best practice.

A number of the following detailed guidelines are captured in our `.editorconfig` and as such you'll get the appropriate feedback in Visual Studio. We're iterating to enable more automated analyzers in the future.

### Spacing

Enabling viewing white space will make conforming to these rules easier. In Visual Studio: "View White Space (Ctrl+R, Ctrl+W)" or "Edit -> Advanced -> View White Space".

1. Use four spaces of indentation (never use tabs). XML blocks should get a single space indent (this includes XML comments).
1. Lines should not have trailing white space or more than one space between code elements (`=` can be aligned when there is notable value in doing so, such as bit flag values).
1. Avoid more than one empty line at any time. For example, do not have two blank lines between members of a type.
1. Closing brackets (`}`) on a line by themself should get a blank line after them unless followed by another line with just a closing bracket.

### Line Breaks

1. Lines should be less than 120 characters long to limit horizontal scrolling in development tools. If it improves clarity, they can be slightly over, but they never should be longer than 150. Statements should not be broken into multiple lines when they fall under the 120 character limit.
1. When using expression body definitions (`=>`) they should be on the same line if they fit, otherwise they should be broken after the `=>` and indented once on the next line.
1. When breaking arguments to a method, all arguments should be indented on individual lines at one indent in.
1. When breaking logical statements, all logical operators (`&&`, `||`, etc.) at a given parenthetical scope should be indented on individual lines at one indent in.
1. When breaking ternary operators (`?:`), they should be broken into two singly indented lines, starting with `?` and `:`.

<details>
<summary>Code Samples</summary>

More complicated line breaks:

``` C#
if (_trackColumn != previousColumnIndex
    && !(previousColumnIndex == -1 && hti._col == _trackColumn)
    && (dataGridViewColumnNext is null || _trackColumn != dataGridViewColumnNext.Index))
```

``` C#
if (Focused
    && !IsCurrentCellInEditMode
    && (EditMode == DataGridViewEditMode.EditOnEnter
        || (EditMode != DataGridViewEditMode.EditProgrammatically && CurrentCellInternal.EditType is null)))
```

Why `=>` isn't at the beginning of a line:

``` C#
// Further breaks logically align
internal bool SingleVerticalBorderAdded =>
    !_layout.RowHeadersVisible
    && (AdvancedCellBorderStyle.All == DataGridViewAdvancedCellBorderStyle.Single
        || CellBorderStyle == DataGridViewCellBorderStyle.SingleVertical);

// Same example, broken alignment
internal bool SingleVerticalBorderAdded
    => !_layout.RowHeadersVisible
    && (AdvancedCellBorderStyle.All == DataGridViewAdvancedCellBorderStyle.Single
        || CellBorderStyle == DataGridViewCellBorderStyle.SingleVertical);

```
</details>

### Code Blocks

1. Use [Allman style](http://en.wikipedia.org/wiki/Indent_style#Allman_style) braces, where each brace begins on a new line.
1. `if` statements must use code blocks with the exception of single line parameter validation at the beginning of a method.
1. `using` statements must use code blocks. [Simple using declarations](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/style-rules/ide0063) (which don't use code blocks) are preferred over using statements when possible. In the rare case that there are multiple `using` statements in a row, they should share a code block to reduce nesting.
1. `fixed` statements must use code blocks. When there are multiple `using` statements in a row, they should share a code block to reduce nesting.
1. `unsafe` should generally be applied to either whole methods or classes (when many methods are unsafe). When unsafe blocks are strictly necessary (say in an async or yield method) they must use code blocks.

### Comments

1. Code comments should be on their own line and precede the code they refer to. In condition blocks, comments should be inside the blocks (e.g., never before the `else`). Switch expression conditions have no blocks and should have the comment before the relevant condition line.
1. Avoid comments labeling the end of a block (never `if {} else {} // else`).
1. Methods and properties should have XML comments, not `\\` comments. `public` API comments should align with the documentation on https://learn.microsoft.com.
1. XML comment blocks that provide no further clarification are not required, with the exception of public API. (You don't have to document the return value if it is obvious, for example.)
1. Do not replicate comments from base methods or interfaces. Use `\\\ <inheritdoc cref='interfacemethod'\>` when docs aren't automatically inherited or you need to modify only a part of the documentation.
1. Avoid `\* *\` comments.

### General Naming

1. Avoid abbreviations and type names for variable or property names (e.g. `Point firstPoint` not `pt1`).
1. Names should describe their use, not their type (e.g. `Rectangle bounds` over `Rectangle rectangle`).
1. Use ```nameof(...)``` instead of ```"..."``` whenever possible and relevant.

### General Visibility

1. Always specify the visibility, even if it's the default (e.g. `private string _foo` not `string _foo`). Visibility should be the first modifier (e.g. `public abstract` not `abstract public`).

### Namespace Usings

1. Namespace `using`s should be specified at the top of the file, before `namespace` declarations, and should be sorted alphabetically, with the exception of `System.*` namespaces, which are to be placed on top of all others.
1. Global `using`s go should in a file called `globalusings.cs`.

### Namespaces

1. Use [file-scoped namespaces](https://learn.microsoft.com/dotnet/csharp/language-reference/keywords/namespace).
1. Files should be in sub folders that match the namespaces. Additional organizational folders can be created within namespace folders when necessary for clarity.

### Types

1. All types should be in their own files. This includes nested types.
1. All internal and private classes should be sealed when they are not derived from.
1. Use Pascal Casing to name all types. The only exception is for interop types, which should match the native casing.
1. Consider [primary constructors](https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/instance-constructors#primary-constructors) for "simple" structs and classes where there is only one constructor with no logic other than field assignment.

### Fields

1. Type constants, statics, and fields should be specified at the top within the type declaration.
1. Use [`_camelCase`](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/identifier-names#camel-case) for internal and private fields and use `readonly` where possible. Prefix instance fields with `_`, static fields with `s_` and thread static fields with `t_`.
1. Use [`PascalCasing`](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/identifier-names#pascal-case) to name all constants. The only exception is for interop code where the constant value should match the naming in the native code.
1. `public` or `internal` fields should not be used (use properties).
1. `protected` properties should be preferred over fields.

### Properties

1. Use [`PascalCasing`](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/identifier-names#pascal-case) to name all properties.
1. Use [auto-implemented properties](https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/auto-implemented-properties) when possible.
1. Prefer methods over properties for expensive code or code with significant side effects.
1. Use [expression body definitions](https://learn.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members) (`=>`) for single line getters and setters.

### Methods

1. Use [`PascalCasing`](https://learn.microsoft.com/dotnet/csharp/fundamentals/coding-style/identifier-names#pascal-case) to name all methods.
1. Constructors should precede all other methods and properties.
1. Use [expression body definitions](https://learn.microsoft.com/dotnet/csharp/programming-guide/statements-expressions-operators/expression-bodied-members) (`=>`) for single line methods.
1. Avoid methods with a single calling method. Use [local functions](https://learn.microsoft.com/dotnet/csharp/programming-guide/classes-and-structs/local-functions). Don't use a method at all in these cases if the logic is simple and not replicated.
1. Use static methods when instance fields are not accessed, and consider passing fields in to make methods static to clarify what a method modifies.
1. Prefer methods where top level blocks fit in a single editor screen (around 25 lines of code). Local functions can be used to break the logic into digestible chunks.
1. Keep block nesting to a minimum (preferably no more than 3 indents, 5 at the maximum). Use early outs and inverted conditionals to help manage nesting.
1. Exit (return) early from methods to reduce nesting.

### Variables

1. We never use `var` for [built-in types](https://learn.microsoft.com/dotnet/csharp/language-reference/builtin-types/built-in-types), e.g. don't use `var count = 2`, instead use `int count = 2`. `var` should only be used when the type name inhibits code readability.
1. [Target-typed `new()`](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/new-operator#target-typed-new) should be used to remove redundancy, not var. For example: `FileStream stream = new(...);`, not `var stream = new FileStream(...);`. Using target-typed `new()` for succinctness is allowed where the type is reasonably obvious, e.g. `Point[] points = [new(1, 2), new(5, 6)];`
1. [Collection expressions](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/collection-expressions) are preferred, e.g. `Point[] points = [new(1, 2)];` over `Point[] points = new Point[] { new(1, 2) }`;

### General

1. Use language keywords instead of BCL types (e.g. `int, string, float` instead of `Int32, String, Single`, etc.) for both type references as well as method calls (e.g. `int.Parse` instead of `Int32.Parse`).
1. Always use [interpolated strings](https://learn.microsoft.com/dotnet/csharp/language-reference/tokens/interpolated) when composing / formatting strings.
1. Use [raw string literals](https://learn.microsoft.com/dotnet/csharp/language-reference/tokens/raw-string) for multi-line strings.

### Conditions

1. Prefer [ternary operators](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/conditional-operator) (`?:`) over `if .. else` when there is only one line in each clause.
1. Prefer [pattern matching](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/patterns) in conditions.
1. Prefer [null-coalescing](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/null-coalescing-operator) operators (`??` and `??=`).
1. Prefer [switch expressions](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/switch-expression) over switch statements where possible.

### Nullability

1. Prefer [pattern matching](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/patterns) to check variable type and null state (e.g. `if (parameter is Form form)`, `if (manager.GetService<IContainer>() is { } container)`, etc.).
1. Using the postfix `!` [null-forgiving operator](https://learn.microsoft.com/dotnet/csharp/language-reference/operators/null-forgiving) to override null analysis must always get a descriptive comment. Prefer to refactor code to avoid this where possible. If we do not control the code in question prefer to throw `ArgumentException` when an associated argument is known or `InvalidOperationException` otherwise. Do not let code fall into `NullReferenceException`.

### Visual Basic

_Forthcoming_

---

### Dataobject Serialization (`docs/dataobject-serialization.md`)

# WinForms Clipboard/DataObject updates for .NET 10

The **.NET 10** cycle introduces major updates to the clipboard and drag‑and‑drop stack in **System.Windows.Forms**. These changes were driven by the **removal of `BinaryFormatter`** from the runtime, which previously handled serialization of custom types for OLE data transfer. The new APIs provide explicit type‑safe methods and use **JSON** instead of binary serialization, while still allowing an opt‑in fallback to `BinaryFormatter` for legacy applications.

## Background

`BinaryFormatter` was used when a custom type was placed on the clipboard for a user defined data format or in a drag‑and‑drop operation. The `BinaryFormatter` is insecure and has been removed from the base runtime. WinForms has introduced new, safer APIs and deprecated older APIs. WinForms also now makes you explicitly enable clipboard and drag drop scenarios for `BinaryFormatter` so you don't get unexpected usage if you need to enable it for other scenarios.

### Best Practices

- Avoid enabling the `BinaryFormatter` for clipboard and drag and drop scenarios if at all possible.
- Use the recommended built-in types (listed below) and `SetData` APIs.
- For custom types, use the new `SetDataAsJson<T>()` APIs or serialize manually as `string` or `byte[]` data.
- **Always** use `TryGetData<T>()` to get data (not `GetData()`).
- Read legacy data using the `NrbfDecoder`.

### Recommended built‑in types

Without `BinaryFormatter`, WinForms can still transfer certain intrinsic types using a built‑in manual serializer in the `BinaryFormatter` data format, **NRBF** ([.NET Remoting Binary Format](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5)). Supported types include:

- **Primitive types**: `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long`, `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string`, `TimeSpan` and `DateTime`.
- **Arrays or `List<T>`** of the above primitive types. For maximum resilience, avoid `string[]` and `List<string>` as they can contain nulls.
- **System.Drawing types**: `Bitmap`, `PointF`, `RectangleF`, `Point`, `Rectangle`, `SizeF`, `Size`, and `Color`.

When data is one of these types, WinForms transfers it without the user needing to implement any special logic. For custom types with [`DataFormats`](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataformats) that aren't predefined, you should use JSON or your own serialization using raw string or byte data.

### Safety

As with any serialization, you should take great care when processing the data you receive. If you follow all of the "Best Practices" above Windows Forms will guarantee that only the types you've requested will be created. We cannot guarantee what the data looks like within the types (other than that we will only create specified types) and we cannot constrain the size of the deserialized data.

For example, if you deserialize an integer, it can contain any value. It could be negative, it could be zero. Your code should be able to handle **any** possible value- it may **not** be what you expect. It could be set to a value unexpected by your code, either accidentally or deliberately.

## New APIs in .NET 10

### `TryGetData<T>` – constrained deserialization of data

Several overloads of `TryGetData<T>` exist on **`Clipboard`**, **`DataObject`**, **`ITypedDataObject`**, **`DataObjectExtensions`** and the VB **`ClipboardProxy`**. These methods:

- Attempt to retrieve data in a given format and deserialize it to the requested type `T`.
- Return a boolean indicating success instead of throwing.
- When enabling `BinaryFormatter`, requires a **`resolver`** callback to restrict deserialization to known types.

Example using the **simplest overload** (no resolver).  This will **never** fall back to `BinaryFormatter`; it only succeeds if the data was serialized with `SetDataAsJson<T>`, one of the built‑in safe NRBF types (see above), _or_ if the data was set in-process without the `copy` flag (not the default):

```csharp
// Reading a Person previously stored with SetDataAsJson
if (Clipboard.TryGetData("MyApp.Person", out Person? person))
{
    Console.WriteLine($"Person: {person.Name} is {person.Age}");
}
else
{
    Console.WriteLine("No person data on clipboard or type mismatch");
}
```

A resolver overload can be used when you need to support legacy binary formats and have fully enabled the `BinaryFormatter`. See the "Enabling Full BinaryFormatter Support" below for details.

### `SetDataAsJson<T>` – write custom types without BinaryFormatter

`SetDataAsJson<T>` is a new overload on the **`Clipboard`**, **`DataObject`** and **VB `ClipboardProxy`** classes. It serializes *simple* `T` types to JSON using **`System.Text.Json`**. For example:

```csharp
public record Person(string Name, int Age);

// Serialize to JSON and put on the clipboard
Person person = new("Alisha", 34);
Clipboard.SetDataAsJson(person);
```
Internally `DataObject.SetDataAsJson<T>` writes the JSON to the underlying OLE data stream in the NRBF format in a way that it can be manually extracted without using the `BinaryFormatter`.


### `ITypedDataObject` interface – enabling typed data retrieval

Custom data objects used with drag & drop should implement the **`ITypedDataObject`** interface.  This interface declares the typed `TryGetData<T>` overloads. Implementing it signals to WinForms that your data object is capable of deserializing data into specific types; if it is not implemented, calls to the typed APIs throw `NotSupportedException`. The `DataObject` class already implements `ITypedDataObject`.

### Summary of new API signatures

| API (class) | Description | Remarks |
|---|---|---|
| `DataObject.SetDataAsJson<T>(string format, T data)` and `DataObject.SetDataAsJson<T>(T data)` | Serialize an object to JSON and store it under the specified format (or the type’s full name). | Uses `System.Text.Json`. |
| `Clipboard.SetDataAsJson<T>(string format, T data)` | Clears the clipboard and stores JSON data in a new `DataObject`. | Equivalent VB method: `ClipboardProxy.SetDataAsJson(Of T)`. |
| `DataObject.TryGetData<T>(string format, Func<TypeName,Type> resolver, bool autoConvert, out T data)` | Attempts to read data and deserialize it; `resolver` controls allowed types when falling back to binary deserialization; `autoConvert` indicates whether OLE conversion should be attempted. | Returns `true` when successful; does not throw. |
| `DataObject.TryGetData<T>(string format, bool autoConvert, out T data)` | Same as above without a resolver; does not fall back to binary serialization. | |
| `DataObject.TryGetData<T>(string format, out T data)` | Uses default `autoConvert=true`; no resolver. | |
| `DataObject.TryGetData<T>(out T data)` | Infers the format from the full name of `T`. | |
| `Clipboard.TryGetData<T>` overloads | Static methods that obtain the current clipboard data and delegate to the corresponding `DataObject` overloads. | Overloads include versions with and without resolver and autoConvert. |
| `ITypedDataObject` | Interface declaring typed `TryGetData` methods. | Implement on custom data objects used for drag & drop. |
| `DataObjectExtensions.TryGetData<T>` | Extension methods on `IDataObject` that call through to `ITypedDataObject`; throws when the underlying object does not implement `ITypedDataObject`. | Enables typed retrieval without explicitly casting. |
| `ClipboardProxy` (VB) new methods | Exposes `SetDataAsJson(Of T)`, `TryGetData(Of T)` and `TryGetData(Of T)(resolver)` in Visual Basic’s `My.Computer.Clipboard`. | VB apps can use typed clipboard APIs without referencing the `System.Windows.Forms` namespace directly. |

## Enabling full `BinaryFormatter` support (not recommended)

Although the default behavior removes `BinaryFormatter`, a full fallback is still available **for legacy applications**.  To enable it you must do **all** of the following:

1. **Reference the `System.Runtime.Serialization.Formatters` package**:  Add a PackageReference to your project file:

   ```xml
   <ItemGroup>
     <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0"/>
   </ItemGroup>
   ```

   This compatibility package is unsupported and dangerous; use it only as a last resort.

2. **Set the runtime switch to enable unsafe serialization**:  In your project file, set the property `EnableUnsafeBinaryFormatterSerialization` to `true`.  Without this switch, calls to binary serialization throw.

    ```xml
    <PropertyGroup>
      <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization>
    </PropertyGroup>
    ```

3. **Set the WinForms‑specific switch**: WinForms adds an app‑context switch `Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization`. Without this switch, WinForms will not fall back to `BinaryFormatter` even if the general serialization switch is enabled. Set this flag in your `runtimeconfig.json` file:

    ```json
    {
        "configProperties": {
            "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true
        }
    }
    ```

4. **Use the resolver overload to control which types are allowed**: Even with `BinaryFormatter` enabled, you must specify a resolver when calling `TryGetData<T>` so you only deserialize known types. The existing, deprecated, `GetData` APIs will continue to work, but provide no additional constraints. A sample type resolver follows:

    ```csharp
    static Type MyExactMatchResolver(TypeName typeName)
    {
        (Type type, TypeName typeName)[] allowedTypes =
        [
            (typeof(MyClass1), TypeName.Parse(typeof(MyClass1).AssemblyQualifiedName)),
            (typeof(MyClass2), TypeName.Parse(typeof(MyClass2).AssemblyQualifiedName))
        ];

        foreach (var (type, name) in allowedTypes)
        {
            // Check the type name
            if (name.FullName != typeName.FullName)
            {
                continue;
            }

            // You should also consider checking the `.AssemblyName` here as well.
            return type;
        }

        // Always throw to prevent the BinaryFormatter from implicitly loading assemblies.    
        throw new NotSupportedException($"Can't resolve {typeName.AssemblyQualifiedName}");
    }
    ```

Only after completing **all of the first three steps** above will WinForms behave as in older versions and automatically use `BinaryFormatter` for unknown types.

## Compatibility

### Predefined formats and primitive types

Types already defined in [`DataFormats`](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataformats) and the primitive types described in the beginning of the document just work. This ensures compatibility with existing applications and common data exchange scenarios. 

### Reading JSON down‑level

Even though `SetDataAsJson<T>` is only available in .NET 10, you can round‑trip JSON data across processes and frameworks by storing the JSON yourself (as UTF-8 `byte[]` or `string`) if you're able to change all of the consumer code.

### Reading legacy NRBF / binary data in .NET 10

While .NET 10 removes `BinaryFormatter` by default, WinForms still includes safe support for the types mentioned above and provides mechanisms to read legacy binary payloads **without referencing `BinaryFormatter`**. The simplest way to read NRBF data is to use the `NrbfDecoder` `SerializationRecord`:

```csharp
if (dataObject.TryGetData("LegacyFormat", out SerializationRecord? record))
{
    // Process the serialization record
}
```

You can also retrieve raw data as a `MemoryStream` for custom processing.

## Links

- [BinaryFormatter migration guide](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide/)
- [Windows Forms migration guide for BinaryFormatter](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide/winforms-applications)
- [Windows Forms and Windows Presentation Foundation BinaryFormatter OLE guidance](https://learn.microsoft.com/dotnet/standard/serialization/binaryformatter-migration-guide)
- [System.Text.Json documentation](https://learn.microsoft.com/dotnet/standard/serialization/system-text-json/overview)
- [.NET Core runtime configuration settings](https://learn.microsoft.com/dotnet/core/runtime-config/)
- [Windows Forms Clipboard class](https://learn.microsoft.com/dotnet/api/system.windows.forms.clipboard)
- [DataObject class](https://learn.microsoft.com/dotnet/api/system.windows.forms.dataobject)
- [NRBF format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5)

---

### Debugging (`docs/debugging.md`)

# Debugging

There are two recommended ways to debug Windows Forms binaries. Both require that you first [build from source](building.md).

Once you are ready to debug your changes on an existing Windows Forms application, please follow one of the two following recommended techniques for relating your changes back to your project. You should then be able to set breakpoints and debug as expected.

If you do not want to modify your local SDK, you may with to perform technique 2. However if you do not want to add an additional reference to your project, technique 1 may be better for you.

## 1. Copy your changes into the SDK

Copy the resulting assembly(-ies) from your local build.

- They are located at `[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms\Debug\net7.0`
- And need to be copied to the system dotnet folder `[Drive]:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\[Version]`

:warning: If you have updated any public APIs, you'll need to overwrite the ref assemblies too (since that's what VS uses when resolving types):
- The ref assemblies compile to `[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms\Debug\net7.0\ref`
- These need to be copied to `[Drive]:\Program Files\dotnet\packs\Microsoft.WindowsDesktop.App.Ref\[Version]`

where:
- **[Drive]** is your OS drive (for example, C:),
- **[Path-to-repo]** is the additional path to our repository from the base drive, and
- **[Version]** is your WindowsDesktop version directory (for example, 5.0.0-rc.2.20464.5).



**NOTE** Make sure to make a backup copy of assemblies you replace, you will modify your SDK. Alternatively you can repair the install or reinstall.

## 2. Point your project to your experimental binary(-ies)

Add references to the binary(-ies) to your project ported to .NET. For example, for System.Windows.Forms, you should add the following reference:

```xml
<ItemGroup>
    <Reference Include="[Drive]:[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms\Debug\net9.0\System.Drawing.Common.dll" />
    <Reference Include="[Drive]:[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms\Debug\net9.0\System.Private.Windows.Core.dll" />
    <Reference Include="[Drive]:[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms\Debug\net9.0\System.Windows.Forms.dll" />
    <Reference Include="[Drive]:[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms.Primitives\Debug\net9.0\System.Windows.Forms.Primitives.dll" />
    
    <Reference Include="[Drive]:[Path-to-repo]\winforms\artifacts\bin\System.Windows.Forms.Design\Debug\net9.0\System.Windows.Forms.Design.dll" />
</ItemGroup>
```

where:
- **[Drive]** is the drive you have our repository in, and
- **[Path-to-repo]** is the additional path to our repository from the base drive.

---

### Designer Accessibility (`docs/designer-accessibility.md`)

# Working around accessibility issues in the Windows Forms Out of Process Designer

The introduction of Windows Forms (WinForms) to .NET Core 3.1 and beyond is enabling developers to migrate their  applications from .NET Framework to the more modern .NET versions. In order to support the designing of these applications within Visual Studio the team was required to create an entirely new Out of Process (OOP) Designer, which is currently still in a preview state. For more information on the technical reasons for this change, and the current status of the designer, see [our recent blog post](https://devblogs.microsoft.com/dotnet/state-of-the-windows-forms-designer-for-net-applications/).

There are several features that still need to be implemented in the OOP designer, foremost of which is supporting the use of Assistive Technologies such as NVDA, Narrator, and Jaws while using the OOP designer. As much as the team wanted to fully support accessibility right out of the gate with this new designer, technical reasons prevented getting an early start on this feature, and resulted in unfortunate user experiences and deadlocks under assistive technology tooling in certain scenarios.

While the team is rebuilding the experience under the new model, it is straightforward to work around the current accessibility issues by using the classic .NET Framework in-process designer and building output assemblies in both .NET and .NET Framework 4.7.2 (or 4.8). In order to multi-target and use the .NET Framework designer use the following steps:

1.  Create your .NET WinForms 3.1 (C\# only), 5 or 6 app (both VB and C\#).

2.  Before the designer by opening a Form or a UserControl, edit the *.csproj*
    file.

3.  In that file you will find the following entry, telling the compiler what
    .NET version to build against:

```<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>
</Project>
```
4.  Change the `<TargetFramework>net6.0-windows</TargetFramework>` to the following: `<TargetFrameworks>net472;net6.0-windows</TargetFrameworks>`

**Note:** it is important to use **net472** (or net48 if you want to target against .NET Framework 4.8) **first** in the  list of targeted frameworks. This tells Visual Studio to load the in-process .NET Framework rather than the .NET OOP WinForms designer.

Once you’ve completed the above steps, you can build your application and interact with the forms directly as you have always done. When you build binaries, they will be built targeting both .NET 6 and .NET Framework 4.7.2. 

:warning: There are limitations around only using the features and types available in both .NET Framework 4.7.2 and .NET 6. If you want to use .NET 6 features, you will need to use C\# preprocessor directives.

We will be communicating out as soon as full accessibility support is available in the WinForms .NET OOP designer so that you can remove the need to multi-target. In the meantime, this workaround should allow you to build your .NET Windows Forms  applications with the respective accessibility features supported at design time.

Happy Coding!

---

### Developer Guide (`docs/developer-guide.md`)

# Developer Guide

The following document describes the setup and workflow that is recommended for working on the Windows Forms project. It assumes that you have read the [Contributing Guide](../CONTRIBUTING.md).

The [Issue Guide](issue-guide.md) describes our approach to using GitHub issues.

## Machine Setup

Windows Forms development requires the following workloads and components be selected when installing Visual Studio 2022 (17.0.0):

* Required Workloads:
  * .NET Desktop Development
  * Desktop development with C++
* [Required Individual Components][required-individual-components]:
  * Windows 10 SDK
  * C++ CMake tools for Windows
* Required Windows Features
  * 'Media Features' including 'Windows Media Player Legacy (App)' (Windows 11) or 'Windows Media Player' (Windows 10) 
* Useful Visual Studio extensions:  
  * [Editor guidelines](https://marketplace.dev.azure.com/items?itemName=PaulHarrington.EditorGuidelines), see https://github.com/dotnet/winforms/pull/4836 for more information
  * [VS Color Output](https://marketplace.dev.azure.com/items?itemName=MikeWard-AnnArbor.VSColorOutput64)
  * [Productivity Power Tools](https://marketplace.dev.azure.com/items?itemName=VisualStudioPlatformTeam.ProductivityPowerPack2022)
 
Optional: To get the latest C# features in Visual Studio or to experiment with the latest runtime when not using the `start-vs.cmd`, install the [latest SDK build](https://github.com/dotnet/dotnet/blob/main/docs/builds-table.md).

## Workflow

We use the following workflow for building as well as testing features and fixes.

You first need to [fork][fork] then [clone][clone] this Windows Forms repository. This is a one-time task.

1. [Build](building.md) the repository.
2. [Debug](debugging.md) the change, as needed.
3. [Test](testing.md) the change, to validate quality.

## More Information

* [Shared WinForms/WPF Infrastructure](shared-wpf-infrastructure.md) - Important guidance for contributors working on clipboard/OLE code
* [How to write good docs for .NET](https://review.docs.microsoft.com/help/contribute-ref/how-to-write-net-docs?branch=main)
* [.NET Docs and Guidelines][net-runtime-instructions]
* ["help wanted" issues][help wanted]

[comment]: <> (URI Links)

[net-runtime-instructions]: https://github.com/dotnet/runtime/tree/master/docs
[fork]: https://guides.github.com/activities/forking/
[clone]: https://www.git-scm.com/docs/git-clone
[help wanted]: https://github.com/dotnet/winforms/issues?q=is%3Aopen+is%3Aissue+label%3A"help%20wanted"
[chocolatey]: https://chocolatey.org/
[cmake-download]: https://cmake.org/download/
[required-individual-components]: ../WinForms.vsconfig

---

### Issue Guide (`docs/issue-guide.md`)

# Issue Guide

This page outlines how WinForms team thinks about and handles issues.
For us, issues on GitHub represent actionable work that should be done at some future point.
It may be as simple as a small product or test bug or as large as the work tracking the design of a new feature.

We will keep issues open even if the WinForms team internally has no plans to address them in an upcoming release, as long as we believe they are in line with our direction.

# How to file issues

You can help us streamline our response time to your feedback and ideas by filing high-quality reports.

### Known Issues

If you encounter an issue using the latest .NET 5.0 SDK, please:

1. Explore [this repositories issues][winforms-issues], and then
1. [Open a new issue][new-issue] if there is none.

### Bug reports

In general, try to be specific. Get straight to the main point. Leave additional details, options, and alternatives to the end (hint: separate them visually). Don't write long bug reports, unless you have to.

* Include a minimal reproduction (repro) in your bug if at all possible (chop off dependencies, remove as much code as possible). If it is not possible, say why.<br />
  :warning: Note: Yes, it may take some time to minimize a repro from your larger app - but that is exactly what we would do in most cases anyway. Issues with clear, concise reproduction guidelines are easier for us to investigate; such issues will have higher chance of being addressed quickly.
* Include call-stacks, symptom descriptions, and differences between actual and expected behaviors.

### Feature and API suggestions

Assume that the reader has minimal knowledge and experience with writing apps/libraries that would benefit from the feature, so try and write to that audience. Provide clear description of your suggestion, and explain scenarios in which it would be helpful and why (motivation).

Prepare code examples that showcase the need and general usefulness of the proposal. Specifically:
* Code that shows the surface area of the API.
* Code that shows real world scenarios, and how they would otherwise be handled.
* Details showing the usage/consumption of the proposed new package, and alternatives (e.g. not having this be a separate package).

:warning: All new API or changes to public API must undergo an API review process. Learn more what the [API review process][api-review-process] entails.

Here are few example of a good API proposal: 
* https://github.com/dotnet/runtime/issues/15725
* https://github.com/dotnet/runtime/issues/15725


## Assignee

We assign each issue to assignee, when the assignee is ready to pick up the work and start working on it.
If the issue is not assigned to anyone and you want to pick it up, please say so - we will assign the issue to you.
If the issue is already assigned to someone, please coordinate with the assignee before you start working on it.

## Up-votes on issues

Up-votes on first post of each issue are useful hint for our prioritization.
We can [sort issues by number of up-votes][up-votes], and we will review the top list on a regular basis.

## Triage rules

Guidance for triage of issues for Windows Forms team members:

1. Issue has no **Assignee**, unless someone is working on the issue at the moment.
1. Use **help wanted** as much as possible, ideally with a quick note about next steps / complexity of the issue.
1. Set milestone to **Future**, unless you can 95%-commit you can fund the issue in specific milestone.
1. Each issue has exactly one "*issue type*" label (**bug**, **enhancement**, **api-suggestion**, **test-bug**, **test-enhancement**, **question**, **documentation**, etc.).
1. Don't be afraid to say no, or close issues — just explain why and be polite.
1. Don't be afraid to be wrong - just be flexible when new information appears.

Feel free to use other labels if it helps your triage efforts (for example, **needs-more-info**, **design-discussion**, **tenet-compatibility**, etc.).

### Motivation for triage rules

1. Issue has no **Assignee**, unless someone is working on the issue at the moment.
    * Motivation: Observation is that contributors are less likely to grab assigned issues, no matter what the repository rules say.

1. Use **help wanted** as much as possible, ideally with a quick note about next steps / complexity of the issue.<br />
    NB: Per [https://up-for-grabs.net][up-for-grabs-net], such issues should be no longer than few nights' worth of work. They should be actionable (that is, no mysterious CI failures that can't be tested in the open).

1. Set milestone to **Future**, unless you can 95%-commit you can fund the issue in specific milestone.
    * Motivation: Helps communicate desire/timeline to community. Can spark further priority/impact discussion.

1. Each issue has exactly one "*issue type*" label (**bug**, **enhancement**, **api-suggestion**, **test-bug**, **test-enhancement**, **question**, **documentation**, etc.).
    * Don't be afraid to be wrong when deciding 'bug' vs. 'test-bug' (flip a coin if you must). The most useful values for tracking are 'api-&#42;' vs. 'enhancement', 'question', and 'documentation'.


# Pull-Request (PR) Guide

Each PR has to have reviewer approval from at least one Windows Forms team member who is not author of the change, before it can be merged.


1. Please don't set any labels on PRs. 
    * exceptions:
      * **NO-MERGE** may be supplied by the WinForms team in order to indicate that the PR should be halted; a reason should be given in the comments
      * **waiting-on-testing** may be supplied by the WinForms team to inform the PR author(s) that their PR is being delayed due to internal, manual testing; this action does not require action by the author(s).
    * Motivation: All the important info (*issue type* label, API approval label, etc.) is already captured on the associated issue.

1. Push PRs forward, don't let them go stale (response every 5+ days, ideally no PRs older than 2 weeks).

1. Close stuck or long-term blocked PRs (for example, due to missing API approval, etc.) and reopen them once they are unstuck.
    * **Motivation: Keep only active PRs. WIP (work-in-progress) PRs should be rare and should not become stale (2+ weeks old). If a PR is stale and there is not immediate path forward, consider closing the PR until it is unblocked/unstuck.

1. Link PR to related issue via [auto-closing][auto-closing] (add "Fixes #12345" into your PR description).

[comment]: <> (URI Links)


[winforms-issues]: https://github.com/dotnet/winforms/issues
[new-issue]: https://github.com/dotnet/winforms/issues/new/choose
[api-review-process]: https://github.com/dotnet/runtime/blob/master/docs/project/api-review-process.md
[labels]: https://github.com/dotnet/winforms/labels
[api-suggestion]: https://github.com/dotnet/winforms/labels/api-suggestion
[API Review process]: https://github.com/dotnet/corefx/blob/master/Documentation/project-docs/api-review-process.md
[bug]: https://github.com/dotnet/winforms/labels/bug
[enhancement]: https://github.com/dotnet/winforms/labels/enhancement
[test-bug]: https://github.com/dotnet/winforms/labels/test-bug
[test-enhancement]: https://github.com/dotnet/winforms/labels/test-enhancement
[question]: https://github.com/dotnet/winforms/labels/question
[documentation]: https://github.com/dotnet/winforms/labels/documentation
[label-description]: https://github.com/dotnet/winforms/labels
[help wanted]: https://github.com/dotnet/winforms/labels/help%20wanted
[needs-more-info]: https://github.com/dotnet/winforms/labels/needs-more-info
[tenet-compatibility]: https://github.com/dotnet/winforms/labels/tenet-compatibility
[milestones]: https://github.com/dotnet/winforms/milestones
[up-votes]: #upvotes-on-issues
[sort issues by number of up-votes]: https://github.com/dotnet/winforms/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc
[up-for-grabs-net]: https://up-for-grabs.net
[auto-closing]: https://help.github.com/articles/closing-issues-via-commit-messages/

---

### List Of Diagnostics (`docs/list-of-diagnostics.md`)

# List of Diagnostics Produced by Windows Forms .NET

We have three kinds of diagnostic messages: obsoletions, code analyzer diagnostics, and experimental feature compiler errors.

## Obsoletions

Per the [Better Obsoletion](https://github.com/dotnet/designs/blob/main/accepted/2020/better-obsoletion/better-obsoletion.md) design and similar to the [runtime diagnostics](https://github.com/dotnet/runtime/blob/main/docs/project/list-of-diagnostics.md), we now have a strategy for marking existing APIs as `[Obsolete]`. This takes advantage of the new diagnostic ID and URL template mechanisms introduced to `ObsoleteAttribute` in .NET 5.

The diagnostic ID values reserved for obsoletions are `WFDEV001` through `WFDEV999`. When obsoleting an API, claim the next three-digit identifier in the `WFDEV###` sequence and add it to the list below. The URL template for all obsoletions is `https://aka.ms/winforms-warnings/{0}`. The `{0}` placeholder is replaced by the compiler with the `WFDEV###` identifier.

### Acceptance Criteria for Adding an Obsoletion

1. **Add the obsoletion to the table below**, claiming the next diagnostic ID.
    - Ensure the description is meaningful within the context of this table and without requiring the context of the calling code.
2. **Add new constants to `src\Common\src\Obsoletions.cs`**, following the existing conventions:
    - A `...Message` const using the same description added to the table below.
    - A `...DiagnosticId` const for the `WFDEV###` ID.
3. **If adding the `<Obsolete>` attribute to the Microsoft.VisualBasic.Forms assembly**, edit the `src\Microsoft.VisualBasic.Forms\src\Obsoletions.vb` file.
4. **Annotate `src` files by referring to the constants defined in `Obsoletions.cs`**:
    - Specify the `UrlFormat = Obsoletions.SharedUrlFormat`.
    - Example:
        ```C#
        [Obsolete(
            Obsoletions.DomainUpDownAccessibleObjectMessage,
            DiagnosticId = Obsoletions.DomainUpDownAccessibleObjectDiagnosticId,
            UrlFormat = Obsoletions.SharedUrlFormat)]
        ```
    - If the `Obsoletions` type is not available in the C# project, link it into the project:
        ```xml
        <Compile Include="..\..\Common\src\Obsoletions.cs" Link="Common\Obsoletions.cs" />
        ```
5. **Create the new `aka.ms` link**
    - Point it to the repo's `.md` file in the `docs` folder that describes your analyzer until the `learn` site docs are completed in the [redirection manager](https://akalinkmanager.trafficmanager.net/am/redirection/home)
    - Set the security group to the team alias
6. **Apply the `:book: documentation: breaking` label** to the PR that introduces the obsoletion.
7. **Document the breaking change**
    - In the breaking-change issue filed in [dotnet/docs](https://github.com/dotnet/docs), specifically mention that this breaking change is an obsoletion with a `WFDEV` diagnostic ID.
    - Create another issue to add documentation to the `learn` website in the [dotnet/docs-desktop repo](https://github.com/dotnet/docs-desktop/issues/new?template=diagnostic-compiler.yml)
    - The documentation team will produce a PR that adds the warning or error documentation to the [`learn` site](https://learn.microsoft.com/dotnet/desktop/winforms/wfdev-diagnostics/wfdev003) page, and we will review it.
    - Once the docs PR is published, get the newly created link to the doc and associate it with the corresponding `aka.ms` name in the [redirection manager](https://akalinkmanager.trafficmanager.net/am/redirection/home?options=host:aka.ms)
    - Connect with `@gewarren`, `@adegeo`, or `@merriemcgaw` with any questions.

### Obsoletion Diagnostics (`WFDEV001` - `WFDEV999`)

| Diagnostic ID | Introduced | Description |
| :-------------| :--------- | :---------- |
| `WFDEV001`    | NET7.0     | (Internal) Casting to/from IntPtr is unsafe, use `WParamInternal`. |
| `WFDEV001`    | NET7.0     | (Internal) Casting to/from IntPtr is unsafe, use `LParamInternal`. |
| `WFDEV001`    | NET7.0     | (Internal) Casting to/from IntPtr is unsafe, use `ResultInternal`. |
| `WFDEV002`    | NET8.0     | `DomainUpDown.DomainUpDownAccessibleObject` is no longer used to provide accessible support for `DomainUpDown` controls. Use `ControlAccessibleObject` instead. |
| `WFDEV003`    | NET8.0     | `DomainUpDown.DomainItemAccessibleObject` is no longer used to provide accessible support for `DomainUpDown` items. |
| `WFDEV004`    | NET10.0    | `Form.OnClosing`, `Form.OnClosed` and the corresponding events are obsolete. Use `Form.OnFormClosing`, `Form.OnFormClosed`, `Form.FormClosing` and `Form.FormClosed` instead. |
| `WFDEV005`    | NET10.0    | `Clipboard.GetData(string)` method is obsolete. Use `Clipboard.TryGetData<T>` methods instead. |
| `WFDEV005`    | NET10.0    | `DataObject.GetData` methods are obsolete. Use the corresponding `DataObject.TryGetData<T>` instead. |
| `WFDEV005`    | NET10.0    | `ClipboardProxy.GetData(As String)` method is obsolete. Use `ClipboardProxy.TryGetData(Of T)(As String, As T)` instead. |
| `WFDEV006`    | NET10.0    | `ContextMenu` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `ContextMenuStrip` instead. |
| `WFDEV006`    | NET10.0    | `DataGrid` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `DataGridView` instead. |
| `WFDEV006`    | NET10.0    | `MainMenu` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `MenuStrip` instead. |
| `WFDEV006`    | NET10.0    | `Menu` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `ToolStripDropDown` and `ToolStripDropDownMenu` instead. |
| `WFDEV006`    | NET10.0    | `StatusBar` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `StatusStrip` instead. |
| `WFDEV006`    | NET10.0    | `ToolBar` is provided for binary compatibility with .NET Framework and is not intended to be used directly from your code. Use `ToolStrip` instead. |

## Analyzer Diagnostics

### When adding a new analyzer

1. **Add the diagnostic ID to the table below**.
    - The current IDs for C#, VB, and language-agnostic analyzers are defined in [DiagnosticIDs.cs](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs). A complete list of IDs, including those that were shipped and then replaced, is available in the `AnalyzerReleases.Shipped.md` and `AnalyzerReleases.Unshipped.md` files.
    - Starting in NET9.0, we are using the `WFO####` format for code analyzer diagnostic IDs.
2. **Create a new Descriptor** in the analyzer code by calling [DiagnosticDescriptorHelper.Create](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Analyzers.CSharp/src/System/Windows/Forms/CSharp/Analyzers/Diagnostics/DiagnosticDescriptorHelper.cs#L10)
    - This method will generate the help link in the https://aka.ms/winforms-warnings/WFO#### format.
3. **Follow the [documentation steps 5-7 described for obsoletions](#create-the-new-aka.ms-link)** above.

| Diagnostic ID | Introduced | Removed | Description |
| :-------------| :--------- | :------ | :---------- |
| `WFAC001`     | NET6.0     | NET9.0  | Unsupported project type. |
| `WFAC002`     | NET6.0     | NET9.0  | Unsupported property value. |
| `WFAC010`     | NET6.0     | NET9.0  | Unsupported high DPI configuration. |
| `WFO0001`     | NET9.0     |         | Only projects with `OutputType=WindowsApplication` supported. |
| `WFO0002`     | NET9.0     |         | ArgumentException: Project property '{0}' cannot be set to '{1}'|
| `WFO0002`     | NET9.0     |         | ArgumentException: Project property '{0}' cannot be set to '{1}'. Reason: {2}.|
| `WFO0003`     | NET9.0     |         | Remove high DPI settings from {0} and configure via Application.SetHighDpiMode API or '{1}' project property.|
| `WFO0003`     | NET9.0     |         | Remove high DPI settings from {0} and configure via '{1}' property in Application Framework.|
| `WFO1000`     | NET9.0     |         | Property '{0}' does not configure the code serialization for its property content.|
| `WFO2001`     | NET9.0     |         | Task is being passed to `InvokeAsync` without a cancellation token |
| `WFO1001`     | NET10.0    |         | Type `{0}` does not implement `ITypedDataObject` interface |

## Experimental Feature Compiler Errors

See [Preview APIs - .NET | Microsoft Learn](https://learn.microsoft.com/dotnet/fundamentals/apicompat/preview-apis) for more information.
Documentation for experimental features is available in the [Experimental Help](https://github.com/dotnet/winforms/blob/main/docs/analyzers/Experimental.Help.md) file.

1. **Add the diagnostic ID to the table below**.
    - The current IDs are defined in [DiagnosticIDs.cs](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Analyzers/src/System/Windows/Forms/Analyzers/Diagnostics/DiagnosticIDs.cs).
2. **Add an `[Experimental](https://learn.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.experimentalattribute)` attribute** to your API.
    - Example:
    ```c#
    [Experimental(DiagnosticIDs.ExperimentalDarkMode, UrlFormat = DiagnosticIDs.UrlFormat)]
    ```
3. **Follow the [documentation steps 5-7 described for obsoletions](#create-the-new-aka.ms-link)** above.

| Diagnostic ID | Introduced | Removed | Description |
| :------------ | :--------- | :------ | :---------- |
| `WFO5001`     | NET9.0     |         | `System.Windows.Forms.Application.SetColorMode`(System.Windows.Forms.SystemColorMode) is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| `WFO5001`     | NET9.0     |         | `System.Windows.Forms.SystemColorMode` is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| `WFO5002`     | NET9.0     |         | `System.Windows.Forms.Form.ShowAsync` is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |
| `WFO5003`     | NET10.0     |         | `System.Windows.Forms.IAsyncDropTarget` is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed. |

---

### Net11 Visualstyles Layout Guidance (`docs/net11-visualstyles-layout-guidance.md`)

# .NET 11 VisualStyles layout guidance

`VisualStylesMode.Net11` modernizes framework-defined control chrome without adding a theming API. Colors and
metrics come from Windows state, including dark mode, accent color, High Contrast, DPI, focus metrics, and text
scale. High Contrast always selects classic, backward-compatible painting through
`EffectiveVisualStylesMode`.

Modern chrome can require more adornment space than classic chrome. When a naturally sized control opts in, the
control grows so its client area remains usable. This is intentional: glyphs and focus indicators designed for
96 DPI are not sufficient at modern display densities, and controls must also react to system text-scale changes.

## Choose an adaptive container

Use `TableLayoutPanel` or `FlowLayoutPanel` for controls whose preferred size can change. These containers already
handle localization, font changes, DPI changes, and AutoSize content, so they also handle modern visual-style
metrics.

Controls with intrinsic sizing, such as `Button`, single-line `TextBox`, `ComboBox`, and `Label`, update their
preferred size when their effective renderer changes. Controls with `AutoSize` enabled request layout
automatically.

### Fixed-bounds exceptions

`RichTextBox` and multiline `TextBox` do not have intrinsic single-line or `IntegralHeight` behavior. Switching
their visual style does not resize their bounds. If the modern non-client frame needs more room, their client area
shrinks slightly within the existing bounds.

That behavior is deliberate. Size and align fixed-bounds editors programmatically for the surrounding workflow
instead of relying on a global pixel-perfect height.

## Anchor when consuming size; Dock when pushing size

Use `Anchor` when a child consumes or aligns to space determined by its container. Use `Dock` when the child's
content should push the size of its container.

Inside an AutoSize `TableLayoutPanel`, anchor a control left and right when it should stretch to a column width
that the table computes:

```csharp
TextBox customerName = new()
{
    Anchor = AnchorStyles.Left | AnchorStyles.Right,
    AutoSize = true
};

tableLayoutPanel.Controls.Add(customerName, column: 1, row: 0);
```

Inside a constituent UserControl whose height should be driven by a single child, dock that child:

```csharp
public sealed class SearchEditor : UserControl
{
    private readonly TextBox _queryTextBox = new()
    {
        Dock = DockStyle.Top,
        AutoSize = true
    };

    public SearchEditor()
    {
        AutoSize = true;
        AutoSizeMode = AutoSizeMode.GrowAndShrink;
        Controls.Add(_queryTextBox);
    }
}
```

Do not use `DockStyle.Fill` as a substitute for AutoSize. Fill consumes the bounds already assigned by the parent;
it does not tell an AutoSize parent what preferred height the child needs.

## Equal-width OK and Cancel buttons

An AutoSize table with two 50 percent columns guarantees equal button widths. Each button is AutoSize and anchored
left and right, so both columns take the width required by the wider preferred button.

```
/* Detailed source-code truncated for AI context efficiency. */
```

The pattern remains stable when localization, DPI, text scale, or a VisualStylesMode transition changes either
button's preferred width or height.

## Align TextBox and ComboBox rows

Modern non-`Simple` ComboBox fields share their height metrics with an AutoSize, single-line modern TextBox using
`BorderStyle.Fixed3D`. ComboBox adds one logical pixel of internal style inset on top of its public Padding; apply
the same Padding to the TextBox when exact field-height parity is required. Put both in an AutoSize row, anchor
them left and right, and avoid hard-coded heights:

```csharp
TableLayoutPanel editorTable = new()
{
    AutoSize = true,
    AutoSizeMode = AutoSizeMode.GrowAndShrink,
    ColumnCount = 2,
    RowCount = 2
};
editorTable.ColumnStyles.Add(new ColumnStyle(SizeType.AutoSize));
editorTable.ColumnStyles.Add(new ColumnStyle(SizeType.Percent, 100F));
editorTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));
editorTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));

Label nameLabel = new()
{
    Anchor = AnchorStyles.Left,
    AutoSize = true,
    Text = "Name"
};
TextBox nameEditor = new()
{
    Anchor = AnchorStyles.Left | AnchorStyles.Right,
    AutoSize = true,
    Padding = new Padding(1)
};

Label categoryLabel = new()
{
    Anchor = AnchorStyles.Left,
    AutoSize = true,
    Text = "Category"
};
ComboBox categoryEditor = new()
{
    Anchor = AnchorStyles.Left | AnchorStyles.Right,
    DropDownStyle = ComboBoxStyle.DropDownList
};

editorTable.Controls.Add(nameLabel, 0, 0);
editorTable.Controls.Add(nameEditor, 1, 0);
editorTable.Controls.Add(categoryLabel, 0, 1);
editorTable.Controls.Add(categoryEditor, 1, 1);
```

Do not derive a ComboBox height from `ItemHeight`. Item height controls list content; the modern selection field
uses TextBox-compatible padding and focus metrics. ComboBox Padding is designer-visible in .NET 11 and is
serialized only when it differs from `Padding.Empty`.

## Account for GroupBox DisplayRectangle

In modern `FlatStyle.Standard` and `FlatStyle.Popup`, the GroupBox caption sits above a modern surface while
the `DisplayRectangle` preserves the classic etched-frame rectangle. `FlatStyle.Popup` uses a subtle
accent-tinted header band and accent border to distinguish the header without changing the content rectangle.
The caption aligns with the control Padding, and existing child layouts remain stable when switching visual
styles.

Use the GroupBox as a real layout container:

```csharp
GroupBox addressGroup = new()
{
    AutoSize = true,
    AutoSizeMode = AutoSizeMode.GrowAndShrink,
    Dock = DockStyle.Top,
    FlatStyle = FlatStyle.Standard,
    Text = "Address"
};

TableLayoutPanel addressTable = new()
{
    AutoSize = true,
    AutoSizeMode = AutoSizeMode.GrowAndShrink,
    Dock = DockStyle.Top
};

addressGroup.Controls.Add(addressTable);
```

Avoid positioning children outside `DisplayRectangle`; it remains the supported content boundary.

The modern caption is derived from the ambient font at paint time. WinForms preserves the ambient font family,
size, and style while still following system text scale.

## React to live text-scale changes

Place controls in AutoSize rows and let the layout engine react to the system event:

```csharp
TableLayoutPanel settingsTable = new()
{
    AutoSize = true,
    AutoSizeMode = AutoSizeMode.GrowAndShrink,
    ColumnCount = 1,
    RowCount = 2
};
settingsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));
settingsTable.RowStyles.Add(new RowStyle(SizeType.AutoSize));

GroupBox optionsGroup = new()
{
    AutoSize = true,
    AutoSizeMode = AutoSizeMode.GrowAndShrink,
    Text = "Options"
};
ComboBox optionSelector = new()
{
    Anchor = AnchorStyles.Left | AnchorStyles.Right,
    DropDownStyle = ComboBoxStyle.DropDownList
};

settingsTable.Controls.Add(optionsGroup, 0, 0);
settingsTable.Controls.Add(optionSelector, 0, 1);
```

Do not recreate controls when text scale changes. WinForms clears preferred-size caches, updates native selection
field metrics where necessary, and requests layout while preserving handles and selection.

## Migration tooling

Automated migration tools can replace fixed pixel layouts with adaptive containers, identify fixed-bounds editor
exceptions, and review accessibility and text-scale behavior. Planned WinForms agent skills will cover High DPI
layout, accessibility, text-scale-adaptive layouts, and pixel-perfect-to-Fluent refactoring. Treat generated
changes as a starting point and verify each workflow at the application's supported DPI, language, and
accessibility settings.

---

### Porting Guidelines (`docs/porting-guidelines.md`)

# Port existing applications to .NET 5.0

>We suggest doing migration in a separate branch or, if you're not using version
>control, creating a copy of your project so you have a clean state to go back
>to if necessary.

The migration process includes two steps: **preparing your project for porting** to
.NET and **porting** itself.

For additional information and assistance, we recommend checking out [this article on the dotnet blog][dotnet-blog-port-guide] as well as the [accompanying video tutorial][dotnet-blog-port-video].


## Breaking changes

Review the following resources that describe breaking changes between Windows Forms on .NET Framework and .NET:

* The [Breaking changes in Windows Forms (.NET Framework to .NET Core)](https://docs.microsoft.com/dotnet/core/porting/winforms-breaking-changes) describes breaking changes you need to be aware of when migrating your applications from .NET Framework
* The [Breaking changes in Windows Forms (.NET Core to .NET)](https://docs.microsoft.com/dotnet/core/compatibility/winforms) describes breaking changes you need to be aware of when migrating your applications from .NET Core 3.x versions to .NET 5.0 onwards.

## Prepare your project for porting

1. **Run [.NET Portability Analyzer][api-port]** first to determine if there are
   any APIs your application depends on that are missing in .NET. If there
   are, you have a few options.
    * Remove not supported APIs or replace them with those, that are included in
      .NET
    * Separate your code into different projects: the one that contains only
      .NET supported APIs and another with APIs not supported in .NET.
      Migrate only the first project.

1. **Start from a working solution**. Ensure the solution opens, builds, and runs without any issues.

1. **Replace `packages.config` with `PackageReference`**. If your project uses
   NuGet packages, you will need to add the same NuGet packages to the new .NET
   project. .NET projects support only `PackageReference` for adding
   NuGet packages. To move your NuGet references from `packages.config` to your
   project file, right-click on `packages.config` -> **Migrate packages.config
   to PackageReference...**.

   You can learn more about this migration in our [docs][pkg-config].

1. **Migrate to the SDK-style .csproj file**. The new SDK-style `.csproj` format is leaner and easier to read. To be able to simply copy-paste your references from the old project to the new one, you first need to migrate your old project file to SDK-style so both project are in the same format. You can either do it by hand or use a third-party tool [CsprojToVs2017][sdk-tool].

   After using the tool you still might need to delete some reference by hand; for example:

    ```xml
    <Reference Include="System.Data.DataSetExtensions" />
    <Reference Include="Microsoft.CSharp" />
    <Reference Include="System.Net.Http" />
    ```

   After you've migrated to the new SDK-style format, ensure your project builds and runs successfully.

1. **Configure assembly file generation**. Most existing projects include an `AssemblyInfo.cs` file in the Properties folder. The new project style uses a different approach and generates the same assembly attributes as part of the build process. As a result, you might end up with two `AssemblyInfo.cs` files and your build will fail. There are two ways to resolve this problem. You can either:
    * Disable `AssemblyInfo.cs` generation on build by setting the property:

        ```xml
        <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
        ```
    * Move the static values from `AssemblyInfo.cs` to properties in the new `.csproj` file.

    Build and run to make sure you did not introduce any issues while preparing your project. Now it is time to port it.



## Port your project

### Automated porting

1. Try porting your project using [`try-convert` tool](https://github.com/dotnet/try-convert), which we built to help migrations. <br />
NB: The tool may not work for all possible projects, in that case please read on.

### Manual porting

1. **Add .NET Windows Forms project**. Add a new .NET 5.0 Windows Forms project to the solution.

1. **Add `<ProjectReference>`**. Copy the `<ProjectReference>` elements from the `.csproj` file of the original project to the new project's `.csproj` file.<br />
Note: The new project format does not use the `Name` and `ProjectGuid` elements, so you can safely delete those.

1. **Restore/Build**. At this point, it's a good idea to restore/build to make sure all dependencies are properly configured.

1. **Link files**. Link all files from your existing .NET Framework WinForms project to the .NET 5.0 WinForms project by adding following to the `.csproj` file.

    ```xml
    <ItemGroup>
        <Compile Include="..\<Your .NET Framework Project Name>\**\*.cs" />
        <EmbeddedResource Include="..\<Your .NET Framework Project Name>\**\*.resx" />
    </ItemGroup>
    ```

1. **Align default namespace and assembly name**. Since you're linking to designer generated files (for example, `Resources.Designer.cs`) you generally want to make sure that the .NET version of your application uses the same namespace and the same assembly name. Copy the following settings from your .NET Framework project:

    ```xml
    <PropertyGroup>
        <RootNamespace></RootNamespace>
        <AssemblyName></AssemblyName>
    </PropertyGroup>
    ```

1. **Run new project**. Set your new .NET project as StartUp Project and run it. Make sure everything works.

1. **Copy or leave linked**. Now instead of linking the files, you can actually copy them from the old .NET Framework WinForms project to the new .NET 5.0 WinForms project. After that you can get rid of the old project.

## Migration tips

### Include the System.Windows.Forms.Datavisualization Pack

If you wish to use types previously associated with the [Charting control in the .NET Framework][framework-charting], you should add a package reference to the [NuGet package of Data Visualization][nuget-dataviz] ported to .NET. For more information about Data Visualization and the Charting control in .NET, including a sample application demonstrating its use, see the [winforms-datavisualization repository][dataviz]

### Include the Windows.Compatibility Pack

Windows applications like Windows Forms and WPF often use APIs that aren't referenced by default in .NET. The reason is that .NET tries to reduce the risk that new applications accidentally depend on legacy technologies or on APIs that are Windows-only. However, when porting existing Windows applications, neither of these two aspects is a concern. To simplify your porting efforts, you can simply reference the [Windows Compatibility Pack][compat-pack], which will give
you access to many more APIs.

```cmd
dotnet add package Microsoft.Windows.Compatibility
```

### Migrating WCF clients

.NET has its own implementation of `System.ServiceModel` with some
differences:

* It is available as a set of NuGet packages (also included in the [Windows
  Compatibility Pack][compat-pack]).
* There are [unsupported features][wcf-supported] that you should review.
* The binding and endpoint address must be specified in the service client constructor. Otherwise, if you reuse the `ServiceReference` created by Visual Studio, you may get the following error:

```cs
System.PlatformNotSupportedException: 'Configuration files are not supported.'
```

### Additional Types and Namespaces

You can search for additional types which you may need in porting your apps to .NET on [.NET API Catalog][apisofnet]. For example, when you search for the type `System.AppDomain`, you will see that the type has been moved to `System.Runtime.Extensions` namespace starting in .NET 2.0.

[comment]: <> (URI Links)

[dotnet-blog-port-guide]: https://devblogs.microsoft.com/dotnet/how-to-port-desktop-applications-to-net-core-3-0/
[dotnet-blog-port-video]: https://www.youtube.com/watch?v=upVQEUc_KwU
[api-port]: https://blogs.msdn.microsoft.com/dotnet/2018/08/08/are-your-windows-forms-and-wpf-applications-ready-for-net-core-3-0/
[pkg-config]: https://docs.microsoft.com/nuget/reference/migrate-packages-config-to-package-reference
[sdk-tool]:https://github.com/hvanbakel/CsprojToVs2017
[framework-charting]: https://docs.microsoft.com/dotnet/api/system.windows.forms.datavisualization.charting
[nuget-dataviz]: https://www.nuget.org/packages/System.windows.forms.datavisualization
[dataviz]: https://github.com/dotnet/winforms-datavisualization
[compat-pack]: https://docs.microsoft.com/dotnet/core/porting/windows-compat-pack
[wcf-supported]: https://github.com/dotnet/wcf/blob/master/release-notes/SupportedFeatures-v2.1.0.md
[apisofnet]: https://catalog.apireview.net/

---

### Release Activity (`docs/release-activity.md`)

# Runtime release procedures

## Milestone releases (dotnet/winforms + dotnet/windowsdesktop)

1. Merge any outstanding PRs, if necessary
2. Ensure the HEAD of the main branch builds successfully and all tests pass
3. Publish any unpublished API - run [.\eng\ApiCompatibility\mark-shipped.cmd](https://github.com/dotnet/winforms/blob/main/eng/ApiCompatibility/mark-shipped.cmd)

4. Commit and wait for a successful build

5. (Milestone releases) Create "release/X.Y-qwe" branch (e.g. release/6.0-preview5) and push it into the main public trunk and the internal trunk.
Wait for both build successfully.
* Main public trunk: https://github.com/dotnet/winforms/
* Internal trunk: <need url>
6. Disable loc on "release/X.Y-qwe" branch (e.g.: https://github.com/dotnet/winforms/pull/6753)
7. Switch back to the main branch
8. Update the Service Fabric bot with the new release label in .\github\fabricbot.json. Refer to .\docs\infra\automation.md, if have questions.
9. Update the branding (e.g.: https://github.com/dotnet/winforms/commit/719b2112778ffd1e7ded559ea2736b4011428117)
10. Commit and wait for a successful build.

11. Create new [milestone](https://github.com/dotnet/winforms/milestones) for the new release before updating following bot service.  

12. Move work items to this new milestone if they were on previous milestone and close the previous milestone.

13. Update necessary reports with the progress

14. If you are responsible for [dotnet/windowsdesktop](https://github.com/dotnet/windowsdesktop) repo, make sure you change the branding there too.

## Servicing releases (dotnet/winforms + dotnet/windowsdesktop)

[NET Servicing - Overview (azure.com)](https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/545/NET-Servicing)

1. Merge internal servicing branch (i.e. internal/internal/release/*) into the public branch, if necessary.  

2. Update the branding (e.g.: https://github.com/dotnet/winforms/commit/480bd703c5af93b9e23dc7435c6029d685be7097)
3. Commit and wait for a successful build.

4. Ensure the HEAD of the servicing branch builds successfully and all tests pass

5. Update [dotnet/installer](https://github.com/dotnet/installer) with the released version (e.g.: https://github.com/dotnet/installer/commit/34ed90f436809631e254b9e15628cbcad7307629)

6. Create a new [milestone](https://github.com/dotnet/winforms/milestones).

7. Close the current milestone on the GitHub, ensuring all open issues/PRs are either closed or bumped to the following milestone

8. Merge any outstanding PRs, if necessary

---

### Roadmap (`docs/roadmap.md`)

# Windows Forms Roadmap

This roadmap communicates priorities for evolving and extending the scope of Windows Forms. For general information regarding .NET plans, see [.NET roadmap](https://github.com/dotnet/core/blob/master/roadmap.md).

* [Future](#future)
* [Present](#present)

This repository is a community effort and we welcome community feedback on our plans. The best way to give your feedback is to open an issue in this repo.
We also invite contributions. The [help wanted issues](https://github.com/dotnet/winforms/issues?q=is%3Aopen+is%3Aissue+label%3A"help%20wanted") on GitHub are a good place to start.

## Future

Here is the list of improvements we are planning to work on in the future.

### Accessibility improvements

Including support for standard [WCAG2.1]( https://www.w3.org/TR/WCAG21/), such as enabling tooltips for controls on `Tab` ([#2726](https://github.com/dotnet/winforms/issues/2726)), etc.

### High DPI improvements

* Fix existing scaling bugs in Per Monitor DPI aware applications
* Enable all controls to support Per Monitor V2 mode
* Add a new "clean" way of calculating location/size information in PMA mode

### Performance improvements

Establish a base line and improve runtime and designer performance.

### Testing infrastructure

Add testing infrastructure and improve test coverage.

## Some potential features

We also are gathering feedback regarding what other features you'd like to see in WinForms. Please let us know if any of those or something else would be useful for your applications. You an create a feature request in this repo or vote for an existing one.

### Add and improve wrappers for missing Win32 controls

Such as Ribbon Control, Balloons, SearchBox, improvements around ListView, etc.

### Add support for OS themes in WinForms applications

Enable dark theme, etc.

## Present

### Windows Forms runtime

**Under considerations**.<br/>A number of aspects are being considered including (but not limited to) layout engine and high DPI support, theming, new controls and components.

### Windows Forms Designer

We continue the work on the designer to to achieve the parity with the .NET Framework designer.
This involves adding the remaining controls and features and improving stability and performance for the designer.

---

### Runtime Configuration (`docs/runtime-configuration.md`)

# Support for application runtime configuration in Windows Forms applications

## Overview

.NET Windows Forms applications currently have limited [application
configurations](https://aka.ms/applicationconfiguration) capabilities that are defined via MSBuils properties and are emitted into source code using source
generators at compile time. This document outlines expansion of those application-wide configurations further to cover runtime config options for .NET Windows Forms applications.

## .NET Framework runtime configuration

.NET Framework Windows Forms applications use `app.config` to define runtime configurations and application-wide settings. The following are the various sections in the app.config that define the application's runtime behavior.

### AppContext switches

These settings are used to opt-in or opt-out of a particular feature from Windows Forms runtime. Refer to the [AppContext Switches](https://docs.microsoft.com/dotnet/framework/configure-apps/file-schema/runtime/appcontextswitchoverrides-element) documentation for more information.

```xml
<configuration>
  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Globalization.NoAsyncCurrentCulture=true" />
  </runtime>
</configuration>
```
### `System.Windows.Forms.ApplicationConfigurationSection` section

This was introduced in .NET Framework 4.7, and it is primarily used by Windows Forms runtime to enable high DPI and other accessibility improvements. Please refer to the [ApplicationConfigurationSection](https://docs.microsoft.com/dotnet/framework/configure-apps/file-schema/winforms/windows-forms-add-configuration-element) documentation for more information.

```xml
<configuration>
  <System.Windows.Forms.ApplicationConfigurationSection>
    
  </System.Windows.Forms.ApplicationConfigurationSection>
</configuration>
```

### Application-wide and user-specific settings

These are commonly defined via the Settings designer in Visual Studio, which serializes those into `app.config`. Refer to the [Application Settings](https://docs.microsoft.com/dotnet/desktop/winforms/advanced/using-application-settings-and-user-settings) documentation for more information.

```xml
<userSettings>
  <WinFormsApp2.Properties.Settings>
    <setting name="ButtonName" serializeAs="String">
      <value>LocalButton</value>
    </setting>
  </WinFormsApp2.Properties.Settings>
</userSettings>

<applicationSettings>
  <WinFormsApp2.Properties.Settings>
    <setting name="BoxName" serializeAs="String">
      <value>LocalBox</value>
    </setting>
  </WinFormsApp2.Properties.Settings>
</applicationSettings>
```


## .NET 7+ runtime configuration

`app.config` has limited support in .NET due to performance and reliability reasons. .NET runtime and other .NET teams use `runtimeconfig.json` to define .NET runtime configurations and `appsettings.json` to define application-level settings. In this proposal, we are leveraging `runtimeconfig.json` to define Windows Forms runtime configurations.

While this proposal is focusing on providing an alternative solution for existing configuration sections `AppContextSwitchOverrides` and `System.Windows.Forms.ApplicationConfigurationSection` that are primarily used for specifying feature flags impacting Windows Forms runtime behavior, we will be looking into alternatives for `Application Settings` that doesn't require `app.config` in the future releases of .NET.


### Goals:

- A replacement for `AppContextSwitchOverrides` and `System.Windows.Forms.ApplicationConfigurationSection` of `app.config`.
- Users should be able to update/modify Windows Forms applications runtime configurations without recompiling the application.
- The existing applications should be able to seamlessly upgrade to the new configuration model when targeting .NET 7+ runtime.
- The existing [application configuration MSBuild properties](https://aka.ms/applicationconfiguration) continue to work.

### Out of scope:

- App settings that are serialized by the Settings designer/editor page. Applications should continue to use the current model.
- Dynamic/real-time (re-)loading of configuration values from `runtimeconfig.json`.
- Unification of comple/runtime configurations into one place, e.g., `runtimeconfig.json`.


### Design proposal

Windows Forms switches will be added to **`runtimeConfig.template.json`** to the [`configProperties` section](https://docs.microsoft.com/dotnet/core/runtime-config) with the rest of the .NET switches. To avoid name conflics Windows Forms specific switches will be prefixed with `System.Windows.Forms`:

```json
{
  "configProperties": {
      "System.Globalization.UseNls": true,
      "System.Net.DisableIPv6": true,
      "System.GC.Concurrent": false,
      "System.Threading.ThreadPool.MinThreads": 4,
      "System.Threading.ThreadPool.MaxThreads": 25,
      
      // Windows Forms specific switches
      "System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi": true,
      "System.Windows.Forms.CustomEnumProperty": "EnumValue"
    }
}
```


#### Reading Windows Forms runtime configurations

When a project is [built](https://docs.microsoft.com/dotnet/core/runtime-config/#runtimeconfigjson), an `[appname].runtimeconfig.json` file is generated in the output directory. If a `runtimeconfig.template.json` file exists in the same folder as the project file, any configuration options it contains are inserted into the `[appname].runtimeconfig.json` file.

This proposal focuses primarily on enabling the runtime configurations for Windows Forms applications. A support for analyzers and source generators may be considered in the future .NET releases. We will revisit this implementation to improve user-experience further, as we make progress.

For example, the content of `[appname].runtimeconfig.json` generated from above content:

```json
{
  "runtimeOptions": {
    "tfm": "net7.0",
    "frameworks": [
      {
        "name": "Microsoft.NETCore.App",
        "version": "7.0.0-preview.7.22375.6"
      },
      {
        "name": "Microsoft.WindowsDesktop.App",
        "version": "7.0.0-preview.7.22377.1"
      }
    ],
    "configProperties": {
      "System.Globalization.UseNls": true,
      "System.Net.DisableIPv6": true,
      "System.GC.Concurrent": false,
      "System.Threading.ThreadPool.MinThreads": 4,
      "System.Threading.ThreadPool.MaxThreads": 25,

      "System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi": true,
      "System.Windows.Forms.StringProperty": "string",
      "System.Windows.Forms.CustomProperty": "CustomValue"
    }
  }
}
```

#### Enabling modern rendering for composite controls

`ToolStrip`, `MenuStrip`, and `DataGridView` use Classic rendering when `VisualStylesMode`
is `Net11` or `Latest` by default. Applications can opt in to modern rendering with these
switches:

```json
{
  "configProperties": {
    "System.Windows.Forms.ToolStripModernRendering": true,
    "System.Windows.Forms.DataGridViewModernRendering": true
  }
}
```

`System.Windows.Forms.ToolStripModernRendering` controls both `ToolStrip` and `MenuStrip`.
Both switches default to `false`.

The target framework information added to `[appname].runtimeconfig.json` file always match with the application target framework irrespective of runtime/SDK installed on the machine or runtime used ([roll-forward scenarios](https://docs.microsoft.com/dotnet/core/versions/selection#framework-dependent-apps-roll-forward)) by the Windows Forms application.

#### .NET runtime support in reading `runtimeconfig.json`

The Windows Forms runtime is leveraging the [support](https://github.com/dotnet/runtime/blob/5098d45cc1bf9649fab5df21f227da4b80daa084/src/native/corehost/runtime_config.cpp) provided by .NET runtime in reading `[appname].runtimeconfig.json` file, and thus get all plumbing required for various hosting and environment scenarios. The Windows Forms runtime adds the following wrapper on top of .NET runtime implementation to improve the performance by caching configuration options, and also by defining custom defaults values for the Windows Forms specific feature flags. This wrapper is very similar to the [.NET runtime's implementation](https://github.com/dotnet/runtime/blob/04dac7b0fede29d44f896c5fd793754f83974175/src/libraries/System.Private.CoreLib/src/System/AppContextConfigHelper.cs).

The below example illustrates how to define `ScaleTopLevelFormMinMaxSizeForDpi` feature flag, opt-in by default, for an application targeting .NET 8 or later running on Windows 10:

```
/* Detailed source-code truncated for AI context efficiency. */
```


The Windows Forms runtime then uses the static `LocalAppContextSwitches` class to access the runtime configurations. The below sample demonstrates the use of the feature switch `System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi` to scale min/max size of a container control:

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Shared Wpf Infrastructure (`docs/shared-wpf-infrastructure.md`)

# Shared WinForms/WPF Infrastructure

## Overview

This document describes infrastructure components shared between **WinForms** (in the `dotnet/winforms` repository) and **WPF** (in the `dotnet/wpf` repository). Understanding this sharing is critical for contributors and maintainers when making changes to shared code, as modifications can impact both UI stacks.

**Key takeaway:** Changes to `System.Private.Windows.Core` and certain other shared assemblies in this repository affect both WinForms and WPF applications. Always consider cross-stack implications when modifying these components.

## Which Components Are Shared

The primary shared component is **`System.Private.Windows.Core`**, which contains low-level Windows interop and OLE/COM support used by both WinForms and WPF. The most critical shared subsystem is the **clipboard and OLE data handling** implementation.

### System.Private.Windows.Core

**Location:** `src/System.Private.Windows.Core/`

**Key shared areas:**
- **OLE/Clipboard implementation:** `src/System.Private.Windows.Core/src/System/Private/Windows/Ole/`
  - `Composition.NativeToManagedAdapter.cs` - Adapts native `IDataObject` to managed interface
  - `Composition.ManagedToNativeAdapter.cs` - Adapts managed `IDataObject` to native COM
  - `DataObjectCore.cs` - Core data object implementation
  - `ClipboardCore.cs` - Core clipboard operations
  - `BinaryFormatUtilities.cs` - Binary format handling for serialization
  - Related support classes for format conversion, drag-and-drop, and data transfer

**Why this matters:** These classes handle fundamental clipboard and drag-and-drop operations. Bugs in this code can manifest in both WinForms and WPF applications, and fixes here benefit both stacks.

## How Sharing Works

The sharing mechanism involves packaging, transport, and ingestion into the Windows Desktop shared framework:

1. **Packaging in dotnet/winforms:**
   - The `Microsoft.Private.Winforms` transport package is built from this repository
   - This package bundles `System.Private.Windows.Core` and other shared assemblies
   - See: `pkg/Microsoft.Private.Winforms/README.md`

2. **Ingestion by WPF:**
   - The `dotnet/wpf` repository consumes the `Microsoft.Private.Winforms` NuGet package
   - Props and targets from `pkg/Microsoft.Private.Winforms/sdk/dotnet-wpf/` are used by WPF's SDK
   - WPF builds integrate these assemblies into their artifact set

3. **Windows Desktop Shared Framework:**
   - Both WinForms and WPF assemblies are bundled into the `Microsoft.WindowsDesktop.App` shared framework
   - The `dotnet/windowsdesktop` repository orchestrates this bundling
   - Applications targeting Windows Desktop get a single unified set of assemblies at runtime

**Result:** At runtime, WinForms and WPF applications in the same process share a single instance of `System.Private.Windows.Core.dll`, ensuring consistent behavior for clipboard, OLE, and related operations.

## Concrete Examples and Case Studies

### Case Study 1: IStream Double-Release (WPF #11401, WinForms #14257/#14296)

**Issue:** When clipboard data was stored using `TYMED_ISTREAM`, the code would wrap the `IStream` pointer in a `ComScope` and then call `ReleaseStgMedium`. This caused a double-release: `ComScope.Dispose()` would release the stream, and then `ReleaseStgMedium` would release it again, leading to crashes or undefined behavior.

**Root cause:** Located in `Composition.NativeToManagedAdapter.cs`, method `TryGetIStreamData<T>`

**Fix in PR #14257:**
```csharp
// Don't wrap in ComScope - ReleaseStgMedium will release the stream.
Com.IStream* pStream = (Com.IStream*)medium.hGlobal;
```

**Impact:**
- **WPF #11401:** Reported as a WPF issue, but the bug was in shared code in dotnet/winforms
- **WinForms #14257:** Fixed in main branch
- **WinForms #14296:** Draft PR to backport the fix to release/10.0
- **Outcome:** Single fix in dotnet/winforms resolved the issue for both WinForms and WPF

**Lesson:** Bugs in shared clipboard/OLE code often surface in both stacks. When WPF reports a clipboard or data transfer issue, check `System.Private.Windows.Core` code in this repository.

### Case Study 2: GetData Failure and Uninitialized STGMEDIUM (WPF #11402, WinForms #14257)

**Issue:** When clipboard content changed between `QueryGetData` (which checks availability) and `GetData` (which retrieves the data), `GetData` would fail but the code would still attempt to read from the uninitialized `STGMEDIUM` structure. This led to reading garbage data or crashing.

**Root cause:** Located in `Composition.NativeToManagedAdapter.cs`, method `TryGetHGLOBALData<T>`

**Fix in PR #14257:**
```csharp
// If GetData failed, don't try to read from the medium - it may contain uninitialized data.
// (This can easily happen when the clipboard content changes between QueryGetData and GetData calls.)
if (hr.Failed)
{
    return false;
}
```

**Impact:**
- **WPF #11402:** Reported as a WPF clipboard reliability issue
- **WinForms #14257:** Fixed in main branch along with other hardening improvements
- **Outcome:** Better error handling and null returns instead of corrupted data, benefiting both stacks

**Lesson:** Race conditions and error handling in shared code require careful validation. Changes should anticipate contention scenarios common in clipboard operations.

### Additional Improvements in PR #14257

- **UTF-8 HGLOBAL hardening:** Improved string reading to prevent malformed data from causing exceptions
- **Test coverage:** Added mocks and tests for STGMEDIUM handling scenarios
- **Constants:** Added `CLIPBRD_E_CANT_OPEN` and other clipboard-related error constants

## Advantages of Sharing

1. **Consistency:** Clipboard and OLE behavior is identical across WinForms and WPF applications
2. **Single fix benefits both:** Bug fixes in shared code automatically improve both stacks
3. **Shared test coverage:** Tests in dotnet/winforms validate behavior for WPF as well
4. **Reduced duplication:** Avoids maintaining two separate implementations of complex OLE/COM interop
5. **Better quality:** Concentrated development and review effort on a single implementation

## Liabilities and Risks

1. **Coupling:** Changes in dotnet/winforms can break WPF, and vice versa (though WPF changes rarely touch these components)
2. **Regressions affect both stacks:** A bug introduced in shared code will impact both WinForms and WPF
3. **Validation requirements:** Changes must be tested in both WinForms and WPF scenarios
4. **Discoverability:** It may not be obvious to contributors that code changes impact WPF

## Guidance for Contributors

### When Working on Shared Code

**Which code is shared?**
- Primarily `src/System.Private.Windows.Core/`, especially the `Ole/` directory
- If in doubt, check if the code is in `System.Private.Windows.Core` or referenced in `pkg/Microsoft.Private.Winforms/`

**Before making changes:**
1. **Consider WPF impact:** Ask yourself: "Could this change affect WPF clipboard, drag-and-drop, or data transfer?"
2. **Search for related WPF issues:** Check the [dotnet/wpf issue tracker](https://github.com/dotnet/wpf/issues) for similar problems
3. **Review existing tests:** Look at test coverage in `src/System.Private.Windows.Core.Tests/` and `src/System.Windows.Forms.Tests/` for clipboard/OLE scenarios

**When making changes:**
1. **Prefer small, targeted fixes:** Especially for release branches (e.g., `release/10.0`), minimize scope to reduce risk
2. **Larger refactorings belong in main:** Structural changes and broad refactorings should target the `main` branch
3. **Add or update tests:** Ensure your changes have test coverage, including error handling and edge cases
4. **Add cross-repo references:** If your PR addresses a WPF issue, link it in the PR description:
   ```
   Fixes dotnet/wpf#11401
   Relates to dotnet/wpf#11402
   ```
5. **Document breaking changes:** If behavior changes in observable ways, call it out explicitly

**Validation checklist:**
- Run WinForms tests: `build.cmd -test`
- Test clipboard operations manually:
  - Copy/paste text between applications
  - Copy/paste images
  - Try custom data formats if your change affects them
  - Test drag-and-drop scenarios
- If possible, validate with a WPF application
  - WPF development follows the same patterns (`build.cmd`, `start-vs.cmd`, etc.)
  - Consider testing via manual insertion of the updated shared DLL or repointing to a locally built transport package
- Check for memory leaks or COM reference counting issues in loops or stress scenarios

**Code review considerations:**
- Ensure error handling is robust (null checks, HRESULT validation, etc.)
- Look for potential double-release or use-after-free patterns in COM/OLE code
- Verify that `ComScope` disposal is correct and that different release mechanisms don't overlap
- Consider thread safety and race conditions (clipboard content can change at any time)
- Look for changes in state return (different values, exceptions). Changes must be carefully considered and have strong justification to minimize breaking changes.
- Document all breaking changes.
- OLE / clipboard state is shared machine wide. It is expected that state can change at any time. Handle state change gracefully.
- Avoid second guessing application intent and shared OLE state. If the data is not retrieved successfully just accept the result, don't retry. Existing retry logic can be kept- if API users want retry logic they should either implement their own wrappers or present new API requests where intent can be made explicit.

### Backporting to Release Branches

When backporting clipboard/OLE fixes to release branches (e.g., for WPF servicing):
- **Minimize risk:** Only backport critical bug fixes, not refactorings or enhancements
- **Preserve behavior:** Avoid changing API signatures or introducing observable behavioral changes
- **Test thoroughly:** Release branches require extra validation since they're servicing supported releases
- **Coordinate with WPF team:** Reach out on GitHub or in discussions if the issue originated in WPF

### Related Open Issues

The following issues track ongoing work and awareness in this area:
- [dotnet/winforms#14304](https://github.com/dotnet/winforms/issues/14304)
- [dotnet/winforms#14305](https://github.com/dotnet/winforms/issues/14305)

## Additional Resources

- **Packaging and transport:** `pkg/Microsoft.Private.Winforms/README.md`
- **Clipboard/DataObject API changes:** `docs/dataobject-serialization.md`
- **Contributing to WinForms:** `CONTRIBUTING.md`
- **Issue guidelines:** `docs/issue-guide.md`
- **WPF repository:** https://github.com/dotnet/wpf
- **Windows Desktop repository:** https://github.com/dotnet/windowsdesktop

## Summary

Shared infrastructure between WinForms and WPF provides significant benefits but requires awareness and care when making changes. Contributors should:
- Recognize when they're working on shared code (especially `System.Private.Windows.Core`)
- Consider the impact on both UI stacks
- Add appropriate test coverage
- Link related WPF issues in PRs
- Validate changes in both WinForms and WPF scenarios when possible
- Prefer small, targeted changes for release branches

By following these guidelines, we can maintain high-quality, reliable clipboard and OLE functionality for both WinForms and WPF applications.

---

### Testing In Vs (`docs/testing-in-vs.md`)

# Windows Forms Testing in Visual Studio

Visual Studio executes unit tests differently from the command line. This page describes some of those differences and covers common problems and workarounds.

## Assert.Same() failures

### Problem

`Assert.Same()` calls that pass when running tests from the command line can often fail when running through Visual Studio. This has to do with a quirk in the xUnit Visual Studio test adapter.

### Cause

* When using `[Theory]` combined with `[InlineData]`, `[ClassData]`, or `[MemberData]`, the xUnit VS test adapter does performs "discovery enumeration", before the test is actually executed
    * It does this to populate the Test Explorer window with all the test cases before they run
* The process running this enumeration executes in a **different App domain** than the tests themselves
* This means objects passed in to the test methods have **different references** than expected (when comparing strings, for example)

### Solution(s)

There are two ways to get around this problem:

1. Use a custom *DataAttribute (inheriting from the appropriate *DataAttributeBase class) and set `DisableDiscoveryEnumeration = true` in the constructor
    * For an example of this, see [MauiDataAttribute.cs](https://github.com/dotnet/winforms/blob/afa8a0779f261e46fe7eb1611142bea143622578/src/System.Windows.Forms/tests/IntegrationTests/System.Windows.Forms.Maui.IntegrationTests/MauiDataAttribute.cs#L42)
    * This is not really preferred, and should only be used when your test data can't be resolved at compile-time

    OR

1. Use Assert.Equal() when comparing against objects created by `[InlineData]`, `[ClassData]`, or `[MemberData]`
    * You can still use Assert.Same() in all other cases

## Tests don't execute

### Problem

* When launching tests through Visual Studio, no tests execute
* Click on `View -> Output` and select `Tests` from the `Show output from:` dropdown
* You might see an error that looks like `Testhost process exited with error: It was not possible to find any compatible framework version. The specified framework 'Microsoft.NETCore.App', version 'XXX' was not found`

### Cause (long)

* The .net core SDK and the .net core runtime (Microsoft.NetCore.App) are two different things.
* The SDK targets a specific NetCore.App. This version is automatically downloaded into your local .dotnet folder when you build from command line, and is also installed when you install a dotnet sdk machine-wide.
    * If you don’t specify an explicit NetCore.App version, you will use the one that the SDK targets.
    * If you’re interested in seeing what this version is, look at `<yourRepoRoot>\.dotnet\sdk\<yourSdkVersion>\dotnet.runtimeconfig.json`
* The winforms (runtime) repo DOES specify an explicit NetCore.App version, and we use the one published by the core-setup repo.
    * If you look at [Directory.Build.Targets](https://github.com/dotnet/winforms/blob/ac0426561b158522eb8564de2bedd28f28148f8d/Directory.Build.targets#L35), you can see where this is set 
* `$(VSRedistCommonNetCoreSharedFrameworkx6490PackageVersion)` is set in [Versions.props](https://github.com/dotnet/winforms/blob/ac0426561b158522eb8564de2bedd28f28148f8d/eng/Versions.props#L19), and gets automatically updated when we ingest dependencies from core-setup. (These PR's are automatically merged in if the build passes)
    * You can see where the dependency comes from by looking at [Version.Details.xml](https://github.com/dotnet/winforms/blob/ac0426561b158522eb8564de2bedd28f28148f8d/eng/Version.Details.xml#L13)
    * The reason we use the version from core-setup instead of the version built-in to the SDK is we don’t want to wait for the runtime to come all the way through the SDK repo to consume it
* Running tests from the command line (.\build -test) works because the build scripts automatically download both the sdk AND the NetCore.App that you need AND add the .dotnet folder to your PATH when running.
    * You can verify this by checking the .dotnet folder in your repo root. The NetCore.App is in the shared folder.
* However, Visual Studio doesn’t care about your local .dotnet folder. It always looks at your machine-wide installs (unless you manually add things to your PATH before launching VS)
    * If you don’t have the required SDK installed machine-wide, your code won’t build (through VS). 
    * If you don’t have the required NetCore.App installed machine-wide, your code won’t run (through VS). 
* **This is why unit tests can fail immediately through VS.**
    * Note that just installing the SDK **IS NOT ENOUGH** if you are using an explicit NetCore.App version.
* Since the command line builds automatically download everything you need, we just have to tell VS where this stuff lives

### Solution(s)

There are two ways to get around this problem:

1. Add your local `<repoRoot>\.dotnet` folder to the front of your PATH variable
    * This is **not preferred** because Visual Studio will always look here first, and can break other things, like if you need to build against a higher version of the SDK

    OR

1. Close VS, run `<repoRoot>\build-local.ps1`, then re-open VS
    * This will do a restore (to download the stuff), do a build, then symlink the stuff you need from your local .dotnet folder to your machine-wide SDK install folder `(C:\Program Files\dotnet\...)`. Then VS will know about it too 😊

---

### Testing (`docs/testing.md`)

# Windows Forms Testing

This document describes our approach to testing.

* [Building tests](#building-tests)
* [Unit Tests](#unit-tests)
    * [Running unit tests](#running-unit-tests)
        - [Unit testing from the command line](#unit-testing-from-the-command-line)
        - [Troubleshooting command-line unit test errors](#troubleshooting-command-line-unit-test-errors)
        - [Unit testing from Visual Studio](#unit-testing-from-visual-studio)
        - [Troubleshooting Visual Studio unit test errors](#troubleshooting-visual-studio-unit-test-errors)
    * [Adding new unit tests](#adding-new-unit-tests)
        - [Test placement](#therefore-you-just-need-to-put-your-tests-in-the-right-place-in-order-for-them-to-run)
        - [Unit Test best practices](#unit-test-best-practices)
            - [Naming](#naming)
            - [Decoration](#decoration)
            - [Disposal](#dispose-created-objects)
            - [Theory tests](#theory-tests)
        - [Strategy](#strategy)
* [Rendering Tests](#rendering-tests)
* [Functional Tests](#functional-tests)
    * [Running functional tests](#running-functional-tests)
        - [Functional testing from the command line](#functional-testing-from-the-command-line)
        - [Troubleshooting command-line functional test errors](#troubleshooting-command-line-functional-test-errors)
        - [Functional testing from Visual Studio](#functional-testing-from-visual-studio)
        - [Troubleshooting Visual Studio functional test errors](#troubleshooting-visual-studio-functional-test-errors)
    * [Adding new functional tests](#adding-new-functional-tests)
        - [Test placement](#therefore-you-just-need-to-put-your-tests-in-the-right-place-in-order-for-them-to-run-1)
 * [Sequential collection](#sequential-collection)
 * [Testing for Accessibility](#testing-for-accessibility)
 * [Running and debugging crashed tests](#running-and-debugging-crashed-tests)
    

# Building tests

Tests are automatically built when running `.\build` since all test projects are referenced in `Winforms.sln` at the repository root.

# Unit Tests

## Running unit tests

### Unit testing from the command line

To execute unit tests, run `.\build -test`

If all the tests are successful, you should see something like this:

```console
  Running tests: E:\src\repos\github\winforms\artifacts\bin\System.Windows.Forms.Tests\Debug\net6.0\System.Windows.Forms.Tests.dll [net6.0|x64]
  Tests succeeded: E:\src\repos\github\winforms\artifacts\bin\System.Windows.Forms.Tests\Debug\net6.0\System.Windows.Forms.Tests.dll [net6.0|x64]

Build succeeded.
    0 Warning(s)
    0 Error(s)
```

### Troubleshooting command-line unit test errors

When testing from the command line, a failed test should look something like this:

```console
Running tests: E:\src\repos\github\winforms\artifacts\bin\System.Windows.Forms.Tests\Debug\net6.0\System.Windows.Forms.Tests.dll [net6.0|x64]
XUnit : error : Tests failed: E:\src\repos\github\winforms\artifacts\TestResults\Debug\System.Windows.Forms.Tests_net6.0_x64.html [net6.0|x64] [E:\src\repos\github\winforms\src\System.Windows.Forms\tests\UnitTests\System.Windows.Forms.Tests.csproj]
XUnit : error : Tests failed: E:\src\repos\github\winforms\artifacts\TestResults\Debug\System.Windows.Forms.Tests_net6.0_x64.html [net6.0|x64] [E:\src\repos\github\winforms\src\System.Windows.Forms\tests\UnitTests\System.Windows.Forms.Tests.csproj]

Build FAILED.
```

* The test summary can be found under artifacts\log
* To see the actual test(s) that failed, along with their error message(s), open the .html file that is displayed in the error message (which is always under `artifacts\TestResults`)

### Unit testing from Visual Studio

To test from Visual Studio, start Visual Studio via `.\start-vs.cmd`, and test how you normally would (using the Test Explorer, for example)

### Troubleshooting Visual Studio unit test errors

* When testing from Visual Studio, test errors show up as normal in the Test Explorer.
* To troubleshoot, debug the selected test and set breakpoints as you normally would.
* For common issues when running tests through Visual Studio, see [Testing in Visual Studio](testing-in-vs.md)

## Adding new unit tests

Tests are built and executed by file name convention

* Every WinForms binary has its own folder under src in the repository root (src\System.Windows.Forms, for example)
* Each of those folders has a tests folder under it (src\System.Windows.Forms\tests, for example)
* Each tests folder contains an xUnit test project (System.Windows.Forms.Tests.csproj)
  * These test projects automatically build when running `.\build`
  * The tests from these projects automatically execute when running `.\build -test`.<br/>
    It is also possible to execute individual tests via `dotnet test --filter <filter expression>` command by switching to the desired test project directory first.
  

### Therefore, you just need to put your tests in the right place in order for them to run

* Browse to the tests folder for the binary you are testing.
* There should be one file per class being tested, and the file name should match the class name followed by a "**Tests**" suffix.
  * For example, if I wanted to test the `Button` class in System.Windows.Forms.dll, I would look for a **ButtonTests.cs** under src\System.Windows.Forms\tests.
  * For example, if I wanted to test the `Button.ButtonAccessibleObject` class in System.Windows.Forms.dll, I would look for a **Button.ButtonAccessibleObjectTests.cs** under src\System.Windows.Forms\tests.
* If the file exists, add your tests there. If it doesn't exist, feel free to create it.
  * **Note that you don't have to modify the csproj at all.** Since the project is a Microsoft.NET.Sdk project, all source files next to it are automatically included.

### Unit Test best practices

#### Naming

* Test files names should match the class they are testing followed by a "**Tests**" suffix.
  * For example, tests for the `Button` class should be in ButtonTests.cs.
  * For example, tests for the `Button.ButtonAccessibleObject` class should be in **Button.ButtonAccessibleObjectTests.cs**.
* Test names should start with the class they are testing.
  * For example, all tests for the `Button` class should start with "Button".
* Test names should end with a description of what the test does - this is very useful when viewing test results, and when browsing in the test explorer. As far as naming conventions are concerned we don't mandate a specific one, as long as a test name clearly communicates its purpose.
  * For example, `Button_AutoSizeModeGetSet` or `MyButton_Click_should_throw_ArgumentNullException`.

#### Decoration

* All tests that deal with UI controls or types that require synchronization context must be decorated with `WinFormsFact` or `WinFormsTheory` attributes.
* Other tests can be decorated with `StaFact`, `StaTheory`, `Fact` or `Theory`

#### Dispose created objects

* All tests creating disposable objects (e.g. UI controls) must dispose them. Otherwise it could lead to memory leaks (bad but not terminal) and race conditions that could lead to deadlocked tests (terminal).
  ```cs
    [WinFormsFact]
    public void ButtonBase_GetAutoSizeMode_Invoke_ReturnsExpected()
    {
        using SubButtonBase control = new();
        Assert.Equal(AutoSizeMode.GrowOnly, control.GetAutoSizeMode());
    }  
  ```
  
#### Theory tests

Quite often there may be multiple tests that test exactly the same functionality but with different input parameters (e.g. `null`, `""`, `" "` for a `string` argument). 
In such cases instead of creating multiple tests it is preferred to have a theory test, which is in another words a data-driven test.

When writing theories note the following:

1. theory test must be [correctly decorated](#Decoration)

2. theories must avoid creating UI controls. E.g. instead of writing:
    ```cs
    public static IEnumerable<object[]> GetButton_TestData()
    {
        yield return new object[] { new Button() };
        yield return new object[] { new Button() { Text = "bla" } };
    }

    [WinFormsTheory]
    [MemberData(nameof(GetButton_TestData))]
    public void Ctor_Control_DataGridViewCellStyle(Button button) { ... }
    ```
    prefer the following:
    ```cs
    public static IEnumerable<object[]> GetButton_TestData()
    {
        yield return new object[] { string.Empty };
        yield return new object[] { "bla" };
    }

    [WinFormsTheory]
    [MemberData(nameof(GetButton_TestData))]
    public void Ctor_Control_DataGridViewCellStyle(string buttonText) 
    {
        using Button button = new() { Text = buttonText };
        ...
    }    
    ```
  
3. theories must not reuse disposable components.<br />
  In situations where following the above recommendation could be impractical, it is maybe acceptable to create disposable controls for each theory data, e.g.:
    ```cs
    public static IEnumerable<object[]> GetButton_TestData()
    {
        yield return new object[] { new Button(), new DataGridViewCellStyle() };
        yield return new object[] { new Button() { Text = "bla" }, new DataGridViewCellStyle() };
    }
    ```
    xUnit tries its best to [dispose](https://github.com/xunit/xunit/blob/56476a9691bb061661190b183733c5d8a2c6ef4d/src/xunit.execution/Sdk/Frameworks/TestMethodTestCase.cs#L191-L197) of disposable objects.
    However objects must not be shared across theories, as it could lead to unknown state, e.g.
    ```cs
    // ** DO NOT DO THIS! **
    public static IEnumerable<object[]> GetButton_TestData()
    {
        Button button = new();
        yield return new object[] { button, new DataGridViewCellStyle() };
        yield return new object[] { button { Text = "bla" }, new DataGridViewCellStyle() }; // the button could already be disposed by the time this theory runs
    }
    ```


Also be mindful of VS-specific behaviours: https://xunit.net/faq/theory-data-stability-in-vs


#### Strategy

##### Unit tests should be part of the same PR as code changes

* Unit tests must be added for any change to public APIs. 
* We will accept unit tests for internal/private methods as well. Some non-public API can be accessed directly (e.g. `internal`), some via subclassing (e.g. `virtual`) or via the public surface. However there are plenty of instances where a non-public API can't be easily accessed or arranged for. In this cases we use [`TestAccessor` pattern](https://github.com/dotnet/winforms/blob/main/src/Common/tests/TestUtilities/TestAccessor.cs) to arrange, act and assert.

##### Code Coverage

* In Visual Studio Test Explorer, select all tests, right click and execute 'Analyze code coverage for selected tests' command. This will run all tests and give a summary of blocks covered in 'Code Coverage Results' window. The summary can be drilled down to method level.
* Any code change accompanied with unit tests is expected to increase code coverage for the code modified.

##### Avoid duplicating tests just for different inputs

* Use `WinFormsTheory`, `StaTheory` or `Theory` attributes for this, followed by either `[InlineData]` or `[MemberData]`. See existing tests for examples on how to use these attributes
* The exception to this is if the code behavior is fundamentally different based on the inputs. For example, if a method throws an `ArgumentException` for invalid inputs, that should be a separate test.

##### One test (or test data) per code path please

* The most common exception to this is when testing a property, most people test get/set together

##### Whenever possible, mock up dependencies to run tests in isolation
  
* For example, if your method accepts an abstraction, use Moq to mock it up
* Search for Mock in the existing tests for examples, and see [Moq](https://github.com/Moq/moq4/wiki/Quickstart) for details on how to use Moq.


# Rendering Tests

We use [Enhance Metafiles](https://docs.microsoft.com/windows/win32/gdi/enhanced-format-metafiles) (or EMF for short) to validate rendering operations, i.e. assert that correct shapes were drawn with expected colours and brushes.

A typical "rendering" assertion test would looks something like this:
```cs
[WinFormsFact]
public void MyControl_Rendering()
{
    // 1. Create a control to validate rendering for.
    // 2. Add the control to a form, and make sure the form is created
    using Form form = new Form();
    using MyControl control = new() { ... };
    form.Controls.Add(control);
    Assert.NotEqual(IntPtr.Zero, form.Handle);

    // Create an Enhance Metafile into which we will render the control
    using EmfScope emf = new();
    DeviceContextState state = new DeviceContextState(emf);

    // Render the control
    control.PrintToMetafile(emf);

    // We can see the rendering steps by invoking this command:
    // string records = emf.RecordsToString();

    // Assert the rendering was as expected
    emf.Validate(
        state,
        ...
        );
}
```


# Functional Tests

> :warning: There is a very blurry line between unit and functional tests in Windows Forms realm. A lot of our implementations depend on ambient contexts (such as Win32, COM, etc.). We classify tests as "functional" or "integration" that require process-wide settings (such as visual styles) or require user-like interactions (e.g. mouse gestures).

The general purpose functional test suite is the **WinFormsControlsTest**. There is an xUnit project that executes various commands against this binary.

## Running functional tests

### Functional testing from the command line

To execute functional tests, run `.\build -integrationTest`

You will see various windows open and close very quickly. If all the tests are successful, you should see something like this:

```console
  Running tests: E:\src\repos\github\winforms\artifacts\bin\System.Windows.Forms.IntegrationTests\Debug\net6.0\System.Windows.Forms.IntegrationTests.dll [net6.0|x64]
  Tests succeeded: E:\src\repos\github\winforms\artifacts\bin\System.Windows.Forms.IntegrationTests\Debug\net6.0\System.Windows.Forms.IntegrationTests.dll [net6.0|x64]

Build succeeded.
    0 Warning(s)
    0 Error(s)
```



### Troubleshooting command-line functional test errors

Since these run in xUnit, functional test errors can be examined in the same way as unit test failures.

### Functional testing from Visual Studio

To test from Visual Studio, open Winforms.sln in Visual Studio and test how you normally would (using the Test Explorer, for example)

### Troubleshooting Visual Studio functional test errors

* When testing from Visual Studio, test errors show up as normal in the test explorer.
* To troubleshoot, debug the selected test and set breakpoints as you normally would.

## Adding new functional tests

Functional tests are built and executed by file name convention

* Every WinForms binary has its own folder under src in the repository root (src\System.Windows.Forms, for example)
* Each of those folders has a tests folder under it (src\System.Windows.Forms\tests, for example), each of which may contain an IntegrationTests folder
* Each of these folders contains an IntegrationTest xUnit project (System.Windows.Forms.IntegrationTests.csproj)
  * These test projects automatically build when running `.\build`
  * The tests from these projects automatically execute when running `.\build -integrationTest`

### Therefore, you just need to put your tests in the right place in order for them to run

* Browse to the tests folder for the binary you are testing
* There should be one file per class being tested, and the file name should match the class name.
  * For example, if I wanted to test the `Button` class in System.Windows.Forms.dll, I would look for a Button.cs under src\System.Windows.Forms\tests
* If the file exists, add your tests there. If it doesn't exist, feel free to create it.
  * **Note that you don't have to modify the csproj at all.** Since the project is a Microsoft.NET.Sdk project, all source files next to it are automatically included

# Sequential Collection

* A sequential collection is a grouping of unit tests that are executed in a specific order.
  - All unit tests in the `Sequential` collection are executed sequentially.
    
* Unit tests that involve the following situations should be included in the `Sequential` collection:
  - Clipboard operations is sensitive to the state of the system and interfere with each other if run in parallel.
    - **Clipboard APIs**: Any test that interacts with the system Clipboard, such as setting or retrieving data.
    - **Drag and Drop**: Tests that simulate drag-and-drop operations, which often involve the Clipboard.
    - **Copy/Paste**: Tests that perform copy and paste actions, which rely on the Clipboard to transfer data.
    - **Register Formats**: Tests that register custom Clipboard formats.
      
    E.g.
    ```cs
    [Collection("Sequential")]
    public class ClipboardTests
    {
        [WinFormsFact]
        public void RichTextBox_OleObject_IncompleteOleObject_DoNothing()
        {
            using RichTextBox control = new();
            control.Handle.Should().NotBe(IntPtr.Zero);

            using MemoryStream memoryStream = new();
            using Bitmap bitmap = new(100, 100);
            bitmap.Save(memoryStream, Drawing.Imaging.ImageFormat.Png);
            Clipboard.SetData("Embed Source", memoryStream);

            control.Text.Should().BeEmpty();
        }
     ```
  - Other tests that rely on a global state, refer to existing tests
    
     - [Clipboard related tests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/ClipboardTests.cs)
     - [WebBrowser control related tests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms/tests/UnitTests/System/Windows/Forms/HtmlElementTests.cs)
     - [PropertyGridTests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms/tests/InteropTests/PropertyGridTests.cs)
     - [ITypeInfoTests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Oleaut32/ITypeInfoTests.cs)
     - [IPictureTests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Primitives/tests/UnitTests/Interop/Ole32/IPictureTests.cs)
     - [IDispatchTests](https://github.com/dotnet/winforms/blob/main/src/System.Windows.Forms.Primitives/tests/UnitTests/Windows/Win32/System/Com/IDispatchTests.cs)  
  
# Testing for Accessibility

Our goal is to make writing accessible WinForms applications easy. Specifically, all default property values should yield accessible experience. To test that controls are accessible, find or add the changed control to [AccessibilityTests application](https://github.com/dotnet/winforms/tree/main/src/System.Windows.Forms/tests/AccessibilityTests) and run [Accessibility Insights for Windows](https://accessibilityinsights.io/docs/en/windows/overview) on it. 


# Running and debugging crashed tests

At times tests may fail in way that makes it difficult to debug (e.g., the [test runner process crashes](https://github.com/dotnet/runtime/issues/76219)). In this case, it's good to replicate the issue locally and collect a memory dump to have a better understanding whether the issue is caused by the change in Windows Forms SDK, or, for example, by the .NET runtime.

* Configure your workstation to automatically collect memory dumps following [Collecting User-Mode Dumps guide](https://learn.microsoft.com/windows/win32/wer/collecting-user-mode-dumps) guide.
* Run `.\start-code.cmd`
* In the VS Code terminal run the following commands to run the tests:
    ```
    .\restore.cmd
    pushd .\src\System.Windows.Forms\tests\UnitTests
    dotnet test 
    ```
* Upon the test process crash, navigate to the collected memory dump and inspect it in [WinDbg](https://learn.microsoft.com/windows-hardware/drivers/debugger/debugger-download-tools) (or [MSFT internal](https://www.osgwiki.com/wiki/WinDbg)) (or another tool of your choice).

❕If you need to debug an x86-related issue, run tests with `-a x86` argument, e.g., `dotnet test -a x86`, and then use the 32-bit version of WinDbg to open the dump.

---

### Accessibility Accessible Role Controltype (`docs/accessibility/accessible-role-controltype.md`)

# Consistency of AccessibleRole and "ControlType" for accessible objects

This document describes a behavior and relations of `AccessibleRole` property of 
[controls](https://docs.microsoft.com/dotnet/api/system.windows.forms.control.accessiblerole) and 
[ToolStrip items](https://docs.microsoft.com/dotnet/api/system.windows.forms.toolstripitem.accessiblerole) 
 and `"ControlType"` accessibility property.

* [Overview](#Overview)
* [AccessibleRole-"ControlType" mapping](#AccessibleRole-"ControlType"-mapping)
* [Default "ControlType" values](#Default-"ControlType"-values)
* [Exceptional cases and additional info](#Exceptional-cases-and-additional-info)
    

# Overview

All accessible objects have `"ControlType"` (a part of modern [UIA](https://docs.microsoft.com/dotnet/framework/ui-automation/ui-automation-overview)) and "[LegacyIAccessible](https://docs.microsoft.com/windows/win32/winauto/uiauto-implementinglegacyiaccessible)`.Role"` 
(further `"Role"` - a part of outdated [MSAA](https://docs.microsoft.com/windows/win32/winauto/microsoft-active-accessibility)) accessibility properties. 

![inspect-accessibility-properties][inspect-accessibility-properties]

Accessibility tools ([Inspect](https://docs.microsoft.com/windows/win32/winauto/inspect-objects), 
[Narrator](https://support.microsoft.com/windows/complete-guide-to-narrator-e4397a0d-ef4f-b386-d8ae-c172f109bdb1),
 etc.) request [Role](https://docs.microsoft.com/dotnet/api/system.windows.forms.accessibleobject.role) property of accessible objects to 
get `"Role"` accessibility property value. `Role` property value of 
[ControlAccessibleObject](https://docs.microsoft.com/dotnet/api/system.windows.forms.control.controlaccessibleobject), 
[ToolStripItemAccessibleObject](https://docs.microsoft.com/dotnet/api/system.windows.forms.toolstripitem.toolstripitemaccessibleobject), 
and their descendants can be set by the developer using public `AccessibleRole` property.

![accessibleobject-role-implementation][accessibleobject-role-implementation]


Accessibility tools call internal `GetPropertyValue` method with `ControlTypePropertyId` 
argument to get `"ControlType"` value.

![accessibleobject-getpropertyvalue-implementation][accessibleobject-getpropertyvalue-implementation]


**.NET Framework 4.7.2** implements the following `AccessibleRole` property and 
`"ControlType"` accessibility property relations:
when `Control`'s or `ToolStripItem`'s `AccessibleRole` property is set to a non-default 
value by the developer, the native accessibility proxy implementation would 
set `"ControlType"` property to a matching value.</br>
**.NET Framework 4.8**, **.NET Core 3.0** and **3.1**, **.NET 5.0** lost 
this behavior for all controls that implement **UIA providers** because 
they provide custom implementation of UIA properties and no longer rely 
on UIA proxy to match roles to control types. **.NET 6.0** restores the **.NET Framework 4.7.2** behavior.


# AccessibleRole-"ControlType" mapping

When a developer changes `AccessibleRole` property value of a control 
or a `ToolStrip` item (for example: `control.AccessibleRole = AccessibleRole.List;`), `"ControlType"` accessibility 
property value of the corresponding accessible object will 
be changed according to the following list (except some cases described below):

| AccessibleRole | ControlType |
| ------------- | ------------- |
|Alert|Pane|
|Animation|Pane|
|Application|Window|
|Border|Pane|
|ButtonDropDown|SplitButton|
|ButtonDropDownGrid|Button|
|ButtonMenu|MenuItem|
|Caret|Pane|
|Cell|DataItem|
|Character|Pane|
|Chart|Pane|
|CheckButton|CheckBox|
|Client|Pane|
|Clock|Button|
|Column|Pane|
|ColumnHeader|Header|
|ComboBox|ComboBox|
|Cursor|Pane|
|Default|Pane|
|Diagram|Pane|
|Dial|Pane|
|Dialog|Pane|
|Document|Document|
|DropList|Pane|
|Equation|Pane|
|Graphic|Image|
|Grip|Thumb|
|Grouping|Group|
|HelpBalloon|Pane|
|HotkeyField|Pane|
|Indicator|Thumb|
|IpAddress|Pane|
|Link|Hyperlink|
|List|List|
|ListItem|ListItem|
|MenuBar|MenuBar|
|MenuItem|MenuItem|
|MenuPopup|Menu|
|None|Pane|
|Outline|Tree|
|OutlineButton|Pane|
|OutlineItem|TreeItem|
|PageTab|TabItem|
|PageTabList|Tab|
|Pane|Pane|
|ProgressBar|ProgressBar|
|PropertyPage|Pane|
|PushButton|Button|
|RadioButton|RadioButton|
|Row|Pane|
|RowHeader|Header|
|ScrollBar|ScrollBar|
|Separator|Separator|
|Slider|Slider|
|Sound|Pane|
|SpinButton|Spinner|
|SplitButton|SplitButton|
|StaticText|Text|
|StatusBar|StatusBar|
|Table|Table|
|Text|Edit|
|TitleBar|TitleBar|
|ToolBar|ToolBar|
|ToolTip|ToolTip|
|WhiteSpace|Pane|
|Window|Window|


# Default "ControlType" values

Here is the list of common controls and `ToolStrip` items with 
their accessible objects `"ControlType"` accessibility property values 
by default - when `AccessibleRole` property value of these controls 
and `ToolStrip` items is not set:
```cs
Control control = new Control();
// control.AccessibleRole = AccessibleRole.List; - Role is not set
```
or equals [AccessibleRole](https://docs.microsoft.com/dotnet/api/system.windows.forms.accessiblerole)`.Default`:
```cs
Control control = new Control();
control.AccessibleRole = AccessibleRole.Default; // Role is set to the default value
```

| Control or item | Default ControlType |
| ------------- | ------------- |
|Button|Button |
|CheckBox |CheckBox |
|CheckedListBox |List |
|ComboBox |ComboBox |
|ContextMenuStrip<br/>└ ToolStripMenuItem<br/>└┴ ToolStripMenuItem<br/>└┴ ToolStripComboBox<br/>└┴ ToolStripTextBox<br/>└┴ ToolStripSeparator<br/>└ ToolStripComboBox<br/>└ ToolStripTextBox<br/>└ ToolStripSeparator|Menu<br/>MenuItem<br/>Pane<br/>ComboBox<br/>Edit<br/>Separator<br/>ComboBox<br/>Edit<br/>Separator|
|DataGridView <br/>└ DataGridViewEditingPanel |Table <br/>Pane|
|DateTimePicker |ComboBox|
|DomainUpDown<br/>└ UpDownButtons<br/>└ UpDownEdit|Spinner<br/>Spinner<br/>Edit|
|FlowLayoutPanel|Pane|
|Form|Window|
|GroupBox|Group|
|HScrollBar|ScrollBar|
|Label|Text|
|LinkLabel|Text|
|ListBox|List|
|ListView|List|
|MenuStrip<br/>└ ToolStripMenuItem<br/>└┴ ToolStripMenuItem<br/>└┴ ToolStripComboBox<br/>└┴ ToolStripTextBox<br/>└┴ ToolStripSeparator<br/>└ ToolStripComboBox<br/>└ ToolStripTextBox|MenuBar<br/>MenuItem<br/>MenuItem<br/>ComboBox<br/>Edit<br/>Separator<br/>ComboBox<br/>Edit|
|MaskedTextBox|Edit|
|MonthCalendar|Calendar/Table|
|NumericUpDown<br/>└ UpDownButtons<br/>└ UpDownEdit|Spinner<br/>Spinner<br/>Edit|
|PictureBox|Pane|
|ProgressBar|ProgressBar|
|PropertyGrid|Pane|
|RadioButton|RadioButton|
|RichTextBox|Document|
|ScrollBar|ScrollBar|
|SplitContainer|Pane|
|Splitter|Pane|
|StatusStrip<br/>└ ToolStripStatusLabel<br/>└ ToolStripProgressBar<br/>└ ToolStripSplitButton<br/>└ ToolStripDropDownButton<br/>└┴ ToolStripMenuItem<br/>└┴ ToolStripComboBox<br/>└┴ ToolStripTextBox<br/>└┴ ToolStripSeparator|StatusBar<br/>Text/Link<br/>ProgressBar<br/>Button<br/>Button<br/>MenuItem<br/>ComboBox<br/>Edit<br/>Separator|
|TabControl|Tab|
|TableLayoutPanel|Pane|
|TabPage|Pane|
|TextBox|Edit|
|TextBoxBase|Edit|
|ToolStrip<br/>└ ToolStripItem<br/>└ ToolStripComboBox<br/>└ ToolStripDropDown<br/>└ ToolStripNumericUpDown<br/>└ ToolStripOverflow<br/>└ ToolStripProgressBar<br/>└ ToolStripTextBox<br/>└ ToolStripButton<br/>└ ToolStripLabel<br/>└ ToolStripSplitButton<br/>└ ToolStripDropDownButton<br/>└ ToolStripSeparator<br/>└ ToolStripOverflowButton<br/>|ToolBar<br/>Button<br/>ComboBox<br/>Menu<br/>Spinner<br/>Menu<br/>ProgressBar<br/>Edit<br/>Button<br/>Text/Link<br/>Button<br/>Button<br/>Separator<br/>MenuItem|
|TrackBar|Slider|
|TreeView|Tree|
|VScrollBar|ScrollBar|
|TrackBar|Slider|
|TreeView|Tree|
|VScrollBar|ScrollBar|

# Exceptional cases and additional info
- Here is the list of controls and `ToolStrip` items that didn't change 
their accessible objects `"ControlType"` values depending on `Role` in **.NET Framework 4.7.2** 
but in **in .NET 6.0** they can do it correctly:
  1. **`ListView`** - `"ControlType"` was always `List`
  2. **`ToolStripMenuItem`** - `"ControlType"` was always `Menu item`
  3. **`ToolStripSplitButton`** - `"ControlType"` was always `Button`
  4. **`ToolStripDropDownButton`** - `"ControlType"` was always `Button`

- **`RichTextBox`**: at this moment, we don't provide a managed accessible object for it. 
It doesn't support setting a custom `AccessibleRole` and 
changing `"ControlType"` respectively (in **.NET Framework 4.7.2** too). 
It always has `"Role"` as `Document` and `"ControlType"` as `Document`.
- **`TreeView`**: at this moment, we don't provide a managed accessible object for it. 
It doesn't support setting a custom `AccessibleRole` and 
changing `"ControlType"` respectively (in **.NET Framework 4.7.2** too). 
It always has `"Role"` value as `Outline` and `"ControlType"` value as `Tree`.
- **`DateTimePicker`**: its accessible object has non-standard 
`"LocalizedControlType"` accessibility property value by default. 
But it changes if to change `AccessibleRole` property value of the control.
- **`Form`**: default `"Role"` value is `Client` but default `"ControlType"` value
is `Window`. This is an exception and does not correspond to the list above.
In the rest, `Form` with a custom `AccessibleRole` value works as expected.
- **`MonthCalendar`**: if `AccessibleName` property value is null or empty 
default `"ControlType"` of its accessible object is `Calendar`, 
if `AccessibleName` is a some text - default `"ControlType"` is `Table`.
- **`ToolStripLabel`**: if `IsLink` property value equals `false` 
its accessible object default `"ControlType"` value is `Text`, 
and `"ControlType"` is `Hyperlink` if `IsLink` is `true`.
- **`ToolStripStatusLabel`**: if `IsLink` property value equals `false` 
its accessible object default `"ControlType"` value is `Text`, 
and `"ControlType"` is `Hyperlink` if `IsLink` is `true`.
- **`ToolStripNumericUpDown`**: this item is used in [PrintPreviewDialog](https://docs.microsoft.com/dotnet/api/system.windows.forms.printpreviewdialog) control.
- **`ToolStripOverflowButton`**:  needs to use [ToolStrip.OverflowButton](https://docs.microsoft.com/dotnet/api/system.windows.forms.toolstrip.overflowbutton) 
property to get this item and set a custom `AccessibleRole` value.
- **`DataGridViewEditingPanel`**: default `"Role"` is `Client`. 
Needs to use [DataGridView.EditingPanel](https://docs.microsoft.com/dotnet/api/system.windows.forms.datagridview.editingpanel) to get the control and set 
a custom value for its `AccessibleRole`.

[inspect-accessibility-properties]: ../images/inspect-accessibility-properties.png
[accessibleobject-role-implementation]: ../images/accessibleobject-role-implementation.png
[accessibleobject-getpropertyvalue-implementation]: ../images/accessibleobject-getpropertyvalue-implementation.png

---

### Accessibility Listview Expected Behavior (`docs/accessibility/listview-expected-behavior.md`)

# ListView accessibility objects expected behavior

This document describes the expected behavior of [ListView](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview) , [ListView](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewgroup), [ListViewSubItem](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.listviewsubitem) accessibility objects when using Inspect.


- [Overview](#Overview)
- [ListView](#ListView)
    - [Accessibility tree for ListView](##Accessibility-tree-for-ListView)
- [ListViewGroup](#ListViewGroup)
    - [Accessibility tree for a ListView with displayed ListViewGroups](##Accessibility-tree-for-a-ListView-with-displayed-ListViewGroups)
	- [Accessibility tree for a ListView with disabled visual styles](##Accessibility-tree-for-a-ListView-with-disabled-visual-styles)	
	- [Accessibility tree for a ListView with disabled ListViewGroups](##Accessibility-tree-for-a-ListView-with-disabled-ListViewGroups)
	- [Accessibility tree for a ListView in virtual mode](##Accessibility-tree-for-a-ListView-in-virtual-mode)
	- [Accessibility tree for a ListView without ListViewGroups](##Accessibility-tree-for-a-ListView-without-ListViewGroups)
- [ListViewSubItem](#ListViewSubItem)
    - [Accessibility tree for a ListViewItem](##Accessibility-tree-for-a-ListViewItem)
	- [Accessibility tree for a ListViewItem (Details view)](##Accessibility-tree-for-a-ListViewItem-(Details-view))
	- [Accessibility tree for a ListViewItem (Tile view)](##Accessibility-tree-for-a-ListViewItem-(Tile-view))

# Overview

[ListView](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview) is a Win32 native control provided by Windows.
Windows Forms runtime provides a support for [UI Automation](https://docs.microsoft.com/dotnet/framework/ui-automation/ui-automation-overview) and, thus, responsible for providing required accessible objects with correct properties and actions to make all aspects of the `ListView` control accessible for customers.

# ListView

## Accessibility tree for ListView

`ListView` accessibility tree must contain all visible items based on the selected `View` [view](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.view).

<details>
<summary>1. Details view</summary>
</br>

![listview-inspect-details-view-tree][listview-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-inspect-largeicon-view-tree][listview-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-inspect-list-view-tree][listview-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-inspect-smallicon-view-tree][listview-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listview-inspect-tile-view-tree][listview-inspect-tile-view-tree]

</details>
</br>

# ListViewGroup

The `ListView` always contains one or more [ListViewGroup](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewgroup), but depending on a configuration of the operating system, application and/or the `ListView` itself, these [groups](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.groups) can be visible or not.

## Accessibility tree for a ListView with displayed ListViewGroups

A `ListViewGroup` is display if the following conditions are met:
1. An application has [visual styles](https://docs.microsoft.com/dotnet/api/system.windows.forms.application.enablevisualstyles) are enabled.
2. A `ListView` is not in a [virtual mode](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.virtualmode).
3. The [ShowGroups](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.showgroups) property has `true` value
4. A `ListView` has one or more [groups](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.groups)
5. A `ListView` is not in a `List` view

```cs
ListViewGroup listViewGroup = new ListViewGroup("Test group");
listView.Groups.Add(listViewGroup);

listView.ShowGroups = true;
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 3", "SubItem 31" }, imageIndex: 0));
```

<details>
<summary>1. Details view</summary>
</br>

![listview-withgroup-inspect-details-view-tree][listview-withgroup-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-withgroup-inspect-largeicon-view-tree][listview-withgroup-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-withgroup-inspect-list-view-tree][listview-withgroup-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-withgroup-inspect-smallicon-view-tree][listview-withgroup-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listview-withgroup-inspect-tile-view-tree][listview-withgroup-inspect-tile-view-tree]

</details>
</br>

## Accessibility tree for a ListView with disabled visual styles
`ListViewGroups` are not visible when [visual styles](https://docs.microsoft.com/dotnet/api/system.windows.forms.application.enablevisualstyles) are disabled.

```cs
ListViewGroup listViewGroup = new ListViewGroup("Test group");
listView.Groups.Add(listViewGroup);

listView.ShowGroups = true;
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 3", "SubItem 31" }, imageIndex: 0));
```

<details>
<summary>1. Details view</summary>
</br>

![listview-disabledstyles-inspect-details-view-tree][listview-disabledstyles-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-disabledstyles-inspect-largeicon-view-tree][listview-disabledstyles-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-disabledstyles-inspect-list-view-tree][listview-disabledstyles-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-disabledstyles-inspect-smallicon-view-tree][listview-disabledstyles-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listview-disabledstyles-inspect-tile-view-tree][listview-disabledstyles-inspect-tile-view-tree]

</details>
</br>

## Accessibility tree for a ListView with disabled ListViewGroups
`ListViewGroups` are not visible when [ShowGroups](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.showgroups) property is set to `false`.

```cs
ListViewGroup listViewGroup = new ListViewGroup("Test group");
listView.Groups.Add(listViewGroup);

listView.ShowGroups = false;
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0, group: listViewGroup));
listView.Items.Add(new ListViewItem(new string[] { "Item 3", "SubItem 31" }, imageIndex: 0));
```

<details>
<summary>1. Details view</summary>
</br>

![listview-showgroupdisabled-inspect-details-view-tree][listview-showgroupdisabled-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-showgroupdisabled-inspect-largeicon-view-tree][listview-showgroupdisabled-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-showgroupdisabled-inspect-list-view-tree][listview-showgroupdisabled-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-showgroupdisabled-inspect-smallicon-view-tree][listview-showgroupdisabled-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listview-showgroupdisabled-inspect-tile-view-tree][listview-showgroupdisabled-inspect-tile-view-tree]

</details>
</br>

## Accessibility tree for a ListView in virtual mode
`ListViewGroups` are not visible when `ListView` is in [virtual mode](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.virtualmode).

```cs
ListViewGroup listViewGroup = new ListViewGroup("Test group");
listView.Groups.Add(listViewGroup);

listView.VirtualMode = virtualMode;
listView.VirtualListSize = 3;

listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

ListViewItem listItem1 = new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0, group: listViewGroup));
ListViewItem listItem2 = new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0, group: listViewGroup));
ListViewItem listItem3 = new ListViewItem(new string[] { "Item 3", "SubItem 31", "SubItem 32", "SubItem 33" }, imageIndex: 0));

listView.RetrieveVirtualItem += (s, e) =>
    {
        e.Item = e.ItemIndex switch
        {
            0 => listItem1,
            1 => listItem2,
            2 => listItem3,
            _ => throw new NotImplementedException()
        };
    };

listItem1.SetItemIndex(listView, 0);
listItem2.SetItemIndex(listView, 1);
listItem3.SetItemIndex(listView, 2);
```

<details>
<summary>1. Details view</summary>
</br>

![listview-virtualmode-inspect-details-view-tree][listview-virtualmode-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-virtualmode-inspect-largeicon-view-tree][listview-virtualmode-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-virtualmode-inspect-list-view-tree][listview-virtualmode-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-virtualmode-inspect-smallicon-view-tree][listview-virtualmode-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

The ListView in virtual mode does not support "Tile" view

</details>
</br>

## Accessibility tree for a ListView without ListViewGroups
`ListViewGroups` are not visible when `ListView` has no [groups](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.groups).

```cs
listView.ShowGroups = true;
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 3", "SubItem 31" }, imageIndex: 0));
```

<details>
<summary>1. Details view</summary>
</br>

![listview-withoutgroup-inspect-details-view-tree][listview-withoutgroup-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listview-withoutgroup-inspect-largeicon-view-tree][listview-withoutgroup-inspect-largeicon-view-tree]

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listview-withoutgroup-inspect-list-view-tree][listview-withoutgroup-inspect-list-view-tree]

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listview-withoutgroup-inspect-smallicon-view-tree][listview-withoutgroup-inspect-smallicon-view-tree]

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listview-withoutgroup-inspect-tile-view-tree][listview-withoutgroup-inspect-tile-view-tree]

</details>
</br>

# ListViewSubItem

## Accessibility tree for a ListViewItem
A [ListViewSubItem](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem) is display if the following conditions are met:
1. A `ListView` is in a `List` or `Details` [views](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.view).
2. A `ListView` has one or more [ListViewSubItems](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.subitems)
3. A `ListView` has one or more [Columns](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.subitems)
4. The `ListViewItem` has a [TileSize](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.tilesize) enough to display `ListViewSubItems` (only for `Tile` view)


```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));

listView.TileSize = new Size(100, 100);  
```

<details>
<summary>1. Details view</summary>
</br>

![listviewsubitem-inspect-details-view-tree][listviewsubitem-inspect-details-view-tree]

</details>
</br>

<details>
<summary>2. LargeIcon view</summary>
</br>

![listviewsubitem-inspect-largeicon-view-tree][listviewsubitem-inspect-largeicon-view-tree]
This view does not support ListViewSubItems

</details>
</br>

<details>
<summary>3. List view</summary>
</br>

![listviewsubitem-inspect-list-view-tree][listviewsubitem-inspect-list-view-tree]
This view does not support ListViewSubItems

</details>
</br>

<details>
<summary>4. SmallIcon view</summary>
</br>

![listviewsubitem-inspect-smallicon-view-tree][listviewsubitem-inspect-smallicon-view-tree]
This view does not support ListViewSubItems

</details>
</br>

<details>
<summary>5. Tile view</summary>
</br>

![listviewsubitem-inspect-tile-view-tree][listviewsubitem-inspect-tile-view-tree]

</details>
</br>

## Accessibility tree for a ListViewItem (Details view)

It is typical for this mode that when displaying accessibility objects for `ListViewSubItems` in the Inspect tree, the main parameter is not the number of [ListViewSubItems](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.subitems), but the number of [Columns](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.columns) that the user can see. 

In the case when the number of `Columns` and `ListViewSubItems` is the same, the user sees that all `Columns` contain data and all `ListViewSubItems` are displayed in the Accessibility tree.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));
```

![listviewsubitem-inspect-details-view-tree][listviewsubitem-inspect-details-view-tree]

If the number of `Columns` is less than the number of `ListViewSubItems`, then the user sees only those `ListViewSubItems` for which there are `Columns`. As a result, only `ListViewSubItems` with matching `Columns` are displayed in the Inspector tree. `ListViewSubItems` without corresponding `Columns` on the screen and in the Accessibility tree are not displayed.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));
```

![listviewsubitem-twocolumns-inspect-details-view-tree][listviewsubitem-twocolumns-inspect-details-view-tree]

If the number of `Columns` is greater than the number of `ListViewSubItems`, then a fake accessibility object is displayed for non-existent `ListViewSubItems`. This is because whether they exist or not, the user sees the cell for the `ListViewSubItem`, so it should have an accessibility object to interact with the Accessibility tree.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21" }, imageIndex: 0));
```

![listviewsubitem-twosubitems-inspect-details-view-tree][listviewsubitem-twosubitems-inspect-details-view-tree]

## Accessibility tree for a ListViewItem (Tile view)
This view takes many factors into account when displaying `ListViewSubItems`.

The first `ListViewSubItem` (with 0 index) is never shown in the Accessibility tree, as its data is displayed within the `ListViewItem`. `ListViewItem.FragmentNavigate(NavigateDirection.FirstChild)`, `ListViewItem.FragmentNavigate(NavigateDirection.LastChild)` and
`ListViewSubItem.FragmentNavigate(NavigateDirection.PreviousSibling)` methods, also never return a 0-indexed `ListViewSubItem`

All [ListViewSubItem](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem) is display if the following conditions are met:
1. A `ListView` has one or more [ListViewSubItems](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.subitems)
2. A `ListView` has one or more [Columns](https://docs.microsoft.com/dotnet/api/system.windows.forms.listviewitem.subitems)
3. The `ListViewItem` has a [TileSize](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.tilesize) enough to display `ListViewSubItems`

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));

listView.TileSize = new Size(100, 100);  
```

![listviewsubitem-inspect-tile-view-tree][listviewsubitem-inspect-tile-view-tree]

If the number of `Columns` is less than the number of `ListViewSubItems`, then only `ListViewSubItems` with corresponding `Columns` are displayed. The rest of the `ListViewSubItems` are hidden both on the screen and in the Accessibility tree.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));

listView.TileSize = new Size(100, 100);  
```

![listviewsubitem-twocolumns-inspect-tile-view-tree][listviewsubitem-twocolumns-inspect-tile-view-tree]

If the number of `ListViewSubItems` is less than the number of `Columns`, then only existing `ListViewSubItems` are displayed in the Accessibility tree (as opposed to the `Details` view), since nonexistent `ListViewSubItems` are not displayed on the screen and the user cannot interact with them.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22" }, imageIndex: 0));

listView.TileSize = new Size(100, 100);  
```

![listviewsubitem-threeitems-inspect-tile-view-tree][listviewsubitem-threeitems-inspect-tile-view-tree]

If the [TileSize](https://docs.microsoft.com/dotnet/api/system.windows.forms.listview.tilesize) of the `ListViewItem` is too small, then only those `ListViewSubItems` that are included in the visible area of ​​the `ListViewItem` are displayed. The rest of the `ListViewSubItems` are hidden both on the screen and in the Accessibility tree.

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));

listView.TileSize = new Size(100, 40);  
```

![listviewsubitem-smallsize-inspect-tile-view-tree][listviewsubitem-smallsize-inspect-tile-view-tree]

`ListViewSubItems` are not displayed when [visual styles](https://docs.microsoft.com/dotnet/api/system.windows.forms.application.enablevisualstyles) are disabled for an application. As a result, `ListViewSubItems` are also hidden in the Accessibility tree

```cs
listView.Columns.Add(new ColumnHeader { Text = "Column 1" });
listView.Columns.Add(new ColumnHeader { Text = "Column 2" });
listView.Columns.Add(new ColumnHeader { Text = "Column 3" });
listView.Columns.Add(new ColumnHeader { Text = "Column 4" });

listView.Items.Add(new ListViewItem(new string[] { "Item 1", "SubItem 11", "SubItem 12", "SubItem 13" }, imageIndex: 0));
listView.Items.Add(new ListViewItem(new string[] { "Item 2", "SubItem 21", "SubItem 22", "SubItem 23" }, imageIndex: 0));

listView.TileSize = new Size(100, 100);  
```

![listviewsubitem-disabledvisualstyles-inspect-tile-view-tree][listviewsubitem-disabledvisualstyles-inspect-tile-view-tree]

[listview-inspect-details-view-tree]: ../images/listview-inspect-details-view-tree.png
[listview-inspect-largeicon-view-tree]: ../images/listview-inspect-largeicon-view-tree.png
[listview-inspect-list-view-tree]: ../images/listview-inspect-list-view-tree.png
[listview-inspect-smallicon-view-tree]: ../images/listview-inspect-smallicon-view-tree.png
[listview-inspect-tile-view-tree]: ../images/listview-inspect-tile-view-tree.png
[listview-withgroup-inspect-details-view-tree]: ../images/listview-withgroup-inspect-details-view-tree.png
[listview-withgroup-inspect-largeicon-view-tree]: ../images/listview-withgroup-inspect-largeicon-view-tree.png
[listview-withgroup-inspect-list-view-tree]: ../images/listview-withgroup-inspect-list-view-tree.png
[listview-withgroup-inspect-smallicon-view-tree]: ../images/listview-withgroup-inspect-smallicon-view-tree.png
[listview-withgroup-inspect-tile-view-tree]: ../images/listview-withgroup-inspect-tile-view-tree.png
[listview-disabledstyles-inspect-details-view-tree]: ../images/listview-disabledstyles-inspect-details-view-tree.png
[listview-disabledstyles-inspect-largeicon-view-tree]: ../images/listview-disabledstyles-inspect-largeicon-view-tree.png
[listview-disabledstyles-inspect-list-view-tree]: ../images/listview-disabledstyles-inspect-list-view-tree.png
[listview-disabledstyles-inspect-smallicon-view-tree]: ../images/listview-disabledstyles-inspect-smallicon-view-tree.png
[listview-disabledstyles-inspect-tile-view-tree]: ../images/listview-disabledstyles-inspect-tile-view-tree.png
[listview-showgroupdisabled-inspect-details-view-tree]: ../images/listview-showgroupdisabled-inspect-details-view-tree.png
[listview-showgroupdisabled-inspect-largeicon-view-tree]: ../images/listview-showgroupdisabled-inspect-largeicon-view-tree.png
[listview-showgroupdisabled-inspect-list-view-tree]: ../images/listview-showgroupdisabled-inspect-list-view-tree.png
[listview-showgroupdisabled-inspect-smallicon-view-tree]: ../images/listview-showgroupdisabled-inspect-smallicon-view-tree.png
[listview-showgroupdisabled-inspect-tile-view-tree]: ../images/listview-showgroupdisabled-inspect-tile-view-tree.png
[listview-withoutgroup-inspect-details-view-tree]: ../images/listview-withoutgroup-inspect-details-view-tree.png
[listview-withoutgroup-inspect-largeicon-view-tree]: ../images/listview-withoutgroup-inspect-largeicon-view-tree.png
[listview-withoutgroup-inspect-list-view-tree]: ../images/listview-withoutgroup-inspect-list-view-tree.png
[listview-withoutgroup-inspect-smallicon-view-tree]: ../images/listview-withoutgroup-inspect-smallicon-view-tree.png
[listview-withoutgroup-inspect-tile-view-tree]: ../images/listview-withoutgroup-inspect-tile-view-tree.png
[listview-virtualmode-inspect-details-view-tree]: ../images/listview-virtualmode-inspect-details-view-tree.png
[listview-virtualmode-inspect-largeicon-view-tree]: ../images/listview-virtualmode-inspect-largeicon-view-tree.png
[listview-virtualmode-inspect-list-view-tree]: ../images/listview-virtualmode-inspect-list-view-tree.png
[listview-virtualmode-inspect-smallicon-view-tree]: ../images/listview-virtualmode-inspect-smallicon-view-tree.png
[listviewsubitem-inspect-details-view-tree]: ../images/listviewsubitem-inspect-details-view-tree.png
[listviewsubitem-inspect-largeicon-view-tree]: ../images/listviewsubitem-inspect-largeicon-view-tree.png
[listviewsubitem-inspect-list-view-tree]: ../images/listviewsubitem-inspect-list-view-tree.png
[listviewsubitem-inspect-smallicon-view-tree]: ../images/listviewsubitem-inspect-smallicon-view-tree.png
[listviewsubitem-inspect-tile-view-tree]: ../images/listviewsubitem-inspect-tile-view-tree.png
[listviewsubitem-twocolumns-inspect-details-view-tree]: ../images/listviewsubitem-twocolumns-inspect-details-view-tree.png
[listviewsubitem-twosubitems-inspect-details-view-tree]: ../images/listviewsubitem-twosubitems-inspect-details-view-tree.png
[listviewsubitem-twocolumns-inspect-tile-view-tree]: ../images/listviewsubitem-twocolumns-inspect-tile-view-tree.png
[listviewsubitem-threeitems-inspect-tile-view-tree]: ../images/listviewsubitem-threeitems-inspect-tile-view-tree.png
[listviewsubitem-smallsize-inspect-tile-view-tree]: ../images/listviewsubitem-smallsize-inspect-tile-view-tree.png
[listviewsubitem-disabledvisualstyles-inspect-tile-view-tree]: ../images/listviewsubitem-disabledvisualstyles-inspect-tile-view-tree.png

---

### Accessibility Monthcalendar Expected Behavior (`docs/accessibility/monthcalendar-expected-behavior.md`)

# MonthCalendarAccessibleObject expected properties and behavior

This document describes the expected behavior of `MonthCalendarAccessibleObject` 
when using accessibility tools such as Inspect, Narrator or Accessibility Insights, and 
expected accessibility properties of all visible items 
of the [MonthCalendar control](https://docs.microsoft.com/dotnet/api/system.windows.forms.monthcalendar).


- [Overview](#Overview)
- [Accessibility Tools](#Accessibility-Tools)
    - [Inspect](#Inspect)
        - [Accessibility tree](##Accessibility-tree)
        - [Accessibility properties](##Accessibility-properties)
        - [Accessibility actions](##Accessibility-actions)
        - [ElementProviderFromPoint (get an item when hovering by mouse) behavior](##ElementProviderFromPoint-(get-an-item-when-hovering-by-mouse)-behavior)   
    - [Narrator](#Narrator)
    - [AccessibilityInsights](#AccessibilityInsights)
- [Behavior test cases](#Behavior-test-cases)
- [Additional dev points that don't affect users](#Additional-dev-points-that-don't-affect-users)
    

# Overview

[MonthCalendar](https://docs.microsoft.com/dotnet/api/system.windows.forms.monthcalendar) is a native Windows control, wrapped by Windows Forms SDK. Windows Forms provide a [UIA support](https://docs.microsoft.com/dotnet/framework/ui-automation/ui-automation-overview) for all
MonthCalendar accessible objects and their children making the MonthCalendar control accessible for Windows Forms end users.

Expected properties and actions of a MonthCalendar and its parts in different accessibility tools are listed below.
:point_up: A checked item means that the current implementation provides the full support, and the unchecked item means the expected implementation is currently unavailable.

# Accessibility Tools

## Inspect

### Accessibility tree

MonthCalendar accessibility tree must contain all visible items based on its view.

<details>
<summary>1. Month view</summary>

![monthcalendar-inspect-month-view-tree][monthcalendar-inspect-month-view-tree]

</details>
</br>

<details>
<summary>2. Year view</summary>

![monthcalendar-inspect-year-view-tree][monthcalendar-inspect-year-view-tree]

</details>
</br>

<details>
<summary>3. Decade view</summary>

![monthcalendar-inspect-decade-view-tree][monthcalendar-inspect-decade-view-tree]

</details>
</br>

<details>
<summary>4. Century view</summary>

![monthcalendar-inspect-century-view-tree][monthcalendar-inspect-century-view-tree]

</details>
</br>

### Accessibility properties


<details>
<summary>1. Month view</summary>
</br>

MonthCalendar:
- [x] `ControlType` = "calendar" always
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `HasKeyboardFocus` = `true`, if the control is in focus
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `HelpText` = "MonthCalendar(Control)"
- [x] Correct grid Column and Row count
- [x] `Name` is empty, if it is not set
- [x] `Role` = "table"
- [x] `Value` = selected dates (e.g. "Saturday, April 10, 2021 - Wednesday, April 14, 2021")
- [x] Column and row headers = `null`
- [x] `State` = "focusable" + "focused", if the control is in focus
- [x] Supports Grid, LegacyIAccessible, Table, Value patterns

Previous/Next buttons:
- [x] `Name` = "Previous" or "Next"
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled and there are next/previous calendars
- [x] `HasKeyboardFocus` = `false`
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Today button:
- [x] `Name` = a button text (e.g. "Today: 3/20/2021")
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `HasKeyboardFocus` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar:
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "pane"
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] Has correct GridItem properties
- [x] `Role` == "client"
- [x] `State` = "focusable, selectable" + has "focused", "selected", if the calendar contains the focused cell
- [x] Doesn't have TableItems columns and rows
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

Calendar header button:
- [x] `Name` = the button text (e.g. "March 2021")
- [x] `HasKeyboardFocus` = `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `DefaultAction` = "Click"
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar body:
- [x] `Name` = the header text (e.g. March 2021)
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "table"
- [x] Correct grid Column and Row count (headers are not included)
- [x] `Role` = "table"
- [x] `State` = "default"
- [x] Supports Grid, LegacyIAccessible, Table patterns

Calendar row:
- [x] `Name` is empty
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the row contains the focused cell
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `ControlType` = "pane"
- [x] `Role` = "row"
- [x] `State` = "normal"
- [x] `Description` = "Week {number}" for date rows. `Description` is empty for a header row
- [x] Supports LegacyIAccessible pattern

Cell of the header row (day of week):
- [x] `Name` = the cell text (e.g. "Mon" or "Fri")
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "header"
- [x] `HasKeyboardFocus` = always `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `Role` = "column header"
- [x] `State` = "normal"
- [x] Doesn't have a `Description`
- [x] Doesn't have a `DefaultAction`
- [x] Supports LegacyIAccessible pattern

The first cell of date rows (week number):
- [x] `Name` = "Week {the cell text}" (e.g. "Week 12" or "Week 36" - a week number)
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "header"
- [x] `HasKeyboardFocus` = always `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `Role` = "row header"
- [x] `State` = "normal"
- [x] Doesn't have a `Description`
- [x] Doesn't have a `DefaultAction`
- [x] Supports LegacyIAccessible pattern

Date cell:
- [x] `Name` = the day long name (e.g. "Wednesday, July 14, 2021")
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "DataItem" ("item" in the accessibility tree)
- [x] `HasKeyboardFocus` = `true`, if the cell is focused and the control in focus
- [x] `IsKeyboardFocusable` = `true`, if the control is enabled
- [x] Correct GridItem pattern properties
- [x] `Description` = "Week {number}, {day of week}" (e.g. "Week 10, Friday")
- [x] `DefaultAction` = "Click"
- [x] `Role` = "cell"
- [x] `State` = "focusable, selectable", if the control is enabled (the order of the states doesn't matter), <br/>
              "selected, focusable, selectable", if the cell is selected, <br/>
              "focused, selected, focusable, selectable", if the cell is selected and focused. <br/>
              :warning: Important point: if a user selects several cells, all of them should have "selected" state, but only one of them should have "focused" state.
- [x] Correct TableItem column and row headers items
- [x] Supports Invoke, GridItem, LegacyIAccessible, TableItem patterns

</details>
</br>

<details>
<summary>2. Year view</summary>
</br>

MonthCalendar:
- [x] `ControlType` = "calendar" always
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `HasKeyboardFocus` = `true`, if the control is in focus
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `HelpText` = "MonthCalendar(Control)"
- [x] Correct grid Column and Row count
- [x] `Name` is empty, if it is not set
- [x] `Role` = "table"
- [x] `Value` = a selected month (e.g. "September 2022")
- [x] Column and row headers = null
- [x] `State` = "focusable" + "focused" if the control is in focus
- [x] Supports Grid, LegacyIAccessible, Table, Value patterns

Previous/Next buttons:
- [x] `Name` = "Previous" or "Next"
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled and there are next/previous calendars
- [x] `HasKeyboardFocus` = `false`
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Today button:
- [x] `Name` = a button text (e.g. "Today: 3/20/2021")
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `HasKeyboardFocus` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar:
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "pane"
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] Has correct GridItem properties
- [x] `Role` == "client"
- [x] `State` = "focusable, selectable" + has "focused", "selected", if the calendar contains the focused cell
- [x] Doesn't have TableItems columns and rows
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

Calendar header button:
- [x] `Name` = the button text (e.g. "2021")
- [x] `HasKeyboardFocus` = `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar body:
- [x] `Name` = the header text (e.g. "2021")
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "table"
- [x] Correct grid Column and Row count (headers are not included)
- [x] `Role` = "table"
- [x] `State` = "default"
- [x] Supports Grid, LegacyIAccessible, Table patterns

Calendar row:
- [x] `Name` is empty
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the row contains the focused cell
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `ControlType` = "pane"
- [x] `Role` = "row"
- [x] `State` = "normal"
- [x] `Description` is empty
- [x] Supports LegacyIAccessible pattern

Month cell:
- [x] `Name` = the cell text (e.g. "May")
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "DataItem" ("item" in the accessibility tree)
- [x] `HasKeyboardFocus` = `true`, if the cell is focused
- [x] `IsKeyboardFocusable` = `true`, if the control is enabled
- [x] Correct GridItem pattern properties
- [x] `Description` is empty
- [x] `Role` = "cell"
- [x] `State` = "focusable, selectable" if the control is enabled. (the order of the states doesn't matter) <br/>
              "focused, selected, focusable, selectable" if the cell is selected and focused <br/>
	          :warning: Important point: if a user can't select several cells in this view, so only one cell should have "selected" state, and this cell should have "focused" state.
- [x] Doesn't have TableItem column and row headers items 
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

</details>
</br>

<details>
<summary>3. Decade view</summary>
</br>

MonthCalendar:
- [x] `ControlType` = "calendar" always
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `HasKeyboardFocus` = `true`, if the control is in focus
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `HelpText` = "MonthCalendar(Control)"
- [x] Correct grid Column and Row count
- [x] `Name` is empty, if it is not set
- [x] `Role` = "table"
- [x] `Value` = a selected year (e.g. "2022")
- [x] Column and row headers = null
- [x] `State` = "focusable" + "focused" if the control is in focus
- [x] Supports Grid, LegacyIAccessible, Table, Value patterns

Previous/Next buttons:
- [x] `Name` = "Previous" or "Next"
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled and there are next/previous calendars
- [x] `HasKeyboardFocus` = `false`
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Today button:
- [x] `Name` = a button text (e.g. "Today: 3/20/2021")
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `HasKeyboardFocus` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar:
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "pane"
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] Has correct GridItem properties
- [x] `Role` == "client"
- [x] `State` = "focusable, selectable" + has "focused", "selected", if the calendar contains the focused cell
- [x] Doesn't have TableItems columns and rows
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

Calendar header button:
- [x] `Name` = the button text (e.g. "2020-2029")
- [x] `HasKeyboardFocus` = `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar body:
- [x] `Name` = the header text (e.g. "2020-2029")
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "table"
- [x] Correct grid Column and Row count (headers are not included)
- [x] `Role` = "table"
- [x] `State` = "default"
- [x] Supports Grid, LegacyIAccessible, Table patterns

Calendar row:
- [x] `Name` is empty
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the row contains the focused cell
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `ControlType` = "pane"
- [x] `Role` = "row"
- [x] `State` = "normal"
- [x] `Description` is empty
- [x] Supports LegacyIAccessible pattern

Year cell:
- [x] `Name` = the cell text (e.g. "2020")
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "DataItem" ("item" in the accessibility tree)
- [x] `HasKeyboardFocus ` = `true`, if the cell is focused
- [x] `IsKeyboardFocusable` = `true`, if the control is enabled
- [x] Correct GridItem pattern properties
- [x] `Description` is empty
- [x] `Role` = "cell"
- [x] `State` = "focusable, selectable" if the control is enabled. (the order of the states doesn't matter) <br/>
              "focused, selected, focusable, selectable" if the cell is selected and focused <br/>
	          :warning: Important point: if a user can't select several cells in this view, so only one cell should have "selected" state, and this cell should have "focused" state.
- [x] Doesn't have TableItem column and row headers items 
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

</details>
</br>

<details>
<summary>4. Century view</summary>
</br>

MonthCalendar:
- [x] `ControlType` = "calendar" always
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `HasKeyboardFocus` = `true`, if the control is in focus
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `HelpText` = "MonthCalendar(Control)"
- [x] Correct grid Column and Row count
- [x] `Name` is empty, if it is not set
- [x] `Role` = "table"
- [x] `Value` = a selected decade (e.g. "2020-2029")
- [x] Column and row headers = null
- [x] `State` = "focusable" + "focused" if the control is in focus
- [x] Supports Grid, LegacyIAccessible, Table, Value patterns

Previous/Next buttons:
- [x] `Name` = "Previous" or "Next"
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled and there are next/previous calendars
- [x] `HasKeyboardFocus` = `false`
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Today button:
- [x] `Name` = a button text (e.g. "Today: 3/20/2021")
- [x] `ControlType` = "button"
- [x] `IsKeyboardFocusable` = `false`
- [x] `HasKeyboardFocus` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action and description
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar:
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "pane"
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] Has correct GridItem properties
- [x] `Role` == "client"
- [x] `State` = "focusable, selectable" + has "focused", "selected", if the calendar contains the focused cell
- [x] Doesn't have TableItems columns and rows
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

Calendar header button:
- [x] `Name` = the button text (e.g. "2000-2099")
- [x] `HasKeyboardFocus` = `false`
- [x] `IsKeyboardFocusable` = `false`
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] Has a default action
- [x] `Role` = "push button"
- [x] `State` = "normal"
- [x] Supports Invoke and LegacyIAccessible

Calendar body:
- [x] `Name` = the header text (e.g. "2000-2099")
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the calendar contains the focused cell
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "table"
- [x] Correct grid Column and Row count (headers are not included)
- [x] `Role` = "table"
- [x] `State` = "default"
- [x] Supports Grid, LegacyIAccessible, Table patterns

Calendar row:
- [x] `Name` is empty
- [x] `HasKeyboardFocus` = `true`, if the control is in focus and the row contains the focused cell
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `IsKeyboardFocusable` = `true`, if the calendar is enabled
- [x] `ControlType` = "pane"
- [x] `Role` = "row"
- [x] `State` = "normal"
- [x] `Description` is empty
- [x] Supports LegacyIAccessible pattern

Decade cell:
- [x] `Name` = the cell text (e.g. "2020-2029")
- [x] `IsEnabled` = `true`, if the control is enabled
- [x] `ControlType` = "DataItem" ("item" in the accessibility tree)
- [x] `HasKeyboardFocus` = `true`, if the cell is focused
- [x] `IsKeyboardFocusable` = `true`, if the control is enabled
- [x] Correct GridItem pattern properties
- [x] `Description` is empty
- [x] `Role` = "cell"
- [x] `State` = "focusable, selectable" if the control is enabled. (the order of the states doesn't matter) <br/>
          "focused, selected, focusable, selectable" if the cell is selected and focused <br/>
	      :warning: Important point: if a user can't select several cells in this view, so only one cell should have "selected" state, and this cell should have "focused" state.
- [x] Doesn't have TableItem column and row headers items 
- [x] Supports GridItem, LegacyIAccessible, TableItem patterns

</details>
</br>

### Accessibility actions

Here are described accessibility actions of supported patterns.
:point_up: The "Focus" action has unexpected behavior, because when you call it from Inspect,
the testing form loses focus. Then the form gets focus, in this case,
MonthCalendar.OnGotFocus handler works, that raises accessibility focus event for the focused cell accessible object.

<details>
<summary>1. Month view</summary>
</br>

MonthCalendar:
- [x] Focus - focuses on the focused cell
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the previous/next month)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (works in the debug mode only, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [ ] Focus - focuses on the focused cell, if the row contains it. And does nothing, if the row doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Cell of the header row (day of week):
- [ ] Focus - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the header cell is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

The first cell of date rows (week numbers):
- [ ] Focus - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the header cell is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Date cell:
- [x] Focus - focuses on the focused cell
- [x] Invoke.Invoke - clicks the cell (select it)
- [x] LegacyIAccessible.Select - selects the cell
- [x] LegacyIAccessible.DoDefaultAction - selects the cell
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

<details>
<summary>2. Year view</summary>
</br>

MonthCalendar:
- [x] Focus - focuses on the focused cell
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the previous/next month)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (works in the debug mode only, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [ ] Focus - focuses on the focused cell, if the row contains it. And does nothing, if the row doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Month cell:
- [x] Focus - focuses on the focused cell
- [x] Invoke.Invoke - clicks the cell (changes the view)
- [x] LegacyIAccessible.Select - selects the cell
- [x] LegacyIAccessible.DoDefaultAction - click the cell
- [x] LegacyIAccessible.SetValue - does nothing


</details>
</br>

<details>
<summary>3. Decade view</summary>
</br>

MonthCalendar:
- [x] Focus - focuses on the focused cell
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the previous/next month)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (works in the debug mode only, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [ ] Focus - focuses on the focused cell, if the row contains it. And does nothing, if the row doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Year cell:
- [x] Focus - focuses on the focused cell
- [x] Invoke.Invoke - clicks the cell (changes the view)
- [x] LegacyIAccessible.Select - selects the cell
- [x] LegacyIAccessible.DoDefaultAction - click the cell
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

<details>
<summary>4. Century view</summary>
</br>

MonthCalendar:
- [x] Focus - focuses on the focused cell
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the previous/next month)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (works in the debug mode only, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [ ] Focus - the button is not keyboard focusable, so does nothing
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Focus - focuses on the focused cell, if the calendar contains it. And does nothing, if the calendar doesn't contain the focused cell 
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [ ] Focus - focuses on the focused cell, if the row contains it. And does nothing, if the row doesn't contain the focused cell 
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Decade cell:
- [x] Focus - focuses on the focused cell
- [x] Invoke.Invoke - clicks the cell (changes the view)
- [x] LegacyIAccessible.Select - selects the cell
- [x] LegacyIAccessible.DoDefaultAction - click the cell
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

### ElementProviderFromPoint (get an item when hovering by mouse) behavior

- [x] Returns a MonthCalendar accessible object, if mouse isn't hovering any element
- [x] Returns a "Previous" button accessible object, if mouse is hovering it
- [x] Returns a "Next" button accessible object, if mouse is hovering it
- [x] Returns a "Today" button accessible object, if mouse is hovering the "Today" text, or to the right of the text
- [x] Returns a calendar header button accessible object (e.g. "March 2021"), if mouse is hovering it
- [x] Returns a day of week cell accessible object (e.g. "Sat"), if its MonthCalendar is in the Month view and mouse is hovering it
- [x] Returns a week number cell accessible object (e.g. "18"), if 
    - `ShowWeekNumber` = `true`, 
    - its MonthCalendar is in the Month view
    - mouse is hovering this cell
- [x] Returns a day/month/year/years cell accessible object, if this cell is visible, and mouse is hovering it
- [x] Returns an accessible object of a gray cell of the next/previous calendar, if it is, and if mouse is hovering it <details><summary>Screenshot</summary>![monthcalendar-gray-dates-accessible-from-point][monthcalendar-gray-dates-accessible-from-point]</details>
- [x] Returns a calendar accessible object, if its Bounds contains mouse coordinates, and if there is no any cell in this point <details><summary>Screenshot</summary>![monthcalendar-calendar-accessible-from-point][monthcalendar-calendar-accessible-from-point]</details>
- [x] Returns a MonthCalendar accessible object, if `MaxDate` and `MinDate` are set, and several months are missing there (they are invisible) and if mouse is hovering some invisible calendar <details><summary>Screenshot</summary>![monthcalendar-control-accessible-from-point][monthcalendar-control-accessible-from-point]</details>
- [x] Returns an accessible object of the first week number of a calendar, if mouse is hovering it, and if the calendar first row is partial (a specific case - there is a workaround that fixes a bug of Win API) <details><summary>Screenshot</summary>![monthcalendar-first-weeknumber-accessible-from-point][monthcalendar-first-weeknumber-accessible-from-point]</details>
- [x] Doesn't return week number cells accessible objects of the last calendar, if `MaxDate` is set, and mouse is hovering them <details><summary>Screenshot</summary>![monthcalendar-last-weeknumbers-accessible-from-point][monthcalendar-last-weeknumbers-accessible-from-point]</details>
- [x] Returns a correct accessible object, that is visible, if `MaxDate`, `MinDate`, `FirstDayOfWeek` are changed or the display range is changed via the "Next"/"Previous" buttons

## Narrator

<details>
<summary>1. Month view</summary>
</br>

- [x] Announces dates when moving through them
- [x] Moves through all the accessibility tree nodes in the "Scan" mode
- [ ] Moves through all the accessibility tree nodes in the "Scan" mode after the display range is changed
- [x] Focuses on the focused cell when the control gets focus
- [ ] Focuses on the focused cell, if `MaxDate`, `MinDate`, `FirstDayOfWeek` are changed or the display range is changed via the "Next"/"Previous" buttons

</details>
</br>

<details>
<summary>2. Year view</summary>
</br>

- [x] Announces dates when moving through them
- [x] Moves through all the accessibility tree nodes in the "Scan" mode
- [ ] Moves through all the accessibility tree nodes in the "Scan" mode after the display range is changed
- [x] Focuses on the focused cell when the control gets focus
- [ ] Focuses on the focused cell, if `MaxDate`, `MinDate`, `FirstDayOfWeek` are changed or the display range is changed via the "Next"/"Previous" buttons

</details>
</br>

<details>
<summary>3. Decade view</summary>
</br>

- [x] Announces dates when moving through them
- [x] Moves through all the accessibility tree nodes in the "Scan" mode
- [ ] Moves through all the accessibility tree nodes in the "Scan" mode after the display range is changed
- [x] Focuses on the focused cell when the control gets focus
- [ ] Focuses on the focused cell, if `MaxDate`, `MinDate`, `FirstDayOfWeek` are changed or the display range is changed via the "Next"/"Previous" buttons

</details>
</br>

<details>
<summary>4. Century view</summary>
</br>

- [x] Announces dates when moving through them
- [x] Moves through all the accessibility tree nodes in the "Scan" mode
- [ ] Moves through all the accessibility tree nodes in the "Scan" mode after the display range is changed
- [x] Focuses on the focused cell when the control gets focus
- [ ] Focuses on the focused cell, if `MaxDate`, `MinDate`, `FirstDayOfWeek` are changed or the display range is changed via the "Next"/"Previous" buttons

</details>
</br>

## AccessibilityInsights

<details>
<summary>1. Month view</summary>
</br>

- [x] There are no any AI errors
- [x] The accessibility tree is correct
- [x] AI gets a correct visible accessible object when hovering the mouse (an element from the point)
- [x] AI sees correct item patterns and does supported pattern Actions correctly

MonthCalendar:
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Invoke.Invoke - clicks the button (moves to the previous/next month)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Cell of the header row (day of week):
- [x] LegacyIAccessible.Select - does nothing, because the header cell is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

The first cell of date rows (week numbers):
- [x] LegacyIAccessible.Select - does nothing, because the header cell is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Date cell:
- [x] Invoke.Invoke - clicks the cell (select it)
- [x] LegacyIAccessible.Select - selects the cell
- [ ] LegacyIAccessible.DoDefaultAction - selects the cell (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

<details>
<summary>2. Year view</summary>
</br>

- [x] There are no any AI errors
- [x] The accessibility tree is correct.
- [x] AI gets a correct visible accessible object when hovering the mouse (an element from the point).
- [x] AI sees correct items patterns and does supported pattern Actions correctly:

MonthCalendar:
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Invoke.Invoke - clicks the button (moves to the previous/next month) (AI issue)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Month cell:
- [x] Invoke.Invoke - clicks the cell (select it)
- [x] LegacyIAccessible.Select - selects the cell
- [ ] LegacyIAccessible.DoDefaultAction - selects the cell (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

<details>
<summary>3. Decade view</summary>
</br>

- [x] There are no any AI errors
- [x] The accessibility tree is correct.
- [x] AI gets a correct visible accessible object when hovering the mouse (an element from the point).
- [x] AI sees correct items patterns and does supported pattern Actions correctly:

MonthCalendar:
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Invoke.Invoke - clicks the button (moves to the previous/next month) (AI issue)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Year cell:
- [x] Invoke.Invoke - clicks the cell (select it)
- [x] LegacyIAccessible.Select - selects the cell
- [ ] LegacyIAccessible.DoDefaultAction - selects the cell (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

<details>
<summary>4. Century view</summary>
</br>

- [x] There are no any AI errors
- [x] The accessibility tree is correct.
- [x] AI gets a correct visible accessible object when hovering the mouse (an element from the point).
- [x] AI sees correct items patterns and does supported pattern Actions correctly:

MonthCalendar:
- [ ] Grid.GetItem- returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] Value.SetValue - does nothing
- [x] LegacyIAccessible.Select - does nothing, because the MonthCalendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Previous/Next buttons:
- [ ] Invoke.Invoke - clicks the button (moves to the previous/next month) (AI issue)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [ ] LegacyIAccessible.DoDefaultAction - clicks the button (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

Today button:
- [x] Invoke.Invoke - clicks the button (moves to the today cell)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar:
- [x] LegacyIAccessible.Select - does nothing, because the calendar is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar header button:
- [x] Invoke.Invoke - clicks the button (changes the calendar view)
- [x] LegacyIAccessible.Select - does nothing, because the button is not selectable
- [x] LegacyIAccessible.DoDefaultAction - clicks the button (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.SetValue - does nothing

Calendar body:
- [ ] Grid.GetItem - returns OK for the correct row and column, returns FAIL for incorrect arguments (doesn't work, it's Inspect Issue)
- [x] LegacyIAccessible.Select - does nothing, because the body is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Calendar row:
- [x] LegacyIAccessible.Select - does nothing, because the row is not selectable
- [x] LegacyIAccessible.DoDefaultAction - does nothing
- [x] LegacyIAccessible.SetValue - does nothing

Decade cell:
- [x] Invoke.Invoke - clicks the cell (select it)
- [x] LegacyIAccessible.Select - selects the cell
- [ ] LegacyIAccessible.DoDefaultAction - selects the cell (AI issue)
- [x] LegacyIAccessible.SetValue - does nothing

</details>
</br>

# Behavior test cases

<details>
<summary>1. Month view</summary>
</br>

- [x] **Case:** Change the Today date (set `TodayDate` of a MonthCalendar)
</br>**Expected:** Nothing happens
- [x] **Case:** Click on a gray date cell (of the next or previous calendars)
</br>**Expected:** The monthCalendar changes the display range. Its accessibility tree rebuilds.
- [x] **Case:** Size of the control is changed that the control changes calendars count
</br>**Expected:** The accessibility tree is rebuilt. ElementProviderFromPoint returns visible items correctly
- [x] **Case:** A calendar of a MonthCalendar has non-full rows
</br>**Expected:** Inspect sees only visible items in that row
- [x] **Case:** A calendar of a MonthCalendar has some empty rows
</br>**Expected:** These rows are not in the accessibility tree
- [x] **Case:** The first week number cell in the first calendar in a MonthCalendar is in a non-full row
</br>**Expected:** Inspect sees that cell correctly with the correct name
- [x] **Case:** The last week number cells of the last non-full calendar have the same values for empty rows
</br>**Expected:** They are not in the accessibility tree
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to right, thereby the focused cell 
will be in right (e.g. 15th of September). Set `MinDate` of the calendar less then the selected range (e.g. 1st of September).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to left, thereby the focused cell 
will be in left (e.g. 10th of September). Set `MinDate` of the calendar less then the selected range (e.g. 1st of September).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to right, thereby the focused cell 
will be in right (e.g. 15th of September). Set `MaxDate` of the calendar more then the selected range (e.g. 20th of September).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to left, thereby the focused cell 
will be in left (e.g. 10th of September). Set `MaxDate` of the calendar more then the selected range (e.g. 20th of September).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to right, thereby the focused cell 
will be in right (e.g. 15th of September). Set `MinDate` of the calendar more then the start of the selected range, 
but less then the end of the selected range (e.g. 13th of September).
</br>**Expected:** The selected range changes. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to left, thereby the focused cell 
will be in left (e.g. 10th of September). Set `MinDate` of the calendar more then the start of the selected range, 
but less then the end of the selected range (e.g. 13th of September).
</br>**Expected:** The selected range changes. The focused cell changes (13th of September). 
The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to right, thereby the focused cell 
will be in right (e.g. 15th of September). Set `MaxDate` of the calendar more then the start of the selected range, 
but less then the end of the selected range (e.g. 13th of September).
</br>**Expected:** The selected range changes. The focused cell changes (13th of September). 
The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to left, thereby the focused cell 
will be in left (e.g. 10th of September). Set `MaxDate` of the calendar more then the start of the selected range, 
but less then the end of the selected range (e.g. 13th of September).
</br>**Expected:** The selected range changes. The focused cell cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to right, thereby the focused cell 
will be in right (e.g. 15th of September). Set new `FirstDayOfWeek` (e.g. Friday).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select some dates (e.g. 10-15th of September), move to left, thereby the focused cell 
will be in left (e.g. 10th of September). Set new `FirstDayOfWeek` (e.g. Friday).
</br>**Expected:** The selected range doesn't change. The focused cell doesn't change. 
The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** `MinDate` is more then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** `MaxDate` is less then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** A MonthCalendar has 1 calendar.
</br>**Expected:** Accessibility tree has 1 calendar.
- [x] **Case:** A MonthCalendar has several calendars. 
</br>**Expected:** Accessibility tree has the same count of calendars.
- [x] **Case:** `MinDate` is set for a MonthCalendar. 
</br>**Expected:** Dates before `MinDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` is set for a MonthCalendar. 
</br>**Expected:** Dates after `MaxDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a more date range then the display range of the MonthCalendar.
</br>**Expected:** Accessibility tree has all visible calendars. All dates are accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a less date range then the display range of the MonthCalendar. 
Thereby the MonthCalendar has several partially visible calendars 
(e.g. the MonthCalendar can contain 6 calendars, but 3 of them are visible due `MinDate` and `MinDate`). 
</br>**Expected:** Accessibility tree has the count of visible calendars only (e.g. 3).
Invisible calendars are not accessible. Invisible dates of partial calendars are not accessible.

</details>
</br>

<details>
<summary>2. Year view</summary>
</br>

- [x] **Case:** Change the Today date (set `TodayDate` of a MonthCalendar)
</br>**Expected:** Nothing happens
- [x] **Case:** Click on a gray month cell (of the next or previous calendars)
</br>**Expected:** The monthCalendar changes the display range. It accessibility tree rebuilds.
- [x] **Case:** Size of the control is changed that the control changes calendars count
</br>**Expected:** The accessibility tree is rebuilt. ElementProviderFromPoint returns visible items correctly
- [x] **Case:** A calendar of a MonthCalendar has non-full rows
</br>**Expected:** Inspect sees only visible items in that row
- [x] **Case:** A calendar of a MonthCalendar has some empty rows
</br>**Expected:** These rows are not in the accessibility tree
- [x] **Case:** There are no week number and day of week cells in calendars
</br>**Expected:** There are no any invisible items (week number and day of week cells) in the accessibility tree
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar less then the selected cell (e.g. 1st of June).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar more then the selected cell (e.g. 1st of December).
</br>**Expected:** The focused cell changes (e.g. December). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar less then the selected cell (e.g. 1st of June).
</br>**Expected:** The focused cell changes (e.g. June). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar more then the selected cell (e.g. 1st of December).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar with the same month (e.g. 30th of September).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. September), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar with the same month (e.g. 1st of September).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** `MinDate` is more then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** `MaxDate` is less then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** A MonthCalendar has 1 calendar.
</br>**Expected:** Accessibility tree has 1 calendar.
- [x] **Case:** A MonthCalendar has several calendars. 
</br>**Expected:** Accessibility tree has the same count of calendars.
- [x]  **Case:** `MinDate` is set for a MonthCalendar. 
</br>**Expected:** Dates before `MinDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` is set for a MonthCalendar. 
</br>**Expected:** Dates after `MaxDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a more date range then the display range of the MonthCalendar.
</br>**Expected:** Accessibility tree has all visible calendars. All dates are accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a less date range then the display range of the MonthCalendar. 
Thereby the MonthCalendar has several partially visible calendars 
(e.g. the MonthCalendar can contain 6 calendars, but 3 of them are visible due `MinDate` and `MinDate`). 
</br>**Expected:** Accessibility tree has the count of visible calendars only (e.g. 3).
Invisible calendars are not accessible. Invisible dates of partial calendars are not accessible.

</details>
</br>

<details>
<summary>3. Decade view</summary>
</br>

- [x] **Case:** Change the Today date (set `TodayDate` of a MonthCalendar)
</br>**Expected:** Nothing happens
- [x] **Case:** Click on a gray year cell (of the next or previous calendars)
</br>**Expected:** The monthCalendar changes the display range. It accessibility tree rebuilds.
- [x] **Case:** Size of the control is changed that the control changes calendars count
</br>**Expected:** The accessibility tree is rebuilt. ElementProviderFromPoint returns visible items correctly
- [x] **Case:** A calendar of a MonthCalendar has non-full rows
</br>**Expected:** Inspect sees only visible items in that row
- [x] **Case:** A calendar of a MonthCalendar has some empty rows
</br>**Expected:** These rows are not in the accessibility tree
- [x] **Case:** There are no week number and day of week cells in calendars
</br>**Expected:** There are no any invisible items (week number and day of week cells) in the accessibility tree
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar less then the selected cell (e.g. 1st of June 2019).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar more then the selected cell (e.g. 1st of December 2021).
</br>**Expected:** The focused cell changes (e.g. 2021). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar less then the selected cell (e.g. 1st of June 2019).
</br>**Expected:** The focused cell changes (e.g. 2019). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar more then the selected cell (e.g. 1st of December 2021).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar with the same year (e.g. 31th of December 2020).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar with the same year (e.g. 1st of January 2020).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** `MinDate` is more then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** `MaxDate` is less then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** A MonthCalendar has 1 calendar.
</br>**Expected:** Accessibility tree has 1 calendar.
- [x] **Case:** A MonthCalendar has several calendars. 
</br>**Expected:** Accessibility tree has the same count of calendars.
- [x] **Case:** `MinDate` is set for a MonthCalendar. 
</br>**Expected:** Dates before `MinDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` is set for a MonthCalendar. 
</br>**Expected:** Dates after `MaxDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a more date range then the display range of the MonthCalendar.
</br>**Expected:** Accessibility tree has all visible calendars. All dates are accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a less date range then the display range of the MonthCalendar. 
Thereby the MonthCalendar has several partially visible calendars 
(e.g. the MonthCalendar can contain 6 calendars, but 3 of them are visible due `MinDate` and `MinDate`). 
</br>**Expected:** Accessibility tree has the count of visible calendars only (e.g. 3).
Invisible calendars are not accessible. Invisible dates of partial calendars are not accessible.

</details>
</br>

<details>
<summary>4. Century view</summary>
</br>

- [x] **Case:** Change the Today date (set `TodayDate` of a MonthCalendar)
</br>**Expected:** Nothing happens
- [x] **Case:** Click on a gray decade cell (of the next or previous calendars)
</br>**Expected:** The monthCalendar changes the display range. It accessibility tree rebuilds.
- [x] **Case:** Size of the control is changed that the control changes calendars count
</br>**Expected:** The accessibility tree is rebuilt. ElementProviderFromPoint returns visible items correctly
- [x] **Case:** A calendar of a MonthCalendar has non-full rows
</br>**Expected:** Inspect sees only visible items in that row
- [x] **Case:** A calendar of a MonthCalendar has some empty rows
</br>**Expected:** These rows are not in the accessibility tree
- [x] **Case:** There are no week number and day of week cells in calendars
</br>**Expected:** There are no any invisible items (week number and day of week cells) in the accessibility tree
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar less then the selected cell (e.g. 1st of June 2019).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar more then the selected cell (e.g. 1st of December 2021).
</br>**Expected:** The focused cell changes (e.g. 2021). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar less then the selected cell (e.g. 1st of June 2019).
</br>**Expected:** The focused cell changes (e.g. 2019). The new focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar more then the selected cell (e.g. 1st of December 2021).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MinDate` of the calendar with the same year (e.g. 31th of December 2020).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** Select one month cell (e.g. 2020), user can't select several cell in this view, 
so the selected cell is focused. Set `MaxDate` of the calendar with the same year (e.g. 1st of January 2020).
</br>**Expected:** The focused cell doesn't change. The focused cell has "focused" accessibility state (check Inspect).
- [x] **Case:** `MinDate` is more then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** `MaxDate` is less then the selected range. 
</br>**Expected:** The focused cell changes. The new focused cell has "focused" accessibility state.
- [x] **Case:** A MonthCalendar has 1 calendar.
</br>**Expected:** Accessibility tree has 1 calendar.
- [x] **Case:** A MonthCalendar has several calendars. 
</br>**Expected:** Accessibility tree has the same count of calendars.
- [x] **Case:** `MinDate` is set for a MonthCalendar. 
</br>**Expected:** Dates before `MinDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` is set for a MonthCalendar. 
</br>**Expected:** Dates after `MaxDate` are invisible and are not accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a more date range then the display range of the MonthCalendar.
</br>**Expected:** Accessibility tree has all visible calendars. All dates are accessible.
- [x] **Case:** `MaxDate` and `MinDate` are set for a MonthCalendar. 
They are has a less date range then the display range of the MonthCalendar. 
Thereby the MonthCalendar has several partially visible calendars 
(e.g. the MonthCalendar can contain 6 calendars, but 3 of them are visible due `MinDate` and `MinDate`). 
</br>**Expected:** Accessibility tree has the count of visible calendars only (e.g. 3).
Invisible calendars are not accessible. Invisible dates of partial calendars are not accessible.

</details>
</br>

# Additional dev points that don't affect users

- Rebuild the accessibility tree, if the calendar `View`, `MaxDate`, `MinDate`, `TodayDate`, `Size` are changed
or Next or Previous buttons are clicked (i.e. the display range is changed).
- Invoke method of button accessible objects of MonthCalendar simulates mouse moving, clicks and then returns the mouse position back.
Windows doesn't provide API to simulate  MonthCalendar buttons clicks via messages.

[monthcalendar-inspect-month-view-tree]: ../images/monthcalendar-inspect-month-view-tree.png
[monthcalendar-inspect-year-view-tree]: ../images/monthcalendar-inspect-year-view-tree.png
[monthcalendar-inspect-decade-view-tree]: ../images/monthcalendar-inspect-decade-view-tree.png
[monthcalendar-inspect-century-view-tree]: ../images/monthcalendar-inspect-century-view-tree.png
[monthcalendar-gray-dates-accessible-from-point]: ../images/monthcalendar-gray-dates-accessible-from-point.png
[monthcalendar-calendar-accessible-from-point]: ../images/monthcalendar-calendar-accessible-from-point.png
[monthcalendar-control-accessible-from-point]: ../images/monthcalendar-control-accessible-from-point.png
[monthcalendar-first-weeknumber-accessible-from-point]: ../images/monthcalendar-first-weeknumber-accessible-from-point.png
[monthcalendar-last-weeknumbers-accessible-from-point]: ../images/monthcalendar-last-weeknumbers-accessible-from-point.png

---

### Analyzers AppManifestAnalyzer.Help (`docs/analyzers/AppManifestAnalyzer.Help.md`)

# How to use System.Windows.Forms.Analyzers

System.Windows.Forms.Analyzers analyzers and source generators are shipped inbox with Windows Desktop .NET SDK, and
are automatically referenced for Window Forms .NET applications.

## `AppManifestAnalyzer`

`AppManifestAnalyzer` is automatically invoked when a Windows Forms application (`OutputType=Exe` or `OutputType=WinExe`) has a custom app.manifest.

## [WFO0003](https://aka.ms/winforms-warnings/wfo0003): Unsupported high DPI configuration.

Windows Forms applications should specify application DPI-awareness via the [application configuration](https://aka.ms/applicationconfiguration) or
[`Application.SetHighDpiMode` API](https://learn.microsoft.com/dotnet/api/system.windows.forms.application.sethighdpimode).

In NET6.0 the same warning was shipped with ID `WFAC010`.

| Item      | Value                    |
|-----------|--------------------------|
| Category  | ApplicationConfiguration |
| Enabled   | True                     |
| Severity  | Warning                  |
| CodeFix   | False                    |
| Changed in| NET9.0                   |

---

---

### Analyzers ApplicationConfigurationGenerator.Help (`docs/analyzers/ApplicationConfigurationGenerator.Help.md`)

# How to use System.Windows.Forms.Analyzers.CSharp

System.Windows.Forms.Analyzers.CSharp analyzers and source generators are shipped inbox with Windows Desktop .NET SDK, and
are automatically referenced for Window Forms .NET applications.

## `ApplicationConfigurationGenerator`

`ApplicationConfigurationGenerator` is automatically invoked when `ApplicationConfiguration.Initialize()` call is detected,
and it emits the application bootstrap code such as:
```cs
public static void Initialize()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.SetHighDpiMode(HighDpiMode.SystemAware);
}
```

For more information on application configuration refer to https://aka.ms/applicationconfiguration.

## [WFO0001](https://aka.ms/winforms-warnings/wfo0001): Unsupported project type.

Only projects with `OutputType` set to "Exe" or "WinExe" are supported, because only applications projects define an application entry point,
where the application bootstrap code must reside.

In NET6.0 the same error was shipped with ID `WFAC001`.

| Item      | Value                      |
|-----------|----------------------------|
| Category  | ApplicationConfiguration   |
| Enabled   | True                       |
| Severity  | Error                      |
| CodeFix   | False                      |
| Changed in| NET9.0                     |

---

## [WFO0002](https://aka.ms/winforms-warnings/wfo0002): Unsupported property value.

The specified project property cannot be set to the given value.
In NET6.0 the same error was shipped with ID `WFAC002`.

| Item      | Value                      |
|-----------|----------------------------|
| Category  | ApplicationConfiguration   |
| Enabled   | True                       |
| Severity  | Error                      |
| CodeFix   | False                      |
| Changed in| NET9.0                     |

---

---

### Analyzers Experimental.Help (`docs/analyzers/Experimental.Help.md`)

# List of WinForms Experimental Function Areas

System.Windows.Forms.Analyzers analyzers and source generators are shipped inbox with Windows Desktop .NET SDK, and
are automatically referenced for Window Forms .NET applications.

| Diagnostic ID  | Description |
| :------------- | :---------- |
|  __`WFO5001`__ | Functionality around Dark Mode Colors is experimental in .NET 9. |
|  __`WFO5002`__ | New ASync APIs for e.g. consuming Windows projected APIs, WebView2 or AI/LLM Libs are experimental in .NET 9. |

---

### Analyzers WinFormsCSharpAnalyzers.Help (`docs/analyzers/WinFormsCSharpAnalyzers.Help.md`)

# How to use System.Windows.Forms.Analyzers

System.Windows.Forms.Analyzers analyzers and source generators are shipped inbox with Windows Desktop .NET SDK, and
are automatically referenced for Window Forms .NET applications.

## `MissingPropertySerializationConfiguration`

`MissingPropertySerializationConfiguration` checks for missing `DesignerSerializationVisibilityAttribute` on properties of classes which are
derived from `Control` and could potentially serialize design-time data by the designer without the user being aware of it.

### [WFO1000](https://aka.ms/winforms-warnings/wfo1000): Missing property serialization configuration.

Properties of classes derived from `Control` should have `DesignerSerializationVisibilityAttribute` 
set to `DesignerSerializationVisibility.Content` or `DesignerSerializationVisibility.Visible`.

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Security|
| Enabled   | True             |
| Severity  | Error            |
| CodeFix   | False            |
| Added in  | NET9.0           |

---

## `AvoidPassingFuncReturningTaskWithoutCancellationToken`

`AvoidPassingFuncReturningTaskWithoutCancellationToken` checks parameters passed to `Control.InvokeAsync`. It suggests to use a cancellation token when passing a task to these methods.

### [WFO2001](https://aka.ms/winforms-warnings/wfo2001): Task is being passed to InvokeAsync without a cancellation token.

Avoid passing a `Func<T>` to `InvokeAsync` where `T` is a `Task` or `ValueTask`, unless your intention is for the delegate to simply be kicked off as an unsupervised task. Instead, use `Func<CancellationToken, ValueTask>` or `Func<CancellationToken, ValueTask<T>>`, so that the delegate passed to `InvokeAsync` can be awaited, allowing exceptions to be properly handled. 

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Usage   |
| Enabled   | True             |
| Severity  | Warning          |
| CodeFix   | False            |
| Added in  | NET9.0           |

---

## `ImplementITypedDataObject`

`ImplementITypedDataObject` checks custom implementations of the managed `IDataObject` interface and suggests to also implement the `ITypedDataObject` interface.

### [WFO1001](https://aka.ms/winforms-warnings/wfo1001): `IDataObject` type does not implement `ITypedDataObject`.

Types should implement `ITypedDataObject` to support best practices when interacting with data. Types will not work with typed APIs in Clipboard and other data exchange scenarios if they only implement `IDataObject`.

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Security|
| Enabled   | True             |
| Severity  | Warning          |
| CodeFix   | False            |
| Added in  | NET10.0          |

---

## WinForms Designer guardrails

These rules protect the generated partial declaration in `.Designer.cs` files. A file is analyzed only
when it contains an instance, non-generic, parameterless `void InitializeComponent` for a partial type
derived from `System.Windows.Forms.Control` or `System.ComponentModel.Component`, and that same type
also has a declaration in a non-Designer file. Framework symbols are resolved semantically: unrelated
types named `Control` or `Component` do not qualify.

The boundary is design-time round-tripping, not runtime equivalence. CodeDOM cannot express many
modern language constructs, and the WinForms Designer interprets only a subset of the statements
CodeDOM can represent. Keep initialization unrolled: explicit construction, assignments, supported
calls, and named event hookups. Move runtime-only behavior to the user partial after
`InitializeComponent`; do not hide designer initialization in a helper call.

### [WFO3000](https://aka.ms/winforms-warnings/wfo3000): Avoid unsupported code in `InitializeComponent`.

Move loops (including deconstructing `foreach`), conditionals, switch constructs, local functions,
`goto`, exception handling, locking, `using`, and `await` out of generated initialization.
Use a block-bodied `InitializeComponent`, not an expression-bodied method. These restrictions do not
apply to the standard generated `Dispose` override.

### [WFO3001](https://aka.ms/winforms-warnings/wfo3001): Keep custom members out of Designer files.

Move properties, nested types, and custom methods out of the generated partial declaration.
Constructors, `InitializeComponent`, the standard `Dispose(bool)` override, and explicit interface
implementations are allowed.

### [WFO3002](https://aka.ms/winforms-warnings/wfo3002): Keep generated fields at the end of the Designer file.

Keep fields at the end of the Designer partial, except the conventional `IContainer components`
infrastructure. This ordering preserves the historical generated layout; it is not itself a CodeDOM
expression restriction. Component fields constructed in `InitializeComponent` must belong to that
partial. Merely reading a user field does not make it designer-owned, and inherited, static, or
unrelated-type fields must not be moved into it.

### [WFO3003](https://aka.ms/winforms-warnings/wfo3003): Keep event and delegate declarations out of Designer files.

Move event and delegate declarations to the user code file.

### [WFO3004](https://aka.ms/winforms-warnings/wfo3004): Avoid collection expressions in Designer files.

Use syntax supported by Designer serialization instead of C# collection expressions in generated
Designer code, for example `new Control[] { button1, button2 }` or unrolled `Add` calls.

### [WFO3005](https://aka.ms/winforms-warnings/wfo3005): Avoid `nameof` expressions in `InitializeComponent`.

Use the serialized string value instead of `nameof`.

### [WFO3006](https://aka.ms/winforms-warnings/wfo3006): Avoid conditional expressions in `InitializeComponent`.

Move the condition to the user code file and serialize one deterministic value.

### [WFO3007](https://aka.ms/winforms-warnings/wfo3007): Avoid null-coalescing expressions in `InitializeComponent`.

Resolve the fallback outside generated Designer code. This includes both `??` and `??=`.

### [WFO3008](https://aka.ms/winforms-warnings/wfo3008): Avoid null-conditional expressions in `InitializeComponent`.

Move null-dependent access to the user code file.

### [WFO3009](https://aka.ms/winforms-warnings/wfo3009): Avoid interpolated strings in `InitializeComponent`.

Serialize the resulting string value instead of an interpolated expression.

### [WFO3010](https://aka.ms/winforms-warnings/wfo3010): Avoid anonymous functions in `InitializeComponent`.

Use a named event handler in the user code file instead of a lambda or anonymous method.

WFO3005–WFO3010 identify constructs that CodeDOM cannot represent. Their separate IDs allow tools and
agents to apply construct-specific guidance.

| Item      | Value             |
|-----------|-------------------|
| Category  | WinForms Designer |
| Enabled   | True              |
| Severity  | Error (WFO3000, WFO3001, WFO3003, WFO3004, WFO3006–WFO3008, WFO3010); Warning (WFO3002, WFO3005, WFO3009) |
| CodeFix   | False             |
| Added in  | NET11.0           |

---

## `PropertyAllocatesNewInstanceAnalyzer`

### [WFO2000](https://aka.ms/winforms-warnings/wfo2000): Avoid constructing fresh reference instances in property getters.

This is a general usage warning, not a Designer-only restriction. It identifies getter return paths
that directly construct a reference instance, without claiming that every access takes that path.
This includes directly returned arrays and anonymous objects.
Value-type construction, cached and initializer-backed properties, indexers, generated code, and
returns inside nested lambdas/local functions are excluded. User-defined conversions are not treated
as transparent returns. The rule does not perform interprocedural factory analysis.

Cache the instance only when stable identity is intended. For deliberate creation, consider a factory
method if API compatibility permits, or document a narrow suppression. There is no automatic fix:
caching can change ownership, disposal, and threading behavior. In particular, fresh instances from
content-serialized properties can discard property-grid edits instead of preserving designer state.

| Item      | Value          |
|-----------|----------------|
| Category  | WinForms Usage |
| Enabled   | True           |
| Severity  | Warning        |
| CodeFix   | False          |
| Added in  | NET11.0        |

---

---

### Analyzers WinFormsVisualBasicAnalyzers.Help (`docs/analyzers/WinFormsVisualBasicAnalyzers.Help.md`)

# How to use System.Windows.Forms.Analyzers

System.Windows.Forms.Analyzers analyzers and source generators are shipped inbox with Windows Desktop .NET SDK, and
are automatically referenced for Window Forms .NET applications.

## `MissingPropertySerializationConfiguration`

`MissingPropertySerializationConfiguration` checks for missing `DesignerSerializationVisibilityAttribute` on properties of classes which are 
derived from `Control` and could potentially serialize design-time data by the designer without the user being aware of it.

### [WFO1000](https://aka.ms/winforms-warnings/wfo1000): Missing property serialization configuration.

Properties of classes derived from `Control` should have `DesignerSerializationVisibilityAttribute` 
set to `DesignerSerializationVisibility.Content` or `DesignerSerializationVisibility.Visible`.

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Security|
| Enabled   | True             |
| Severity  | Error            |
| CodeFix   | False            |
| Added in  | NET9.0           |

---

## `AvoidPassingFuncReturningTaskWithoutCancellationToken`

`AvoidPassingFuncReturningTaskWithoutCancellationToken` checks parameters passed to `Control.InvokeAsync`. It suggests to use a cancellation token when passing a task to these methods.

### [WFO2001](https://aka.ms/winforms-warnings/wfo2001): Task is being passed to InvokeAsync without a cancellation token.

Avoid passing a `Func<T>` to `InvokeAsync` where `T` is a `Task` or `ValueTask`, unless your intention is for the delegate to simply be kicked off as an unsupervised task. Instead, use `Func<CancellationToken, ValueTask>` or `Func<CancellationToken, ValueTask<T>>`, so that the delegate passed to `InvokeAsync` can be awaited, allowing exceptions to be properly handled. 

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Usage   |
| Enabled   | True             |
| Severity  | Warning          |
| CodeFix   | False            |
| Added in  | NET9.0           |

---

## `ImplementITypedDataObject`

`ImplementITypedDataObject` checks custom implementations of the managed `IDataObject` interface and suggests to also implement the `ITypedDataObject` interface.

### [WFO1001](https://aka.ms/winforms-warnings/wfo1001): `IDataObject` type does not implement `ITypedDataObject`.

Types should implement `ITypedDataObject` to support best practices when interacting with data. Types will not work with typed APIs in Clipboard and other data exchange scenarios if they only implement `IDataObject`.

| Item      | Value            |
|-----------|------------------|
| Category  | WinForms Security|
| Enabled   | True             |
| Severity  | Warning          |
| CodeFix   | False            |
| Added in  | NET10.0          |

---

## WinForms Designer guardrails

These rules protect the generated partial declaration in `.Designer.vb` files. A file is analyzed only
when it contains an instance, non-generic, parameterless `Sub InitializeComponent` for a partial type
derived from `System.Windows.Forms.Control` or `System.ComponentModel.Component`, and that same type
also has a declaration in a non-Designer file. Framework symbols are resolved semantically: unrelated
types named `Control` or `Component` do not qualify. Identifier matching respects VB casing rules and
optional parameter-list parentheses.

The boundary is design-time round-tripping, not runtime equivalence. CodeDOM cannot express many
modern constructs, and the WinForms Designer interprets only a subset of CodeDOM statements.
Keep initialization unrolled and move runtime-only behavior to the user partial after
`InitializeComponent`; do not hide designer initialization behind helper calls.

### [WFO3000](https://aka.ms/winforms-warnings/wfo3000): Avoid unsupported code in `InitializeComponent`.

Move `For`, `For Each`, `While`, `Do`, `If`, `Select`, `GoTo`, `Try`, `SyncLock`, `Using`, and `Await`
out of generated initialization. The standard generated `Dispose` override is intentionally exempt:
its `Try`/`If`/`Finally` structure is valid infrastructure.

### [WFO3001](https://aka.ms/winforms-warnings/wfo3001): Keep custom members out of Designer files.

Move properties, nested types, and custom methods out of the generated partial declaration.
Constructors, `InitializeComponent`, the standard `Dispose(Boolean)` override, and explicit interface
method implementations are allowed.

### [WFO3002](https://aka.ms/winforms-warnings/wfo3002): Keep generated fields at the end of the Designer file.

Keep fields and `WithEvents` declarations at the end of the Designer partial, except the conventional
`IContainer components` infrastructure. This preserves the historical generated layout rather than
enforcing a modern application-code style. Component members constructed in `InitializeComponent`
belong in that partial; merely reading a user field does not make it designer-owned. Inherited and
unrelated-type members must not be moved.

VB `WithEvents` declarations bind as property symbols. They are explicitly handled without treating
ordinary properties as generated fields.

### [WFO3003](https://aka.ms/winforms-warnings/wfo3003): Keep event and delegate declarations out of Designer files.

Move event and delegate declarations to the user code file.

WFO3004 is C#-only because Visual Basic has no collection-expression syntax.

### [WFO3005](https://aka.ms/winforms-warnings/wfo3005): Avoid `NameOf` expressions in `InitializeComponent`.

Use the serialized string value instead of `NameOf`.

### [WFO3006](https://aka.ms/winforms-warnings/wfo3006): Avoid conditional expressions in `InitializeComponent`.

Move the three-argument `If` condition to the user code file and serialize one deterministic value.

### [WFO3007](https://aka.ms/winforms-warnings/wfo3007): Avoid null-coalescing expressions in `InitializeComponent`.

Resolve the two-argument `If` fallback outside generated Designer code.

### [WFO3008](https://aka.ms/winforms-warnings/wfo3008): Avoid null-conditional expressions in `InitializeComponent`.

Move null-dependent access to the user code file.

### [WFO3009](https://aka.ms/winforms-warnings/wfo3009): Avoid interpolated strings in `InitializeComponent`.

Serialize the resulting string value instead of an interpolated expression.

### [WFO3010](https://aka.ms/winforms-warnings/wfo3010): Avoid anonymous functions in `InitializeComponent`.

Use a named event handler in the user partial instead of a lambda. Use `Handles` for designer member
events and `AddressOf` for supported local-component event hookups.

WFO3005–WFO3010 identify constructs that CodeDOM cannot represent. Their separate IDs allow tools and
agents to apply construct-specific guidance.

### [WFO3011](https://aka.ms/winforms-warnings/wfo3011): Declare Designer component members `WithEvents`.

A component member constructed by `InitializeComponent` must use the VB Designer's event model.
For example, keep `Friend WithEvents Button1 As Button` at the end of the Designer partial and put
`Private Sub Button1_Click(...) Handles Button1.Click` in the user partial. The rule does not apply to
the components container, scalar/helper fields, or local variables.

### [WFO3012](https://aka.ms/winforms-warnings/wfo3012): Use `Handles` for Designer member events.

Replace `AddHandler Button1.Click, AddressOf Button1_Click` in `InitializeComponent` with
`Handles Button1.Click` on the named handler in the user partial, without retaining both hookups.
Root events preserve the receiver with `Handles Me.EventName`, `Handles MyBase.EventName`, or
`Handles MyClass.EventName`; inherited `WithEvents` members also support `Handles` without
redeclaring them.

This is not a blanket ban on `AddHandler`. The designer's field-generation setting is named
`GenerateMember`: when it is `False`, components can be locals, and supported
`AddHandler local.Click, AddressOf Handler` wiring remains valid. Arbitrary properties, inherited
plain fields, unrelated receivers, and runtime event wiring outside `InitializeComponent` are not
rewritten into the member model. CodeDOM itself represents event attachment; the restriction protects
VB Designer ownership and event round-tripping.

WFO3011 and WFO3012 are VB-only. No automatic fix is offered because changing declarations and
subscriptions requires preserving captures, accessibility, and existing `Handles` clauses.

| Item      | Value             |
|-----------|-------------------|
| Category  | WinForms Designer |
| Enabled   | True              |
| Severity  | Error (WFO3000, WFO3001, WFO3003, WFO3006–WFO3008, WFO3010–WFO3012); Warning (WFO3002, WFO3005, WFO3009) |
| CodeFix   | False             |
| Added in  | NET11.0           |

---

## `PropertyAllocatesNewInstanceAnalyzer`

### [WFO2000](https://aka.ms/winforms-warnings/wfo2000): Avoid constructing fresh reference instances in property getters.

This remains a general usage warning, not a Designer-only restriction. It identifies getter return
paths that directly construct reference instances, not guaranteed allocation on every access.
This includes directly returned arrays and anonymous objects.
Value types, cached and initializer-backed properties, indexers, generated code, nested lambda
returns, and user-defined conversions are excluded.

Cache only when stable identity is intended. Otherwise consider a factory method when API
compatibility permits, or document a narrow suppression. No automatic fix changes ownership,
disposal, or threading semantics. Content-serialized properties returning fresh instances are a
particular design-time hazard because property-grid edits can be applied to discarded instances.

| Item      | Value          |
|-----------|----------------|
| Category  | WinForms Usage |
| Enabled   | True           |
| Severity  | Warning        |
| CodeFix   | False          |
| Added in  | NET11.0        |

---

---

### Analyzers Akams (`docs/analyzers/akams.md`)

## These mappings are defined in the [redirection manager](https://akalinkmanager.trafficmanager.net/am/redirection/home?options=host:aka.ms)

| Short URL                      | Full URL                                                                                       |
|--------------------------------|------------------------------------------------------------------------------------------------|
| https://aka.ms/WfoGenManifest  | https://github.com/dotnet/winforms/blob/main/docs/analyzers/AppManifestAnalyzer.Help.md         |
| https://aka.ms/WfoExperimental | https://github.com/dotnet/winforms/blob/main/docs/analyzers/Experimental.Help.md                |
| https://aka.ms/WfoCsAppConfig  | https://github.com/dotnet/winforms/blob/main/docs/analyzers/ApplicationConfigurationGenerator.Help.md |
| https://aka.ms/WfoCsAnalyzers  | https://github.com/dotnet/winforms/blob/main/docs/analyzers/WinFormsCSharpAnalyzers.Help.md     |
| https://aka.ms/WfoVbAnalyzers  | https://github.com/dotnet/winforms/blob/main/docs/analyzers/WinFormsVisualBasicAnalyzers.Help.md|

---

### Design Anchor Layout Changes In Net80 (`docs/design/anchor-layout-changes-in-net80.md`)

# Anchor layout changes in .NET 8.0


## Description

We have multiple [issues](https://github.com/dotnet/winforms/issues?q=is%3Aissue+is%3Aopen+anchor+label%3A%22area%3A+anchor%2Fscaling%22) reported in WinForms around the anchor layout being problematic on higher DPI scale monitors, irrespective of application DPI mode. This document outlines the changes being made in .NET 8.0 to address these issues, which is aligned with the larger goal to support all supported application DPI modes in WinForms.

## Problem in Scope

The position of an anchored control with respect to its parent should be able to be determined at design time and should only need to be changed if there were explicit changes in the control's bounds or when the control is scaled in response to a DPI changed event. Bounds changes that happen as result of the parent control's bounds changing shouldn't alter a control's relative position in the parent's rectangle. However, currently the layout engine computes the anchored control's relative position every time there are changes to the control's bounds or the control's location-related properties.

For example, the following simple code snippet copied from a Control's `InitializeComponent` method demonstrates the impact of the "over-eager" computations. The number of unnecessary computations can increase quite dramatically for nested layouts.

```CS
// The following line triggers layout to compute anchors with the default button size and without a parent control.
this.button7.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right)));

// The following line triggers layout again to compute anchors with the default button size with a new location but still without a parent control.
this.button7.Location = new System.Drawing.Point(9, 47);

// The following line triggers layout once again to compute anchors with the button's new size but still without a parent control.
this.button7.Size = new System.Drawing.Size(134, 23);

// The following line triggers layout to compute anchors with button's current size and the default size for the parent control.
this.Controls.Add(button7);

// The following line triggers layout to compute anchors with the button's current size and a new size for the parent control.
// These sizes still may be changed for the current DPI depending on application's DPI mode.
this.Size = new System.Drawing.Size(828, 146);

// The following line triggers layout to compute anchors with the button's current size and new size for the parent control.
// The current DPI is still not applied.
this.ResumeLayout(false);
```
The above snippet does not represent the complete set of instances where anchor computations are unnecessary and may hold invalid anchor values. It gets even more complicated when nested UserControls are involved.

In addition, the original anchor calculation implementation was designed prior to adding high DPI support to WinForms.

## Known issues

Customer reported issues can be largely grouped as follows:


### Missing controls

Calculation of control's anchors with default sizes may result in negative anchors and, thus, result in an invalid location for the anchored controls.




### Overlapped Controls

Related to the "Missing controls" issue above, if the parent control is scaled to match the current monitor's DPI, and the control's anchor calculations happen out of sync with this scaling, controls may overlap:




## Proposed solution

 The proposal is that we calculate anchors for a control only if the following conditions are met:

- The control is parented.
- The control's parent's layout is resumed.

 The initial anchor calculations would now happen whenever parent's layout is resumed, or when control is parented/resized and parent's layout is not suspended. The anchors will be recalculated whenever there are changes in geometry (`Size`, `Location`, etc.) or hierarchy (`ParentChanged`).

### Anchor calculations

The following image illustrates anchors calculation with respect to a control's parent's display rectangle. The "orange" rectangle is the parent's display rectangle, and the "blue" rectangle is the anchored control's (button) bounds.
- `Left` arrow indicates the X coordinate of the button location with respect to the parent's display rectangle.
- `Top` arrow indicates the Y coordinate of the button location with respect to the parent's display rectangle.
- `Right` arrow indicates the distance from right edge of the parent's rectangle where button is placed.
- `Right` arrow indicates the distance from the bottom edge of the parent's rectangle where the button is placed.

    


In the above image the boundary marked in "orange" is a container hosting the control (boundary marked with "blue"). The control can define its anchor property to explicitly tell the layout engine how its bounds change relative to its parent's bounds.

For example:
```CS
this.button14.Anchor = (System.Windows.Forms.AnchorStyles.Bottom
 | System.Windows.Forms.AnchorStyles.Left
 | System.Windows.Forms.AnchorStyles.Top
 | System.Windows.Forms.AnchorStyles.Right );
```
When the control's `Anchor` property is set, the anchors (that is, left, top, right, bottom values) are computed and stored in an internal struct `AnchorInfo`. The only time the anchor values can be negative is when the control is placed/position outside/overlapped with the hosting control's bounds.

The following code snippet demonstrates anchor calculations:

```CS
private static void ComputeAnchorInfo(IArrangedElement element)
{
    AnchorInfo? anchorInfo = GetAnchorInfo(element);
    if (anchorInfo is null)
    {
        anchorInfo = new();
        SetAnchorInfo(element, anchorInfo);
    }
    Rectangle displayRect = element.Container.DisplayRectangle;
    Rectangle elementBounds = GetCachedBounds(element);
    int x = elementBounds.X;
    int y = elementBounds.Y;
    anchorInfo.Left = x;
    anchorInfo.Top = y;
    anchorInfo.Right = displayRect.Width - (x + elementBounds.Width);
    anchorInfo.Bottom = displayRect.Height - (y + elementBounds.Height);
}
```

## Risk mitigation

The layout engine, in general, is quite complex, and any changes in it carry a very high risk. In order to reduce the risks and to provide backward compatibility, the new anchor calculations are put behind a feature switch `System.Windows.Forms.AnchorLayoutV2`. The switch is disabled by default for Windows Forms applications.

Developers need to opt-in to get this new feature by setting the switch value to `true` in the [runtimeconfig.json](https://learn.microsoft.com/dotnet/core/runtime-config/#runtimeconfigjson).
Snippet for runtimeconfig.template.json:
```JSON
{
  "configProperties": {
    "System.Windows.Forms.AnchorLayoutV2": true
  }
}
```

---

### Designer Designer High Dpi Mode (`docs/designer/designer-high-dpi-mode.md`)

# Designer HighDpi mode
Visual Studio 2022 and beyond by default launch in PerMonitor DpiAwareness mode but it also supports SystemAware and Unaware DpiAwareness modes when users launch it with [custom settings](https://docs.microsoft.com/visualstudio/designers/disable-dpi-awareness?view=vs-2022). The WinForms designer does not fully support PerMonitor DpiAwareness mode yet and by default launches in SystemAware mode.

In .NET 6, as part of unifying the information sharing between WinForms designer and WinForms runtime, we added [support](https://aka.ms/applicationconfiguration) for specifying the application dpi mode as a build time property on the project and share it for both designtime and at runtime.

## Issues
 The Winforms designer, when operating in SystemAware/PermonitorV2 mode, serializes layout metrics into the source file based on the Dpi setting of the current display device on which it is being rendered. This may lead to two kinds of problems.

 1. WinForms applications developed on a machine with DPI settings different from the machine where they are executed may encounter layout inconsistencies. 
 
 2. Within a team of multiple developers collaborating on the same project, this situation can lead to unintentional modifications in the serialized source code, even if they are unrelated to the intended changes. As a consequence, it introduces additional overhead in the code review and merging process.

The following example demonstrates an undesired modification in the serialized WinForms source code.




Up until now, developers have been advised to adhere to the instructions given [here](https://go.microsoft.com/fwlink/?linkid=875609) and restart Visual Studio in DpiUnAware mode to resolve these problems. Nevertheless, this process requires individual developers to do it every time they work on the project, adding inconvenience. Additionally, the entire Visual Studio IDE would be launched as DPI Unaware resulting in a blurry IDE experience.

## Solution

In Visual Studio 2022 Version 17.8, we are introducing a new [configuration]((https://aka.ms/applicationconfiguration)) option called `ForceDesignerDpiUnaware`, distinct from `ApplicationHighDpiMode`. This option enables developers to enforce DpiUnAware mode for all WinForms designers in the project, regardless of the `ApplicationHighDpiMode`, which continues to take effect during runtime. The rest of the Visual Studio environment remains in PerMonitor mode and renders crisply.


```xml
 <Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net7.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
    <ApplicationHighDpiMode>SystemAware</ApplicationHighDpiMode>
    <ForceDesignerDpiUnaware>true</ForceDesignerDpiUnaware>
  </PropertyGroup>
 </Project>
```

---

### Designer Designer Selection (`docs/designer/designer-selection.md`)

# Designer Selection Feature for .NET Framework Projects

## Problem
Visual Studio 2022 is a 64-bit process and it cannot load 32-bit assemblies. Due to this technical limitation, Windows Forms .NET Framework in-process designer, which runs in the Visual Studio process, cannot load controls present in 32-bit assemblies.
This has been a major Visual Studio 2022 adoption blocker for customers who have Windows Forms .NET Framework projects which utilize ActiveX/COM controls or other custom controls contained in 32-bit assemblies and which cannot be updated to `AnyCPU` or to .NET. Until now, such projects could only use Windows Forms designer in Visual Studio 2019 because it is a 32-bit process.

## Solution
To address this problem, we have been adding support for .NET Framework projects in Windows Forms **out-of-process** designer in last few Visual Studio 2022 releases.
This feature is still in an early preview state, and we are collecting developers' feedback on it. The **Visual Studio 17.9 Preview 2** release had added the following enhancements:
1. Improved **Type Resolution** for .NET Framework projects.
2. **ActiveX/COM** support for both .NET Framework and .NET projects.
3. **Designer Selection Feature** to track 32-bit assembly load failures in .NET Framework projects.

When a failure is detected, Designer Selection Feature presents following dialog to the user to select appropriate designer for the project:



On selecting `Yes`, the project will be reloaded and Windows Forms out-of-process designer will be used for the project. When project is targeting x86 platform, the designer will spawn a 32-bit process. When project is targeting AnyCPU or x64 platform, the designer will spawn a 64-bit process. Control assemblies will be loaded in that process.

On selecting `No`, the project will continue to use in-process designer.

With `Yes/No` buttons, the designer selection will be remembered for current Visual Studio instance only. To add the designer selection as a project configuration property automatically, enable option `Remember for current project`. It will add `UseWinFormsOutOfProcDesigner` property to each project configuration. Windows Forms designer will read this property value to select desired designer automatically the next time project is open in Visual Studio. Here is a sample project configuration after adding this property:



The newly added property is:
```xml
<UseWinFormsOutOfProcDesigner>True</UseWinFormsOutOfProcDesigner>
```

This feature will solve the cases of forms having controls that have modern designers, i.e., the ones referencing the new [out-of-process designer SDK](https://www.nuget.org/packages/Microsoft.WinForms.Designer.SDK) or some simple controls which do not use complex designer features. However, this feature will not work for forms with controls that use complex designer features and as a result they must be updated to use [out-of-process designer extensibility](https://github.com/microsoft/winforms-designer-extensibility) model.

Note that the `Designer Selection` feature is currently under following preview feature flag which is enabled by default:



This feature flag is present in Visual Studio under **Tools -> Options -> Preview Features**.

Following InfoBar will show up when out-of-process designer is used for .NET Framework projects:



## :warning: Warning
Since the out-of-process designer for .NET Framework projects cannot handle all third-party controls, there is a possibility of data loss on using this feature. Hence, we recommend that you create a backup of your project beforehand.

Also, there is a difference in the way CodeDom parsing is handled between in-process and out-of-process designers. The out-of-process designer will likely make significant updates to the code behind file which might make it incompatible with in-process designer. This issue will be addressed in an upcoming release.

## Next Steps
Following are the list of features which we plan to add support for in upcoming Visual Studio releases:

1. Disable code style and formatting changes for .NET Framework projects utilizing out-of-process designer (see [Modernization of Code Behind in out-of-process designer](https://github.com/dotnet/winforms/blob/main/docs/designer/modernization-of-code-behind-in-OOP-designer/modernization-of-code-behind-in-oop-designer.md)).
2. Add Toolbox support for third-party and custom controls.
3. Add setting for `UseWinFormsOutOfProcDesigner` property in project property pages.

---

### Designer Net Inproc Designer (`docs/designer/net-inproc-designer.md`)

# How to use Windows Forms .NET Framework designer for .NET applications

The OOP designer is a port of the original .NET Framework Windows Forms designer that was run inside the Visual Studio's process. And whilst the team is aiming for parity there are still functional gaps between the original designer and the new OOP designer. With that it is possible that you may find yourself in a situtation where the OOP designer is not working as expected, and you'd want to use the .NET Framework designer to carry you on.

This guide will walk you through the steps that enable a substantial use of the .NET Framework designer to design Windows Forms .NET applications. Please note, that due to the changes in the default font and new APIs in Windows Forms .NET, the .NET Framework designer won't be able to provide 100% parity.

## 1. Create Windows Forms .NET app

Create a new Windows Forms application targeting .NET from Visual Studio or your favorite command line interface.

### Create in Visual Studio

`VS2022`:

1. _File > Add > New Project... > Windows Forms App (.NET Core)_, choose C# or Visual Basic
2. Specify project name, e.g. `SimpleWinForms`



### Create from command line

Open your favorite console, create a new folder for your application:

```cmd
md SimpleWinForms
cd SimpleWinForms
dotnet new winforms -n SimpleWinForms
dotnet new sln
dotnet sln add SimpleWinForms
```

:point_up: **TIP:** You can have the folder name different from the project's name. Use the option `-n` (or `-name`) for that when using `dotnet new`.

:point_up: **TIP:** For Visual Basic projects use the option `-lang vb` when using `dotnet new`.

After creating the project, you can run the application:
```cmd
dotnet run --project SimpleWinForms\SimpleWinForms.csproj
```


## 2. Enable .NET Framework designer support

There are few options available to help you to design UI for your .NET Core project.


### Option 1: multi-target your app

1. Open `SimpleWinForms.sln`

2. Open the `SimpleWinForms` project file by double clicking on it in Solution Explorer. Change the ``TargetFramework`` property from:

    ```diff
    -    <TargetFramework>net6.0-windows</TargetFramework>
    +    <TargetFrameworks>net472;net6.0-windows</TargetFrameworks>
    ```

3. Add for any and every form file you have in this ``ItemGroup``:

    ```xml
     <ItemGroup Condition="'$(TargetFramework)' == 'net472'">
       <Compile Update="Form1.cs">
         <SubType>Form</SubType>
       </Compile>
       <Compile Update="Form1.Designer.cs">
         <DependentUpon>Form1.cs</DependentUpon>
       </Compile>
     </ItemGroup>
    ```

    After doing these steps this is what you should end up with:

    ![edit-project-file][edit-project-file]


### Option 2: Shadow .NET Frameowk project

1. Open `SimpleWinForms.sln`

2. Add a new **Windows Forms App (.NET Framework)** project (VS2017: _Visual C# > Windows Desktop_ / VS2019+: _C# : Windows : Desktop_) to the solution (_File > Add > New Project..._)

    ![add-netfx-project][add-netfx-project]

3. Name the new .NET Framework project as the .NET project, but add ".Designer" to it (e.g. `SimpleWinForms.Designer`)

4. Go to the .NET Framework project properties and set the default namespace to the .NET project's namespace

    ![edit-namespace][edit-namespace]

5. Delete the existing Form files in both projects

6. Add a new Windows Form in the .NET Framework project's context menu _Add > Windows Form..._

    ![add-new-form][add-new-form]

7. In the section list, click on *Windows Forms*, and chose *Windows Form* from the installed templates

    ![add-new-form-dialog][add-new-form-dialog]

8. Give the name and click `[Add]`.

   :exclamation: **IMPORTANT**: You need to trigger a form change event for the Designer to create a `resx` file. You can do it by resizing the form for a couple of pixels or changing the form's `Text` property. Don't forget to save.

9. Now we move the form to the .NET project.<br />
In the Solution Explorer click on the form and press <kbd>CTRL</kbd>+<kbd>X</kbd> to cut it; and then paste it in to the .NET project (<kbd>CTRL</kbd>+<kbd>V</kbd>). Check that the main form file, the .designer file and the resource file for the form are all present.

10. Then we link the form back into the .NET Framework project back.<br />
Remember: We can only use the .NET Framework designer, but we want to have only one set of files. So the form files, of course, belong to the .NET project but we want to edit them in the context of the .NET Framework project (thus using the .NET Framework designer).

    * To do this open the context menu on the .NET Framework project in the Solution Explorer, and pick _Add > Existing Item_

    * In the File Open Dialog, navigate to the .NET project, select the *Form.cs*, *Form.Designer.cs* and *Form.resx* files and choose *Add as Link* option.

    ![add-as-link][add-as-link]

11. Compile the solution to see if the file references were set up correctly

1. As the last but important step, we need to re-nest the linked form files.<br/>
If you installed the [File Nesting Visual Studio Extension][file-nesting-extension] then that is done easily: Select both the *Form.Designer.cs* and *Form.resx* file, and from the context menu click _File Nesting > Nest Items_. In the dialog, pick the main form file (Form.cs), and click OK.

Now, whenever you need to use the Designer on one of the .NET Form or UserControl files, simply open the linked files in the .NET Framework project with the Windows Forms Designer.


### More information

If you are porting an existing .NET Framework application to .NET you may wish to read the following blog posts:
* [Porting desktop apps to .NET](https://devblogs.microsoft.com/dotnet/porting-desktop-apps-to-net-core/)
* [.NET Upgrade Assistant](https://devblogs.microsoft.com/dotnet/introducing-the-net-upgrade-assistant-preview/)
* [Using the Windows Forms designer for .NET projects](https://devblogs.microsoft.com/dotnet/how-to-port-desktop-applications-to-net-core-3-0/#user-content-using-the-winforms-designer-for-net-core-projects)

[comment]: <> (URI Links)

[file-nesting-extension]: https://marketplace.visualstudio.com/items?itemName=MadsKristensen.FileNesting

[comment]: <> (Images)

[add-netfx-project]: ../images/add-netfx-project.png
[edit-namespace]: ../images/edit-namespace.png
[add-new-form]: ../images/add-new-form.png
[add-new-form-dialog]: ../images/add-new-form-dialog.png
[add-as-link]: ../images/add-as-link.png
[edit-project-file]: ../images/edit-project-file.png

---

### Designer Troubleshooting (`docs/designer/troubleshooting.md`)

# How to troubleshoot the Windows Forms Out-Of-Process designer

Whilst the Windows Forms Out-Of-Process Designer (or the OOP designer) is by far and large sort of a black box to the users, it actually provides some good means to find out more information on its state.

## Logging 

Once the OOP designer is started, its log is available in the Visual Studio Output window:



The default verbosity is set to  _Warnings_, which includes Warnings and Errors (prior to VS 2022 17.2 was _None_, i.e. logging disabled). You can change the logging level to terser or more verbose under **Tools -> Options -> Windows Forms Designer -> General -> Logging Level**, e.g.:



## "Designer never loads" problems and possible ways to resolve those

### Connection Timeouts

When the OOP designer starts it launches the designer server process (aka DesignToolsServer.exe). If the server process fails to launch or connect to the Visual Studio, you may see the following error:

```
[02:59:20.7198643] [MyProj]: Timed out waiting for the design tools server process launch to complete.
[02:59:20.7668637] Microsoft.DotNet.DesignTools.Client.ServerException: Timed out waiting for the design tools server process launch to complete.
```

The default connection timeout is set to _2 minutes_ (prior to VS 2022 17.1p5 was _10 seconds_). VS 2022 17.2 introduces the ability to increase the connection timeout, if necessary. You can change it under **Tools -> Options -> Windows Forms Designer -> General -> Connection timeout**, e.g.:



There can be various reasons why the server process may be taking longer than the allocated time. For example, some users have reported to have solutions with a large number of projects. The designer performs a shadow copying of the necessary files and folders before it can render your form or control, and if you have a slow hard drive, or the project files are located on a network drive, it can have a significant effect on how fast files are copied to the shadow cache folder.

### Antivirus is blocking the server process executables

Some customers have reported that the connection timeouts were caused by configurations of their antivirus services. In such cases it is recommended to add exclusion rules for `devenv.exe` and `DesignToolsServer.exe`, and this can unblock these executables and can increase the I/O of the shadow cache. For example, to add an exception to the Windows Defender so that it is not slowed down by the system call hooks Defender uses to provide real-time protection can be done with the following PowerShell command:

```powershell
Add-MpPreference -ExclusionProcess 'devenv.exe'
Add-MpPreference -ExclusionProcess 'DesignToolsServer.exe'
```

### `Switch.System.IO.UseLegacyPathHandling` override is enabled

The designer server process uses [long paths](https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation) and requires [path normalizations](https://docs.microsoft.com/dotnet/framework/migration-guide/mitigation-path-normalization), the behaviours that can be altered by `Switch.System.IO.UseLegacyPathHandling` appcontext switch. The default value of the switch is `false`, and if the value is set to `true` either in devenv.exe.config (which is located somewhere like C:\Program Files\Microsoft Visual Studio\2022\Common7\IDE) or in the [registry](https://docs.microsoft.com/dotnet/api/system.appcontext?view=net-6.0#appcontext-for-library-consumers) it will prevent the designer from loading with `Argument Exception: Illegal characters in path` error.

---

### Infra Automation (`docs/infra/automation.md`)

## Automation

### Fabric Bot

This repository uses Fabric Bot to automate issue and pull request management. All automation rules are defined in the [`.github/fabricbot.json`](.github/fabricbot.json) file.

At this moment Fabric Bot has not published a JSON schema for the configuration format. In order to make changes to the configuration file, you should use the [`Fabric Bot portal`](https://portal.fabricbot.ms/bot/) to load the configuration file via the "Import Configuration" option and make changes using the editor. You need to be signed out from the portal in order for this option to appear.

---

### Serialization Register Custom Type Converter (`docs/serialization/register-custom-type-converter.md`)

# Manually Registering a TypeConverter to a Class
A [type converter](https://learn.microsoft.com/dotnet/api/system.componentmodel.typeconverter) is usually bound to a class by adding the [`TypeConverterAttribute`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typeconverterattribute) to the class. When you cannot apply this attribute or want to override it you can programmatically assign a converter instead. This document outlines how to accomplish this.

## Prerequisite
Follow the steps to implement your own custom type converter listed [here](https://learn.microsoft.com/dotnet/api/system.componentmodel.typeconverter#notes-to-inheritors).

## Registering Your TypeConverter

### Background
A [`TypeConverter`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typeconverter) for a given type is found via the `TypeDescriptor` static method [`GetConverter()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor.getconverter). To provide custom `TypeDescriptor` behavior you must create and register a custom type descriptor ([`ICustomTypeDescriptor`](https://learn.microsoft.com/dotnet/api/system.componentmodel.icustomtypedescriptor)) via a [`TypeDescriptionProvider`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptionprovider).

### Implementing An ICustomTypeDescriptor
Inherit from [`CustomTypeDescriptor`](https://learn.microsoft.com/dotnet/api/system.componentmodel.customtypedescriptor) to get default [`ICustomTypeDescriptor`](https://learn.microsoft.com/dotnet/api/system.componentmodel.icustomtypedescriptor) behavior and override [`GetConverter()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.customtypedescriptor.getconverter) to return your custom type converter.
```c#
private class CustomConverterDescriptor : CustomTypeDescriptor
{
    private TypeConverter _converter;

    public CustomConverterDescriptor(ICustomTypeDescriptor parent, TypeConverter converter) : base(parent)
        => _converter = converter;

    public override TypeConverter GetConverter() => _converter;
}
```

An `ICustomTypeDescriptor` is accessed through [`TypeDescriptionProvider.GetTypeDescriptor()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptionprovider.gettypedescriptor). This method needs to be overridden to provide your newly created `ICustomTypeDescriptor`. Have another class inherit from `TypeDescriptionProvider` to preserve the default behavior and override `GetTypeDescriptor()` to provide `CustomConverterDescriptor`.

```c#
public class CustomConverterProvider : TypeDescriptionProvider
{
    private TypeConverter _converter;

    public CustomConverterProvider(TypeDescriptionProvider parent, TypeConverter converter) : base(parent)
        => _converter = converter;

    public override ICustomTypeDescriptor GetTypeDescriptor(Type objectType, object instance) 
        => new CustomConverterDescriptor(base.GetTypeDescriptor(objectType, instance), _converter);

    // Consider nesting CustomConverterDescriptor here
}
```
Note: The parent `TypeDescriptionProvider` to be passed to the constructor can be found via [`TypeDescriptor.GetProvider()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor.getprovider) and passing in the type that is intended to be associated to your custom type converter. An example of this will follow.

### Registration/Deregistration
Once you have `CustomConverterProvider` and `CustomConverterDescriptor` as outlined above, finish up registering your custom `TypeConverter` to a type by calling [`TypeDescriptor.AddProvider()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor.addprovider) with parameters `CustomConverterProvider` and the type you want your custom converter to be associated with. 
```c#
TypeDescriptionProvider parentProvider = TypeDescriptor.GetProvider(type);
CustomConverterProvider newProvider = new(parentProvider, converter);
TypeDescriptor.AddProvider(newProvider, type);
```

At this point, calling [`TypeDescriptor.GetConverter()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor.getconverter) with the same type that was passed to `TypeDescriptor.AddProvider()` will now return your custom type converter. To restore the previous behavior call [`TypeDescriptor.RemoveProvider()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor.removeprovider).
```c#
TypeDescriptor.RemoveProvider(newProvider, type);
```

## Additional Information

### TypeDescriptor.GetConverter() Details
This is a static method on [`TypeDescriptor`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptor) that will run through its private list of [`TypeDescriptionProviders`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptionprovider) and get the provider associated with the type. Once the right provider is found, it will then call [`TypeDescriptionProvider.GetTypeDescriptor()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typedescriptionprovider.gettypedescriptor) to get an [ICustomTypeDescriptor](https://learn.microsoft.com/dotnet/api/system.componentmodel.icustomtypedescriptor) and call [`ICustomTypeDescriptor.GetConverter()`](https://learn.microsoft.com/dotnet/api/system.componentmodel.icustomtypedescriptor.getconverter) to grab the [`TypeConverter`](https://learn.microsoft.com/dotnet/api/system.componentmodel.typeconverter). 
```mermaid
sequenceDiagram
title TypeDescriptor.GetConverter() Flow

participant TypeDescriptor
participant CustomConverterProvider#58;TypeDescriptionProvider
participant CustomConverterDescriptor#58;CustomTypeDescriptor
participant CustomTypeConverter#58;TypeConverter
note right of CustomConverterProvider#58;TypeDescriptionProvider: Call TypeDescriptor.RemoveProvider() to no longer associate your custom type converter with a given type
TypeDescriptor->>CustomConverterProvider#58;TypeDescriptionProvider: TypeDescriptor.GetConverter()
note over TypeDescriptor,CustomConverterProvider#58;TypeDescriptionProvider: Must call TypeDescriptor.AddProvider() with a given type first
CustomConverterProvider#58;TypeDescriptionProvider->>CustomConverterDescriptor#58;CustomTypeDescriptor: CustomConverterProvider.GetTypeDescriptor()
note over CustomConverterProvider#58;TypeDescriptionProvider,CustomConverterDescriptor#58;CustomTypeDescriptor: Must override GetTypeDescriptor() to return CustomConverterDescriptor first
CustomConverterDescriptor#58;CustomTypeDescriptor->>CustomTypeConverter#58;TypeConverter: CustomConverterDescriptor.GetConverter()
note over CustomConverterDescriptor#58;CustomTypeDescriptor,CustomTypeConverter#58;TypeConverter: Must override GetConverter() to return CustomTypeConverter first
```

---

### Trimming Feature Switches (`docs/trimming/feature-switches.md`)

# WinForms Libraries Feature Switches

Publicly documented [feature-switches](https://github.com/dotnet/designs/blob/master/accepted/2020/feature-switch.md) can be found on the [official docs](https://learn.microsoft.com/en-us/dotnet/core/deploying/trimming/trimming-options#trimming-framework-library-features). Additional details on feature switches usage can be found on the [runtime repo](https://github.com/LakshanF/runtime/blob/main/docs/workflow/trimming/feature-switches.md). Non-public feature switches that impact WinForms libraries can be found in the following table.

## Available Feature Switches

| MSBuild Property Name | AppContext Setting | Description |
|-|-|-|
| _ActiveXImplSupport | System.Windows.Forms.ActiveXImpl.IsSupported | WinForms ActiveX support is trimmed when set to false. |
| _MdiWindowDialogSupport | System.Windows.Forms.MdiWindowDialog.IsSupported | WinForms MdiWindowDialog support is trimmed when set to false. |
| _UseComponentModelRegisteredTypes | System.Windows.Forms.Control.UseComponentModelRegisteredTypes | Uses ComponentModel type registration feature when set to true. |
| _WinFormsBindingSupport | System.Windows.Forms.Binding.IsSupported | WinForms binding support is trimmed when set to false. |
| _WinFormsDesignTimeFeaturesSupport | System.Windows.Forms.Control.AreDesignTimeFeaturesSupported | WinForms design time support is trimmed when set to false. |
| _WinFormsImageIndexConverterSupport | System.Windows.Forms.ImageIndexConverter.IsSupported | WinForms ImageIndexConverter support is trimmed when set to false. |
| _WinFormsUITypeEditorSupport | System.Drawing.Design.UITypeEditor.IsSupported | WinForms UITypeEditor support is trimmed when set to false. |

---

### Feature Prompts SuspendRelocationPaintingFlashPreventing Create Github API Proposal Prompt (`docs/Feature-Prompts/SuspendRelocationPaintingFlashPreventing/Create-Github-API-Proposal-Prompt.md`)

# Copilot Prompt 1 — Author the WinForms API Suggestion

## Your task

Write a complete API suggestion for the `dotnet/winforms` repository, ready to be filed
as a GitHub issue with the `api-suggestion` label. The issue covers two related features
for reducing visible intermediate states while WinForms applications update their UI:

1. Painting suspension with optional layout suspension across a control tree.
2. Deferred top-level form reveal.

Use these issue sections:

- `## Rationale`
- `## API Proposal`
- `## API Usage`
- `## Alternative Designs`
- `## Risks`
- `## Will this feature affect UI controls?`
- `### Status Checklist`

## Sub-feature A — painting and layout suspension

### Settled API surface

```csharp
namespace System.Windows.Forms;

public interface ISupportSuspendPainting
{
    void BeginSuspendPainting();
    void EndSuspendPainting();
}

public enum LayoutSuspendTraversal
{
    None = 0,
    TopLevelOnly = 1,
    Traverse = 2,
}

public sealed class SuspendPaintingScope : IDisposable
{
    public SuspendPaintingScope(ISupportSuspendPainting? target);
    public void Dispose();
}

public static class ControlMutationExtensions
{
    public static SuspendPaintingScope SuspendPainting(
        this ISupportSuspendPainting target);

    public static SuspendPaintingScope SuspendPainting(
        this ISupportSuspendPainting target,
        LayoutSuspendTraversal layoutSuspendTraversal);

    public static SuspendPaintingScope SuspendPainting(
        this ISupportSuspendPainting target,
        Func<Control, bool> suspendLayoutContainerFilter);
}
```

- `Control` implements `ISupportSuspendPainting` explicitly and exposes protected virtual
  `BeginSuspendPaintingCore` / `EndSuspendPaintingCore` hooks.
- `ListView`, `ListBox`, `ComboBox`, `TreeView`, and `RichTextBox` route painting
  suspension through their existing `BeginUpdate` / `EndUpdate` paths.
- `None` suspends painting only.
- `TopLevelOnly` suspends layout on the target `Control`.
- `Traverse` suspends layout on the target and all existing descendants.
- The predicate is evaluated for the target and every descendant. A `false` result skips
  that node but does not prune traversal.
- Selected nodes are suspended even when they currently have no children.
- Layout-aware overloads require the target to derive from `Control`.
- The scope is a sealed class so it can span `await`.

### Design considerations

- Snapshot the selected controls when the scope starts.
- Suspend layout root-to-leaf and resume it deepest-first.
- Resume layout before ending painting so recursive invalidation occurs after layout.
- Keep disposal idempotent and preserve nesting through the existing ref counts.
- Explain that controls added after the snapshot are covered by their parent's suspended
  layout but do not receive an independently balanced suspension.
- Discuss traversal cost for large control trees and exceptions thrown by predicates.
- Include invalid and non-`Control` target behavior in the proposal.

## Sub-feature B — deferred form reveal

Use the current `FormRevealMode` design from the tracked API proposal:

```csharp
namespace System.Windows.Forms;

public enum FormRevealMode
{
    Inherit = -1,
    Classic = 0,
    Deferred = 1,
}

public partial class Form
{
    public virtual FormRevealMode FormRevealMode { get; set; }
}

public partial class Application
{
    public static FormRevealMode DefaultFormRevealMode { get; }
    public static void SetDefaultFormRevealMode(FormRevealMode mode);
    public static bool IsFormRevealDeferred { get; }
}
```

Describe DWM cloaking, dark-mode-aware default resolution, designer serialization,
top-level-window limitations, and conservative fallback behavior on unsupported systems.

## Filing instruction

Produce a complete proposal rather than an implementation plan. Clearly distinguish fixed
API shape from implementation choices that remain open for review.

---

### Feature Prompts SuspendRelocationPaintingFlashPreventing SuspendRelocationAndPainting API Feature Prompt (`docs/Feature-Prompts/SuspendRelocationPaintingFlashPreventing/SuspendRelocationAndPainting-API-Feature-Prompt.md`)

# Copilot Prompt 2 — Implement the flicker-free UI mutation APIs

## Prerequisite

Read the current upstream API suggestion before implementation. Treat its latest
`API Proposal` section as the public contract and report any conflict instead of silently
choosing a different shape.

## Scope

### A — painting suspension with optional layout traversal

- Implement `ISupportSuspendPainting` on `Control` with ref-counted
  `BeginSuspendPaintingCore` / `EndSuspendPaintingCore` hooks.
- Route `ListView`, `ListBox`, `ComboBox`, `TreeView`, and `RichTextBox` through their
  existing `BeginUpdate` / `EndUpdate` mechanisms.
- Keep `SuspendPaintingScope` as a sealed, idempotent `IDisposable` class so it can span
  `await`.
- Provide these extension methods:

  ```csharp
  public static SuspendPaintingScope SuspendPainting(
      this ISupportSuspendPainting target);

  public static SuspendPaintingScope SuspendPainting(
      this ISupportSuspendPainting target,
      LayoutSuspendTraversal layoutSuspendTraversal);

  public static SuspendPaintingScope SuspendPainting(
      this ISupportSuspendPainting target,
      Func<Control, bool> suspendLayoutContainerFilter);
  ```

- `LayoutSuspendTraversal` has `None`, `TopLevelOnly`, and `Traverse`.
- Snapshot selected controls before suspension. Suspend root-to-leaf and resume
  deepest-first.
- The predicate is evaluated for the target and every descendant. A `false` result skips
  suspension for that node without pruning its descendants.
- Suspend selected controls even when they currently have no children.
- Validate layout-aware calls before beginning painting. A non-`Control` target is invalid.
- Resume all selected layout scopes before ending painting so the recursive invalidation
  occurs after layout.

### B — deferred form reveal

- Implement the approved `FormRevealMode`, `Form.FormRevealMode`, and
  `Application` configuration APIs.
- Preserve classic behavior when deferred reveal is not active.
- Cloak eligible top-level form handles and uncloak according to the timing strategy in the
  proposal.
- Keep unsupported DWM and window configurations inert and safe.

## Engineering requirements

- Match the current repository language version, nullable annotations, code style, and
  interop conventions.
- Add XML documentation for every public or protected API.
- Update `PublicAPI.Unshipped.txt`.
- Keep state lazy where existing `Control` property-store patterns apply.
- Do not change existing public `BeginUpdate` / `EndUpdate` behavior.

## Tests

- Painting ref-count balance, nesting, idempotent disposal, handle creation, and handle
  recreation.
- `None`, `TopLevelOnly`, and `Traverse` layout selection.
- Predicate selection, continued traversal after a rejected node, and empty containers.
- Deepest-first layout resume and recursive invalidation after layout.
- Null, invalid-enum, and non-`Control` target failures without partial suspension.
- Existing native update paths for the selected built-in controls.
- Classic/deferred form reveal behavior and unsupported-OS fallback.

## Deliverable

Provide production code, focused tests, updated API tracking, and an updated API proposal.
Call out any behavior that the implementation proves unsafe or unnecessarily costly.

---

### Designer Modernization Of Code Behind In OOP Designer Modernization Of Code Behind In Oop Designer (`docs/designer/modernization-of-code-behind-in-OOP-designer/modernization-of-code-behind-in-oop-designer.md`)

# Modernization of code-behind in WinForms OOP designer

## Background

The WinForms designer saves visual representations of user controls or forms on the design surface to code-behind file (`Form1.Designer.cs` or `Form1.Designer.vb`). Control instances that developer sees on the design surface are represented as a CodeDOM tree (see [Using the CodeDOM](https://learn.microsoft.com/dotnet/framework/reflection-and-codedom/using-the-codedom)), that tree is saved to the generated code-behind file in the `InitializeComponent` method. We call this feature design time serialization.

Previously COM-based [CodeModel interface](https://learn.microsoft.com/dotnet/api/envdte.codemodel?view=visualstudiosdk-2022) was used to write code into the editor's buffer as well as to generate CodeDOM tree from the source code when designer was loading. This COM object was accessible from the main thread only, which prevented parallelization in source code processing. Also, being more than 20 years old, it did not support some of the newer language features, for example the `nameof()` expression.

## What's different

Starting with [Visual Studio 2022 v17.5 Preview 3](https://visualstudio.microsoft.com/vs/preview/), the WinForms out-of-process designer uses [Roslyn](https://github.com/dotnet/roslyn) for design time serialization.

In Preview 3, designer serializes more modern code into `InitializeComponent`. We have worked hard to ensure that you can take projects between this version of Visual Studio and earlier versions. Someday in the future, we may build on the improvements in our serialization to enable performance enhancements and use newer language features. These potential future investments may break the backwards compatibility with earlier VS versions - but we will be sure to inform our developers well ahead of such changes so that you can prepare.

## Why change it

* The use of Roslyn unblocks multithreaded serialization and deserialization to solve performance delays in designer load and unload scenarios.
* Code-behind generation now respects `.editorconfig` settings and thus matches code style in the source files.
* If implicit usings feature is enabled in project properties, global namespaces are not repeated in type names.
* Further modernization of code-behind is unblocked.
* Newly generated code will work with modern Roslyn analyzers.

## How the new code looks like

While `InitializeComponent` method is meant for the designer use only, and manual modifications to this method are not supported, developers might see some unexpected changes in `Form1.Designer.cs` and `Form1.designer.vb` files when comparing versions in the source control tools. This is a one-time code churn. Once the designer file is regenerated in v17.5 Preview 3 or newer and saved, designer will generate code only for controls modified in the design surface.

For example, `InitializeComponent` method for a form with a button will be modified like this on the first save:



Code generated by VisualStudio v17.4 or earlier:

```cs
private void InitializeComponent()
{
    this.button1 = new System.Windows.Forms.Button();
    this.SuspendLayout();
    // 
    // button1
    // 
    this.button1.Location = new System.Drawing.Point(58, 60);
    this.button1.Name = "button1";
    this.button1.Size = new System.Drawing.Size(136, 69);
    this.button1.TabIndex = 0;
    this.button1.Text = "button1";
    this.button1.UseVisualStyleBackColor = true;
    // 
    // Form1
    // 
    this.AutoScaleDimensions = new System.Drawing.SizeF(10F, 25F);
    this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
    this.ClientSize = new System.Drawing.Size(270, 208);
    this.Controls.Add(this.button1);
    this.Name = "Form1";
    this.Text = "Form1";
    this.ResumeLayout(false);

}
```

Code generated by VisualStudio v17.5 Preview 3, or newer:

```cs
private void InitializeComponent()
{
    button1 = new Button();
    SuspendLayout();
    // 
    // button1
    // 
    button1.Location = new Point(58, 60);
    button1.Name = "button1";
    button1.Size = new Size(136, 69);
    button1.TabIndex = 0;
    button1.Text = "button1";
    button1.UseVisualStyleBackColor = true;
    // 
    // Form1
    // 
    AutoScaleDimensions = new SizeF(10F, 25F);
    AutoScaleMode = AutoScaleMode.Font;
    ClientSize = new Size(270, 208);
    Controls.Add(button1);
    Name = "Form1";
    Text = "Form1";
    ResumeLayout(false);
}
```

### Support for code style settings

The above code was generated for default C# code style settings, thus `this` access qualifier was removed in the Preview 3 version.

To preserve legacy code generation style in `InitializeComponent` method, set style preferences to legacy values in [`.editorconfig` file](https://learn.microsoft.com/visualstudio/ide/create-portable-custom-editor-options).

```ini
[*.designer.cs]

# this. preferences
dotnet_style_qualification_for_event = true
dotnet_style_qualification_for_field = true
dotnet_style_qualification_for_method = true
dotnet_style_qualification_for_property = true

[*.vb]

# Me. preferences
dotnet_style_qualification_for_event = true
dotnet_style_qualification_for_field = true
dotnet_style_qualification_for_method = true
dotnet_style_qualification_for_property = true
```

### Support for implicit usings property

Namespace names were removed from the type names in Preview 3 version. They are not needed for type resolution because design time serialization looks up the [implicit usings](https://learn.microsoft.com/dotnet/core/tutorials/top-level-templates#implicit-using-directives) property, available in C# starting with .NET 6 for C#, from the project file:

```xml
<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>
```

When implicit usings property is disabled in the C# project file, namespace names are generated.

### Similar changes are present in Visual Basic



Code generated by VisualStudio v17.4 or earlier:

```vb
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
    Me.Button1 = New System.Windows.Forms.Button()
    Me.SuspendLayout()
    '
    'Button1
    '
    Me.Button1.Location = New System.Drawing.Point(58, 60)
    Me.Button1.Name = "Button1"
    Me.Button1.Size = New System.Drawing.Size(136, 69)
    Me.Button1.TabIndex = 0
    Me.Button1.Text = "Button1"
    Me.Button1.UseVisualStyleBackColor = True
    '
    'Form1
    '
    Me.AutoScaleDimensions = New System.Drawing.SizeF(10.0!, 25.0!)
    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
    Me.ClientSize = New System.Drawing.Size(270, 208)
    Me.Controls.Add(Me.Button1)
    Me.Name = "Form1"
    Me.Text = "Form1"
    Me.ResumeLayout(False)

End Sub
```

Code generated by VisualStudio v17.5 Preview 3, or newer:

```vb
<System.Diagnostics.DebuggerStepThrough()>
Private Sub InitializeComponent()
    Button1 = New Button()
    SuspendLayout()
    ' 
    ' Button1
    ' 
    Button1.Location = New Point(58, 60)
    Button1.Name = "Button1"
    Button1.Size = New Size(136, 69)
    Button1.TabIndex = 0
    Button1.Text = "Button1"
    Button1.UseVisualStyleBackColor = True
    ' 
    ' Form1
    ' 
    AutoScaleDimensions = New SizeF(10.0F, 25.0F)
    AutoScaleMode = AutoScaleMode.Font
    ClientSize = New Size(270, 208)
    Controls.Add(Button1)
    Name = "Form1"
    Text = "Form1"
    ResumeLayout(False)
End Sub
```

## Summary

New code-behind in WinForm apps looks differently because it follows code style settings defined for the project. Under the covers, the design time serialization was redesigned in order to move from `EnvDTE.CodeModel` to `Roslyn`. We are planning to build upon this foundation in the future Visual Studio releases. Code-behind generated by the older releases will load into v17.5 Preview 3 or later releases and will work as expected. Code-behind generated by v17.5 Preview 3 can be loaded in the previous releases of the Visual Studio, but we are considering generating modern code that might not be supported by the previous versions of deserializer.

---

### Src System Windows Forms TaskDialog Issue AccessViolation NavigationInButtonClicked (`docs/src/System/Windows/Forms/TaskDialog/Issue_AccessViolation_NavigationInButtonClicked.md`)

# Windows Task Dialog Issue

## Access Violation when receiving [`TDN_NAVIGATED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-navigated) within [`TDN_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-button-clicked)

An Access violation can occur when receiving a navigation notification ([`TDN_NAVIGATED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-navigated))
within a [`TDN_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-button-clicked)
notification (e.g. due to running the message loop) and then returning `S_OK`.
 
* Run the code.
* Click on the "My Custom Button" button.
* Notice that the dialog navigates and an inner dialog shows.
* Close the inner dialog by clicking the OK button.
* **Issue:** In most cases, an access violation occurs now (if not, try again a
  few times).
* Notice the problem also occurs when you (after the navigation) first close
  the original dialog, and then close the inner dialog.
* The problem can be avoided by returning `S_FALSE` from the `TDN_BUTTON_CLICKED`
  notification.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Src System Windows Forms TaskDialog Issue AccessViolation NavigationInRadioButtonClicked (`docs/src/System/Windows/Forms/TaskDialog/Issue_AccessViolation_NavigationInRadioButtonClicked.md`)

# Windows Task Dialog Issue

## Access Violation when receiving [`TDN_NAVIGATED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-navigated) within [`TDN_RADIO_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-radio-button-clicked)

An Access Violation occurs when receiving a navigation notification
([`TDN_NAVIGATED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-navigated))
within a [`TDN_RADIO_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-radio-button-clicked)
notification (e.g. due to running the message loop).
 
* Run the code and select one of the radio buttons.
* Notice the dialog has navigated and an inner dialog is opened.
* Close the inner dialog.
* **Issue:** Notice the application crashes with an access violation.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Src System Windows Forms TaskDialog Issue ButtonClickHandlerCalledTwice (`docs/src/System/Windows/Forms/TaskDialog/Issue_ButtonClickHandlerCalledTwice.md`)

# Windows Task Dialog Issue

## [`TDN_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-button-clicked) notification sent twice when pressing a button with its access key

When you "click" a button by pressing its access key (mnemonic) and the dialog
is still open when the message loop continues, the [`TDN_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-button-clicked)
notification is sent twice instead of once.
 
* Run the code.
* Click one of the buttons with the mouse, or press space or enter, and notice
  that the counter increments by 1.
* **Issue:** Press <kbd>Alt</kbd>+<kbd>M</kbd> or <kbd>Alt</kbd>+<kbd>N</kbd> and 
  notice the counter increments by 2.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Src System Windows Forms TaskDialog Issue RadioButton InfiniteLoop (`docs/src/System/Windows/Forms/TaskDialog/Issue_RadioButton_InfiniteLoop.md`)

# Windows Task Dialog Issue

## Infinite loop with radio buttons

An infinite loop occurs when sending a
[`TDM_CLICK_RADIO_BUTTON`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdm-click-radio-button) message within a
[`TDN_RADIO_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-radio-button-clicked) notification.
 
* Run the code and select the second radio button.
* **Issue:** Notice that the GUI doesn't respond any more. When debugging, you can see that
  the callback is flooded with `TDN_RADIO_BUTTON_CLICKED` notifications even though we
  don't send any more messages to the dialog.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

### Src System Windows Forms TaskDialog Issue RadioButton WeirdBehavior (`docs/src/System/Windows/Forms/TaskDialog/Issue_RadioButton_WeirdBehavior.md`)

# Windows Task Dialog Issue

## Weird behavior with radio buttons

Weird behavior occurs when running the message loop within an
[`TDN_RADIO_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-radio-button-clicked)
notification.

* Run the code.
* Notice that within the
  [`TDN_TIMER`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-timer) notification, a
  [`TDM_CLICK_RADIO_BUTTON`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdm-click-radio-button) is
  sent to select the second radio button which causes an inner dialog to be shown within
  the [`TDN_RADIO_BUTTON_CLICKED`](https://docs.microsoft.com/en-us/windows/desktop/Controls/tdn-radio-button-clicked)
  notification, but the radio button is only selected after 
  the inner dialog is closed (and therefore the notification handler returns).<br>
  While that seems like a strange/undesired behavior, it is actually the documented behavior:
  > "The specified radio button ID is sent to the TaskDialogCallbackProc callback function
  as part of a TDN_RADIO_BUTTON_CLICKED notification code. After the callback function
  returns, the radio button will be selected."

  (For the .NET implementation that has the `TaskDialogRadioButton.CheckedChanged` event
  that is expected to show already the new state, this can be worked-around by ignoring
  `TDN_RADIO_BUTTON_CLICKED` notifications caused by the code itself, and instead raising
  the events after sending the `TDM_CLICK_RADIO_BUTTON` message.)
  However, this special behavior might be related to the following issue (and the other
  code samples regarding radio buttons):  
* When you click one of the radio buttons and then immediately close the inner dialog,
  everything works.
* Now try the following: Click the first radio button (but do NOT close the inner dialog),
  then click the second radio button.
* Now close the most inner dialog (showing call count 2), and then the other inner dialog.
* **Issue:** Notice that the dialog changed the selection of the radio button and shows the inner
  dialog again. When you close it, even more inner dialogs open.
* During that time, when you focus the original dialog, it will switch the selected radio
  button again.

```
/* Detailed source-code truncated for AI context efficiency. */
```

---

--- METRICS ---
- Files Extracted: 60
- Estimated Token Budget: ~92554 tokens
- Canonical Reference: https://codewiki.google/github.com/dotnet/winforms
