From e9cd1314374717b0f043d3806c79edc46e3e08c0 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:53:09 -0700 Subject: [PATCH 01/51] Update base copilot instructions --- .github/copilot-instructions.md | 5 +++++ AGENTS.md | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 AGENTS.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 7b29b75140..f7f8b8bd99 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,6 +8,11 @@ IMPORTANT: For any Markdown files generated by AI, always disclose that they wer ai-usage: ai-generated ``` +## New articles + +- New articles must follow a template in the /.github/projects/article-templates/ folder. +- If you don't know which template to use, ask. + ## Terminology - Unless otherwise specified, all .NET content refers to modern .NET (not .NET Framework). diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..aa42579636 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,4 @@ +There are two distinct .NET Desktop products documented in this repository: + +- Windows Forms (known as winforms): located in the ./dotnet-desktop-guide/winforms/ folder +- Windows Presentation Foundation (known as WPF): located in the ./dotnet-desktop-guide/wpf/ folder From 1144ba568d0f70dc737124a97eb3f4e94612cf95 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:53:33 -0700 Subject: [PATCH 02/51] Create project folder with supporting materials --- .../clipboard-dataobject-net10-changes.md | 186 ++++++++++++++++++ .../clipboard/temp-clipboard-articles.md | 92 +++++++++ 2 files changed, 278 insertions(+) create mode 100644 .github/projects/clipboard/clipboard-dataobject-net10-changes.md create mode 100644 .github/projects/clipboard/temp-clipboard-articles.md diff --git a/.github/projects/clipboard/clipboard-dataobject-net10-changes.md b/.github/projects/clipboard/clipboard-dataobject-net10-changes.md new file mode 100644 index 0000000000..d5ce5b770f --- /dev/null +++ b/.github/projects/clipboard/clipboard-dataobject-net10-changes.md @@ -0,0 +1,186 @@ +# 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`** in .NET 9 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()` APIs or serialize manually as `string` or `byte[]` data. +- **Always** use `TryGetData()` 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`** of the above primitive types. For maximum resilience, avoid `string[]` and `List` 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` – constrained deserialization of data + +Several overloads of `TryGetData` 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`, 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` – write custom types without BinaryFormatter + +`SetDataAsJson` 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` 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` 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(string format, T data)` and `DataObject.SetDataAsJson(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(string format, T data)` | Clears the clipboard and stores JSON data in a new `DataObject`. | Equivalent VB method: `ClipboardProxy.SetDataAsJson(Of T)`. | +| `DataObject.TryGetData(string format, Func 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(string format, bool autoConvert, out T data)` | Same as above without a resolver; does not fall back to binary serialization. | | +| `DataObject.TryGetData(string format, out T data)` | Uses default `autoConvert=true`; no resolver. | | +| `DataObject.TryGetData(out T data)` | Infers the format from the full name of `T`. | | +| `Clipboard.TryGetData` 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` | 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 + + + + ``` + + 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 + + true + + ``` + +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` 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` 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) \ No newline at end of file diff --git a/.github/projects/clipboard/temp-clipboard-articles.md b/.github/projects/clipboard/temp-clipboard-articles.md new file mode 100644 index 0000000000..5f5cbb8a87 --- /dev/null +++ b/.github/projects/clipboard/temp-clipboard-articles.md @@ -0,0 +1,92 @@ +# Clipboard-Related Articles in Windows Forms Documentation + +This document lists all articles in the Windows Forms documentation that reference clipboard functionality. This is intended as a reference for updating documentation about new clipboard features. + +## Core Clipboard Documentation + +### Main Articles + +1. **Drag-and-Drop Operations and Clipboard Support** + - **Path:** `dotnet-desktop-guide\winforms\advanced\drag-and-drop-operations-and-clipboard-support.md` + - **Description:** Overview article covering both drag-and-drop and clipboard functionality + - **Content:** Main hub for clipboard operations + +1. **How to: Add Data to the Clipboard** + - **Path:** `dotnet-desktop-guide\winforms\advanced\how-to-add-data-to-the-clipboard.md` + - **Description:** Step-by-step guide for adding data to the clipboard + - **Content:** Covers `Clipboard.SetText()`, `SetData()`, and `SetDataObject()` methods + +1. **How to: Retrieve Data from the Clipboard** + - **Path:** `dotnet-desktop-guide\winforms\advanced\how-to-retrieve-data-from-the-clipboard.md` + - **Description:** Guide for retrieving data from the clipboard + - **Content:** Covers `Clipboard.GetText()`, `GetData()`, and `ContainsData()` methods + +### Security and Permissions + +1. **Additional Security Considerations in Windows Forms** + - **Path:** `dotnet-desktop-guide\winforms\additional-security-considerations-in-windows-forms.md` + - **Description:** Contains a dedicated "Clipboard Access" section discussing security permissions + - **Content:** Security implications and permission requirements for clipboard access + +1. **Windows Forms and Unmanaged Applications** + - **Path:** `dotnet-desktop-guide\winforms\advanced\windows-forms-and-unmanaged-applications.md` + - **Description:** Discusses clipboard access in the context of COM interop scenarios + - **Content:** References clipboard in COM interoperability context + +### Control-Specific Articles + +1. **How to: Create a Read-Only Text Box (Windows Forms)** + - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-create-a-read-only-text-box-windows-forms.md` + - **Description:** Mentions clipboard shortcuts (Ctrl+C, Ctrl+V) work in read-only text boxes + - **Content:** Brief reference to clipboard functionality preservation + +1. **How to: Put Quotation Marks in a String (Windows Forms)** + - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-put-quotation-marks-in-a-string-windows-forms.md` + - **Description:** Example includes copying text to clipboard + - **Content:** Code example using `Clipboard.SetText()` + +1. **How to: Select Text in the Windows Forms TextBox Control** + - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-select-text-in-the-windows-forms-textbox-control.md` + - **Description:** Mentions clipboard operations (copy/cut/paste) work with selected text + - **Content:** References standard clipboard keyboard shortcuts + +## Code Snippets and Examples + +### Snippet Locations + +- **Path:** `dotnet-desktop-guide\samples\snippets\winforms\*` +- **Files Found:** + - Various code examples demonstrating clipboard operations. + - Both C# and VB.NET implementations. + - Examples of text, image, and custom data formats. + +## Navigation and TOC References + +### Table of Contents + +- **Path:** `dotnet-desktop-guide\winforms\advanced\toc.yml` +- **Content:** Contains navigation entries for clipboard-related articles + +## Summary + +This repository contains comprehensive documentation covering: + +- **3 primary clipboard articles** (overview, adding data, retrieving data). +- **Multiple supporting articles** that reference clipboard functionality. +- **Security considerations** for clipboard access. +- **Control-specific guidance** on clipboard behavior. +- **Code examples** in both C# and VB.NET. + +## Notes for Updates + +When adding new clipboard features: + +1. Update the main overview article first. +1. Consider if new how-to guides are needed. +1. Update security considerations if permissions change. +1. Add code snippets for new functionality. +1. Update control-specific articles if behavior changes. + +--- + +*Generated on September 25, 2025 as a reference for clipboard feature documentation updates.* From c361a6a0244809f5c74b9937c94f9b3458ca38f9 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:53:58 -0700 Subject: [PATCH 03/51] Generate a plan as an instructions file based on the supporting information and the desire to upgrade clipboard code --- .../clipboard-plan.instructions.md | 230 ++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 .github/instructions/clipboard-plan.instructions.md diff --git a/.github/instructions/clipboard-plan.instructions.md b/.github/instructions/clipboard-plan.instructions.md new file mode 100644 index 0000000000..525762f9ec --- /dev/null +++ b/.github/instructions/clipboard-plan.instructions.md @@ -0,0 +1,230 @@ +--- +description: The plan for updating the Clipboard content +--- + +# Plan to Update WinForms Clipboard Documentation for .NET 10 + +## LLM instructions +If you're creating article files, use the [templates](/.github/projects/article-templates/) folder to find a suitable article template. + +IMPORTANT! Add the following files as context: +- [Engineer's overview on the changes in .NET 10 for Clipboard](/.github/projects/clipboard/clipboard-dataobject-net10-changes.md) +- [Summary of existing articles](/.github/projects/clipboard/temp-clipboard-articles.md) + +## Executive Summary + +The .NET 10 release introduces significant changes to the Windows Forms clipboard and drag-and-drop functionality, primarily driven by the removal of `BinaryFormatter` from the runtime. This requires updating existing documentation and creating new articles to cover the new type-safe APIs, JSON serialization, and migration guidance. + +## Current Documentation Inventory + +### Existing Articles to Update: + +1. **`drag-and-drop-operations-and-clipboard-support.md`** - Main overview article +2. **`how-to-add-data-to-the-clipboard.md`** - Adding data guide +3. **`how-to-retrieve-data-from-the-clipboard.md`** - Retrieving data guide +4. **`additional-security-considerations-in-windows-forms.md`** - Security section needs updates + +### Existing Code Snippets: + +- **`dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`** +- **`dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`** + +## Detailed Update Plan + +### Phase 1: Create New Comprehensive Overview Article + +**New Article: `clipboard-dataobject-net10.md`** + +- **Location**: dontnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +- **Priority**: High +- **Content Focus**: + - Overview of .NET 10 changes and BinaryFormatter removal + - Comparison table: old vs new APIs + - Best practices for type-safe clipboard operations + - Migration guide from legacy methods + - Security improvements and implications +- **Target Audience**: Developers migrating existing applications +- **Estimated Length**: 2,000-2,500 words + +### Phase 2: Update Existing Core Articles + +#### 2.1 Update Main Overview (`drag-and-drop-operations-and-clipboard-support.md`) + +- **Changes Needed**: + - Add .NET 10 compatibility section + - Update introduction to mention new type-safe APIs + - Add links to new migration guide + - Update "In This Section" with new articles +- **Priority**: High + +#### 2.2 Comprehensive Rewrite (`how-to-add-data-to-the-clipboard.md`) + +- **Major Changes**: + - Add new section on `SetDataAsJson()` method + - Update best practices to recommend new APIs first + - Add warning about BinaryFormatter deprecation + - Show examples of recommended built-in types + - Add migration examples from old to new methods +- **New Sections**: + - "Adding Custom Types with JSON Serialization" + - "Working with Recommended Built-in Types" + - "Migrating from Legacy SetData Methods" +- **Priority**: High + +#### 2.3 Comprehensive Rewrite (`how-to-retrieve-data-from-the-clipboard.md`) + +- **Major Changes**: + - Replace `GetData()` examples with `TryGetData()` methods + - Add type-safe retrieval examples + - Cover resolver patterns for legacy data + - Add error handling best practices +- **New Sections**: + - "Type-Safe Data Retrieval with `TryGetData`" + - "Handling Legacy Binary Data" + - "Working with Custom JSON Types" +- **Priority**: High + +#### 2.4 Update Security Article (`additional-security-considerations-in-windows-forms.md`) + +- **Changes Needed**: + - Update clipboard security section for .NET 10 + - Add information about BinaryFormatter security implications + - Document new runtime configuration switches + - Add guidance on type resolvers for legacy support +- **Priority**: Medium + +### Phase 3: Create New Specialized Articles + +#### 3.1 New Article: `how-to-use-typed-clipboard-apis.md` + +- **Content Focus**: + - Detailed guide on `TryGetData()` methods + - Examples of all overloads + - Type resolver implementation patterns + - Error handling strategies +- **Priority**: High + +#### 3.2 New Article: `clipboard-json-serialization.md` + +- **Content Focus**: + - Using `SetDataAsJson()` effectively + - System.Text.Json considerations + - Custom type design for clipboard + - Cross-process/cross-framework compatibility +- **Priority**: Medium + +#### 3.3 New Article: `enabling-binaryformatter-clipboard-support.md` + +- **Content Focus**: + - Complete guide for legacy application migration + - Runtime configuration steps + - Security considerations and risks + - Type resolver implementation examples +- **Priority**: Medium (for legacy support) + +### Phase 4: Update Code Snippets and Examples + +#### 4.1 Create New Snippet Collections + +- **Location**: `dotnet-desktop-guide/samples/snippets/winforms/clipboard-net10/` +- **Contents**: + - `basic-json-serialization/` - SetDataAsJson examples + - `typed-retrieval/` - TryGetData examples + - `legacy-migration/` - Before/after migration examples + - `custom-resolver/` - Type resolver implementations +- **Languages**: C# and VB.NET for each example + +#### 4.2 Update Existing Snippets + +- **`VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`**: + - Add new .NET 10 examples alongside existing ones + - Mark legacy examples with version compatibility notes + - Add migration guidance in comments + +### Phase 5: Navigation and Discoverability Updates + +#### 5.1 Update Table of Contents (`toc.yml`) + +- Add new articles to the drag-and-drop section +- Reorganize clipboard articles for better flow +- Add migration guide as featured content + +#### 5.2 Update Cross-References + +- Add xref links between related articles +- Update "See also" sections across all clipboard articles +- Link to BinaryFormatter migration guidance + +## Implementation Timeline + +### Week 1-2: Foundation + +- [ ] Create comprehensive migration overview article +- [ ] Update main overview article with .NET 10 references +- [ ] Set up new code snippet structure + +### Week 3-4: Core Rewrites + +- [ ] Rewrite "How to: Add Data" article +- [ ] Rewrite "How to: Retrieve Data" article +- [ ] Create new typed APIs guide + +### Week 5-6: Specialized Content + +- [ ] Create JSON serialization guide +- [ ] Create BinaryFormatter legacy support guide +- [ ] Update security considerations + +### Week 7: Polish and Integration + +- [ ] Update all code snippets +- [ ] Update navigation and cross-references +- [ ] Review and test all examples + +## Quality Assurance Checklist + +### Content Standards + +- [ ] All articles include `ai-usage: ai-generated` frontmatter +- [ ] Follow Microsoft Writing Style Guide +- [ ] Use Oxford commas in all lists +- [ ] Number ordered lists as "1." (not sequential) +- [ ] Use complete sentences in lists with proper punctuation +- [ ] Active voice and second person throughout + +### Technical Standards + +- [ ] All code examples compile and run +- [ ] Both C# and VB.NET examples where appropriate +- [ ] API references use proper xref format +- [ ] Version compatibility clearly documented +- [ ] Security warnings appropriately placed + +### Documentation Architecture + +- [ ] Logical information hierarchy +- [ ] Clear navigation between related topics +- [ ] Appropriate use of includes for shared content +- [ ] SEO-friendly titles and descriptions + +## Success Metrics + +1. **Coverage**: All major .NET 10 clipboard APIs documented +2. **Migration Support**: Clear upgrade path from legacy APIs +3. **Developer Experience**: Easy-to-find, actionable guidance +4. **Code Quality**: All examples follow best practices +5. **Discoverability**: Proper navigation and cross-linking + +## Risk Mitigation + +### Technical Risks + +- **API Changes**: Monitor .NET 10 development for any last-minute API changes +- **Backward Compatibility**: Ensure legacy guidance remains accurate + +### Content Risks + +- **Information Overload**: Balance comprehensive coverage with readability +- **Fragmentation**: Maintain consistent messaging across all articles + +This plan ensures comprehensive coverage of the .NET 10 clipboard changes while maintaining the existing documentation structure and providing clear migration guidance for developers. From 01df98b30c4ede6fb8be686a74d0d60c80135606 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:55:22 -0700 Subject: [PATCH 04/51] Phase 1 article: Initial --- .../migration/clipboard-dataobject-net10.md | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md new file mode 100644 index 0000000000..2f05acffb3 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -0,0 +1,59 @@ +--- +title: "Windows Forms clipboard and DataObject changes in .NET 10" +description: "Learn about the major clipboard and drag-and-drop changes in .NET 10, including new type-safe APIs, JSON serialization, and migration from BinaryFormatter." +author: [your GitHub alias] +ms.author: [your Microsoft alias or a team alias] +ms.service: dotnet-desktop +ms.topic: concept-article +ms.date: 09/25/2025 +ai-usage: ai-generated + +#customer intent: As a Windows Forms developer, I want to understand the clipboard and DataObject changes in .NET 10 so that I can migrate my applications and use the new type-safe APIs. + +--- + +# Windows Forms clipboard and DataObject changes in .NET 10 + +[Introduce and explain the purpose of the article - overview of .NET 10 clipboard changes and why they matter to developers.] + +## Prerequisites + +[Prerequisites for understanding and applying these changes - .NET knowledge, Windows Forms experience, etc.] + +## Breaking changes from BinaryFormatter removal + +[Describe the main breaking changes and immediate impact on existing code.] + +## New type-safe APIs + +[Explain the new TryGetData\ and SetDataAsJson\ methods and their benefits.] + +## Recommended built-in types + +[Detail the types that work without custom serialization - primitives, arrays, System.Drawing types.] + +## Working with custom types + +[Explain JSON serialization approach and best practices for custom types.] + +## Legacy data support + +[How to handle existing binary data using NrbfDecoder and SerializationRecord.] + +## Migration strategies + +[Practical approaches for updating existing applications.] + +## Enabling BinaryFormatter support (not recommended) + +[Complete guide for legacy applications that need temporary BinaryFormatter support.] + +## Use Copilot to update types + +[Explain and give some example of using copilot to data objects.] + +## Related content + +- [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md) +- [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) +- [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) \ No newline at end of file From 6713a469f667688795cc20b5f642a9329ddc5ac4 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:56:40 -0700 Subject: [PATCH 05/51] Phase 1 article: Expand plan in the sections --- .../migration/clipboard-dataobject-net10.md | 124 ++++++++++++++++-- 1 file changed, 116 insertions(+), 8 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 2f05acffb3..5b56b46cf6 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -22,31 +22,139 @@ ai-usage: ai-generated ## Breaking changes from BinaryFormatter removal -[Describe the main breaking changes and immediate impact on existing code.] +- **Custom types no longer serialize automatically** - Objects that previously worked with `SetData()` now require explicit handling +- **`GetData()` behavior changes** - Legacy method may not retrieve data as expected +- **Legacy binary data handling** - Existing clipboard data may not be accessible without special handling +- **Common patterns that need updating**: + - Direct `SetData()` calls with custom objects + - `GetData()` retrieval without type checking + - Cross-process data sharing with complex types ## New type-safe APIs -[Explain the new TryGetData\ and SetDataAsJson\ methods and their benefits.] +- **`TryGetData()` family of methods**: + - Multiple overloads for different scenarios + - Returns boolean success indicator instead of throwing exceptions + - Type-safe retrieval with explicit type specification + - Optional resolver parameter for legacy data handling + - `autoConvert` parameter for OLE data conversion control + +- **`SetDataAsJson()` methods**: + - JSON serialization using System.Text.Json + - Automatic format inference from type name + - Custom format specification support + - Cross-process and cross-framework compatibility + +- **`ITypedDataObject` interface**: + - Enables typed data retrieval for drag-and-drop scenarios + - Must be implemented by custom data objects + - Provides compile-time type safety guarantees ## Recommended built-in types -[Detail the types that work without custom serialization - primitives, arrays, System.Drawing types.] +- **Primitive types** that work without BinaryFormatter: + - `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long` + - `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string` + - `TimeSpan` and `DateTime` + +- **Collections** of primitive types: + - Arrays of any supported primitive type + - `List` where T is a supported primitive type + - Avoid `string[]` and `List` due to null handling complexity + +- **System.Drawing types**: + - `Bitmap`, `Point`, `PointF`, `Rectangle`, `RectangleF` + - `Size`, `SizeF`, `Color` + +- **Type safety guarantees**: + - WinForms ensures only requested types are created + - Data content validation remains developer responsibility + - No size constraints on deserialized data ## Working with custom types -[Explain JSON serialization approach and best practices for custom types.] +- **JSON serialization best practices**: + - Design simple, serializable types for clipboard use + - Use System.Text.Json compatible attributes + - Avoid complex object hierarchies and circular references + - Consider serialization size and performance impact + +- **Alternative serialization strategies**: + - Manual string serialization for simple data + - Custom byte array handling for binary data + - Format-specific serialization (XML, custom protocols) + - Direct conversion to supported built-in types when possible + +- **Cross-process compatibility considerations**: + - JSON provides better cross-framework compatibility + - Consider version compatibility when designing types + - Test data exchange between different application versions ## Legacy data support -[How to handle existing binary data using NrbfDecoder and SerializationRecord.] +- **Reading legacy NRBF data** without BinaryFormatter: + - Use `NrbfDecoder` for safe binary data access + - Work with `SerializationRecord` objects instead of direct deserialization + - Extract data manually without automatic type creation + +- **Cross-version data exchange strategies**: + - Design fallback mechanisms for mixed .NET environments + - Implement version detection and compatibility layers + - Consider maintaining dual serialization approaches during migration + +- **Safe legacy data handling**: + - Always validate data structure before processing + - Implement type checking and bounds verification + - Use allow-lists for acceptable data types and values ## Migration strategies -[Practical approaches for updating existing applications.] +- **Assessment and planning**: + - Inventory existing clipboard and drag-drop functionality + - Identify custom types used in data transfer operations + - Prioritize migration based on security and functionality impact + +- **Common migration patterns**: + - Replace `GetData()` calls with `TryGetData()` + - Convert custom types to use `SetDataAsJson()` + - Update drag-drop implementations to use `ITypedDataObject` + +- **Phased migration approach**: + - Start with new development using type-safe APIs + - Update critical security-sensitive operations first + - Gradually migrate legacy functionality + - Maintain compatibility layers during transition + +- **Testing and validation strategies**: + - Test cross-process data exchange scenarios + - Validate data integrity after serialization changes + - Performance test with realistic data sizes ## Enabling BinaryFormatter support (not recommended) -[Complete guide for legacy applications that need temporary BinaryFormatter support.] +- **Security warnings and risks**: + - BinaryFormatter is inherently insecure and deprecated + - Enables arbitrary code execution through deserialization attacks + - Should only be used as temporary migration bridge + - Requires explicit opt-in through multiple configuration steps + +- **Complete configuration requirements**: + - Reference `System.Runtime.Serialization.Formatters` package + - Set `EnableUnsafeBinaryFormatterSerialization` project property to `true` + - Configure `Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization` runtime switch + - Implement security-focused type resolvers for safe operation + +- **Type resolver implementation patterns**: + - Use explicit allow-lists of permitted types + - Verify assembly names and versions + - Throw exceptions for any unauthorized types + - Never allow implicit type loading or resolution + +- **Gradual migration approach**: + - Enable BinaryFormatter support only during transition period + - Migrate high-risk operations to new APIs first + - Plan complete removal of BinaryFormatter dependency + - Monitor and log all binary deserialization operations ## Use Copilot to update types @@ -56,4 +164,4 @@ ai-usage: ai-generated - [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md) - [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) -- [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) \ No newline at end of file +- [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) From 23ddfb9e519afa70f34f6077c7250fde59c61677 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:57:40 -0700 Subject: [PATCH 06/51] Phase 1 article: Query LLM about best way to communicate; move to HTML comments --- .../migration/clipboard-dataobject-net10.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 5b56b46cf6..47f6f74e16 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -14,14 +14,44 @@ ai-usage: ai-generated # Windows Forms clipboard and DataObject changes in .NET 10 + + [Introduce and explain the purpose of the article - overview of .NET 10 clipboard changes and why they matter to developers.] ## Prerequisites + + [Prerequisites for understanding and applying these changes - .NET knowledge, Windows Forms experience, etc.] ## Breaking changes from BinaryFormatter removal + + - **Custom types no longer serialize automatically** - Objects that previously worked with `SetData()` now require explicit handling - **`GetData()` behavior changes** - Legacy method may not retrieve data as expected - **Legacy binary data handling** - Existing clipboard data may not be accessible without special handling @@ -32,6 +62,17 @@ ai-usage: ai-generated ## New type-safe APIs + + - **`TryGetData()` family of methods**: - Multiple overloads for different scenarios - Returns boolean success indicator instead of throwing exceptions @@ -52,6 +93,17 @@ ai-usage: ai-generated ## Recommended built-in types + + - **Primitive types** that work without BinaryFormatter: - `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long` - `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string` @@ -73,6 +125,17 @@ ai-usage: ai-generated ## Working with custom types + + - **JSON serialization best practices**: - Design simple, serializable types for clipboard use - Use System.Text.Json compatible attributes @@ -92,6 +155,17 @@ ai-usage: ai-generated ## Legacy data support + + - **Reading legacy NRBF data** without BinaryFormatter: - Use `NrbfDecoder` for safe binary data access - Work with `SerializationRecord` objects instead of direct deserialization @@ -109,6 +183,17 @@ ai-usage: ai-generated ## Migration strategies + + - **Assessment and planning**: - Inventory existing clipboard and drag-drop functionality - Identify custom types used in data transfer operations @@ -132,6 +217,17 @@ ai-usage: ai-generated ## Enabling BinaryFormatter support (not recommended) + + - **Security warnings and risks**: - BinaryFormatter is inherently insecure and deprecated - Enables arbitrary code execution through deserialization attacks @@ -158,6 +254,17 @@ ai-usage: ai-generated ## Use Copilot to update types + + [Explain and give some example of using copilot to data objects.] ## Related content From 47927267152af26b4eea90710050c114daa27b3b Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:59:13 -0700 Subject: [PATCH 07/51] Phase 1 article: Intro/Prereqs first draft --- .../migration/clipboard-dataobject-net10.md | 34 +++++++------------ 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 47f6f74e16..63845f2133 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -8,37 +8,29 @@ ms.topic: concept-article ms.date: 09/25/2025 ai-usage: ai-generated -#customer intent: As a Windows Forms developer, I want to understand the clipboard and DataObject changes in .NET 10 so that I can migrate my applications and use the new type-safe APIs. +#customer intent: As a Windows Forms developer, I want to understand the clipboard and DataObject changes in .NET 10 so that I can upgrade my applications and use the new type-safe APIs. --- # Windows Forms clipboard and DataObject changes in .NET 10 - +.NET 10 introduces significant changes to Windows Forms clipboard and drag-and-drop functionality, driven by the removal of `BinaryFormatter` from the .NET runtime. The `BinaryFormatter` component, which previously handled serialization of custom objects for clipboard operations and data transfer scenarios, has been removed due to serious security vulnerabilities that made it unsuitable for modern applications. This change affects how Windows Forms applications store and retrieve custom data types through clipboard operations and drag-and-drop interactions. + +The new clipboard APIs provide a more secure and type-safe approach to data transfer. Instead of relying on binary serialization, .NET 10 introduces JSON-based serialization through the `SetDataAsJson()` method and type-safe retrieval through the `TryGetData()` family of methods. These changes eliminate the security risks associated with `BinaryFormatter` while providing better error handling, improved performance for common scenarios, and explicit type safety that helps prevent runtime errors. -[Introduce and explain the purpose of the article - overview of .NET 10 clipboard changes and why they matter to developers.] +This modernization is part of broader .NET security improvements and requires Windows Forms developers to update their applications. While the changes are breaking, they offer significant benefits including enhanced security, better cross-process compatibility, and more predictable behavior. This article guides you through understanding these changes, upgrading existing code, and adopting the new recommended patterns for clipboard and drag-and-drop operations in your Windows Forms applications. ## Prerequisites - +To effectively understand and apply the clipboard changes in .NET 10, you should have: -[Prerequisites for understanding and applying these changes - .NET knowledge, Windows Forms experience, etc.] +- Experience developing Windows Forms applications in .NET. +- Basic understanding of clipboard operations and drag-and-drop functionality in Windows Forms. +- Familiarity with C# or Visual Basic .NET programming. +- Knowledge of object serialization concepts, particularly JSON serialization using `System.Text.Json`. +- Understanding of type safety and generic methods in .NET. +- Experience with error handling patterns and boolean return methods. +- Basic familiarity with .NET security concepts and the risks associated with deserialization. ## Breaking changes from BinaryFormatter removal From 03ac47f0dfeb678703b47862edf47e6ea94f5df2 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 15:59:51 -0700 Subject: [PATCH 08/51] Phase 1 article: Intro/Prereqs final draft (3 iterations) --- .../migration/clipboard-dataobject-net10.md | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 63845f2133..e52584a140 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -14,23 +14,19 @@ ai-usage: ai-generated # Windows Forms clipboard and DataObject changes in .NET 10 -.NET 10 introduces significant changes to Windows Forms clipboard and drag-and-drop functionality, driven by the removal of `BinaryFormatter` from the .NET runtime. The `BinaryFormatter` component, which previously handled serialization of custom objects for clipboard operations and data transfer scenarios, has been removed due to serious security vulnerabilities that made it unsuitable for modern applications. This change affects how Windows Forms applications store and retrieve custom data types through clipboard operations and drag-and-drop interactions. +This article explains how to upgrade Windows Forms clipboard and drag-and-drop operations to .NET 10's new type-safe APIs. You'll learn to use the new `TryGetData()` and `SetDataAsJson()` methods, understand which built-in types work without modification, and discover strategies for handling custom types and legacy data affected by `BinaryFormatter` removal. -The new clipboard APIs provide a more secure and type-safe approach to data transfer. Instead of relying on binary serialization, .NET 10 introduces JSON-based serialization through the `SetDataAsJson()` method and type-safe retrieval through the `TryGetData()` family of methods. These changes eliminate the security risks associated with `BinaryFormatter` while providing better error handling, improved performance for common scenarios, and explicit type safety that helps prevent runtime errors. - -This modernization is part of broader .NET security improvements and requires Windows Forms developers to update their applications. While the changes are breaking, they offer significant benefits including enhanced security, better cross-process compatibility, and more predictable behavior. This article guides you through understanding these changes, upgrading existing code, and adopting the new recommended patterns for clipboard and drag-and-drop operations in your Windows Forms applications. +`BinaryFormatter` was removed from the .NET runtime in .NET 9 due to security vulnerabilities, breaking existing clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and provide type-safe methods to restore this functionality while maintaining security and improving error handling and cross-process compatibility. ## Prerequisites -To effectively understand and apply the clipboard changes in .NET 10, you should have: +To understand the context and implications of these changes: + +- Familiarity with how `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. +- Understanding of the security vulnerabilities that led to `BinaryFormatter` removal (see [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide)). +- Knowledge of `System.Text.Json` serialization patterns and limitations. -- Experience developing Windows Forms applications in .NET. -- Basic understanding of clipboard operations and drag-and-drop functionality in Windows Forms. -- Familiarity with C# or Visual Basic .NET programming. -- Knowledge of object serialization concepts, particularly JSON serialization using `System.Text.Json`. -- Understanding of type safety and generic methods in .NET. -- Experience with error handling patterns and boolean return methods. -- Basic familiarity with .NET security concepts and the risks associated with deserialization. +For background on the breaking changes, see [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ## Breaking changes from BinaryFormatter removal From be5f30e24ba53375b67dea1919514d48f2f55554 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 16:01:53 -0700 Subject: [PATCH 09/51] Add additional resource to instructions --- .github/instructions/clipboard-plan.instructions.md | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/instructions/clipboard-plan.instructions.md b/.github/instructions/clipboard-plan.instructions.md index 525762f9ec..a2172b152c 100644 --- a/.github/instructions/clipboard-plan.instructions.md +++ b/.github/instructions/clipboard-plan.instructions.md @@ -10,6 +10,7 @@ If you're creating article files, use the [templates](/.github/projects/article- IMPORTANT! Add the following files as context: - [Engineer's overview on the changes in .NET 10 for Clipboard](/.github/projects/clipboard/clipboard-dataobject-net10-changes.md) - [Summary of existing articles](/.github/projects/clipboard/temp-clipboard-articles.md) +- [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/) ## Executive Summary From 3e93a6116119b8e50221529716349f0851dbc011 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 25 Sep 2025 18:14:41 -0700 Subject: [PATCH 10/51] Phase 1 article: Breaking changes section --- .../migration/clipboard-dataobject-net10.md | 98 ++++++++++++++++--- 1 file changed, 82 insertions(+), 16 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index e52584a140..3459b1b744 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -30,23 +30,89 @@ For background on the breaking changes, see [BinaryFormatter migration guide](/d ## Breaking changes from BinaryFormatter removal - +The removal of `BinaryFormatter` from .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality. + +### Custom types no longer serialize automatically + +Previously, you could place any serializable custom object on the clipboard using `SetData()`, and `BinaryFormatter` would handle serialization automatically. This pattern no longer works stating with .NET 9, but importantly, it fails silently without throwing exceptions. + +The following code doesn't work: + +```csharp +[Serializable] +public class Person +{ + public string Name { get; set; } + public int Age { get; set; } +} + +// This worked in .NET 8 and earlier but silently fails starting with .NET 9 +Person person = new Person { Name = "John", Age = 30 }; +Clipboard.SetData("MyApp.Person", person); // No data is stored + +// Later attempts to retrieve the data returns null +object data = Clipboard.GetData("MyApp.Person"); +``` + +#### Behavior you encounter + +- `SetData()` completes without throwing an exception but doesn't actually store the data. +- The clipboard operation appears to succeed from your application's perspective. +- Later attempts to retrieve the data with `GetData()` return `null`. + +#### Migration strategy + +Use the new `SetDataAsJson()` method or serialize manually to `string` or `byte[]`. See [Working with custom types](#working-with-custom-types) section for detailed guidance. + +### GetData() is obsolete - use TryGetData\() instead + +The legacy `GetData()` method is obsolete in .NET 10. Even for scenarios where it might still return data, migrate to the new type-safe `TryGetData()` methods that provide better error handling and type safety. + +**Obsolete code that should be avoided:** + +```csharp +// DON'T USE - GetData() is obsolete in .NET 10 +object data = Clipboard.GetData("MyApp.Person"); // Obsolete method + +// Always returns null on a custom object type +if (data != null) +{ + Person person = (Person)data; // Unsafe casting + ProcessPerson(person); +} +``` + +**Modern approach using TryGetData\():** + +```csharp +// USE THIS - Type-safe approach with TryGetData() +if (Clipboard.TryGetData("MyApp.Person", out Person person)) +{ + ProcessPerson(person); // person is guaranteed to be the correct type +} +else +{ + // Handle the case where data isn't available or is wrong type + ShowError("Unable to retrieve person data from clipboard"); +} +``` + +#### Benefits of TryGetData\(): + +- **Type safety**: No need for casting - the method returns the exact type you request. +- **Clear error handling**: Returns boolean success indicator instead of null/exception patterns. +- **Future-proof**: Designed to work with new serialization methods and legacy data support. + +#### How to identify affected code + +Look for: + +- Any `GetData()` calls - the entire method is obsolete regardless of data type. +- `DataObject.GetData()` and `IDataObject.GetData()` usage in drag-and-drop operations. + +#### Migration strategy -- **Custom types no longer serialize automatically** - Objects that previously worked with `SetData()` now require explicit handling -- **`GetData()` behavior changes** - Legacy method may not retrieve data as expected -- **Legacy binary data handling** - Existing clipboard data may not be accessible without special handling -- **Common patterns that need updating**: - - Direct `SetData()` calls with custom objects - - `GetData()` retrieval without type checking - - Cross-process data sharing with complex types +Replace all `GetData()` usage with type-safe `TryGetData()` methods. See [New type-safe APIs](#new-type-safe-apis) section for comprehensive examples of all overloads. ## New type-safe APIs From 53b9e8cacaf273b5ee0681eae5abaae5e69636c4 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 11:24:04 -0700 Subject: [PATCH 11/51] Move plan file --- ...oard-plan.instructions.md => plan.clipboard.instructions.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/instructions/{clipboard-plan.instructions.md => plan.clipboard.instructions.md} (98%) diff --git a/.github/instructions/clipboard-plan.instructions.md b/.github/instructions/plan.clipboard.instructions.md similarity index 98% rename from .github/instructions/clipboard-plan.instructions.md rename to .github/instructions/plan.clipboard.instructions.md index a2172b152c..cd44257df4 100644 --- a/.github/instructions/clipboard-plan.instructions.md +++ b/.github/instructions/plan.clipboard.instructions.md @@ -9,8 +9,8 @@ If you're creating article files, use the [templates](/.github/projects/article- IMPORTANT! Add the following files as context: - [Engineer's overview on the changes in .NET 10 for Clipboard](/.github/projects/clipboard/clipboard-dataobject-net10-changes.md) +- [BinaryFormatter migration guide](https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-migration-guide/) - [Summary of existing articles](/.github/projects/clipboard/temp-clipboard-articles.md) -- [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/) ## Executive Summary From 54b724168715057667918fe6752c32d7681d4c0e Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 11:24:44 -0700 Subject: [PATCH 12/51] Phase 1 article: Add summary section --- .../winforms/migration/clipboard-dataobject-net10.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 3459b1b744..2ddfe488d1 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -28,6 +28,10 @@ To understand the context and implications of these changes: For background on the breaking changes, see [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). +## Summary of the changes + + + ## Breaking changes from BinaryFormatter removal The removal of `BinaryFormatter` from .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality. From 6e98618865471cadbf6d025fff0b5c95360f0e16 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 11:25:45 -0700 Subject: [PATCH 13/51] Phase 1 article: Finish 2 more sections --- .../migration/clipboard-dataobject-net10.md | 343 +++++++++++++++--- 1 file changed, 292 insertions(+), 51 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 2ddfe488d1..b4734473c4 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -120,66 +120,307 @@ Replace all `GetData()` usage with type-safe `TryGetData()` methods. See [New ## New type-safe APIs - +.NET 10 introduces three new API families that provide type safety, better error handling, and JSON serialization support for clipboard and drag-and-drop operations. -- **`TryGetData()` family of methods**: - - Multiple overloads for different scenarios - - Returns boolean success indicator instead of throwing exceptions - - Type-safe retrieval with explicit type specification - - Optional resolver parameter for legacy data handling - - `autoConvert` parameter for OLE data conversion control +### TryGetData\() methods -- **`SetDataAsJson()` methods**: - - JSON serialization using System.Text.Json - - Automatic format inference from type name - - Custom format specification support - - Cross-process and cross-framework compatibility +The `TryGetData()` family replaces the obsolete `GetData()` method with type-safe retrieval and clear success/failure indication. -- **`ITypedDataObject` interface**: - - Enables typed data retrieval for drag-and-drop scenarios - - Must be implemented by custom data objects - - Provides compile-time type safety guarantees +#### Basic type-safe retrieval -## Recommended built-in types +```csharp +// Simple retrieval with standard formats +if (Clipboard.TryGetData(DataFormats.Text, out string textData)) +{ + ProcessTextData(textData); +} - +// Works with any supported type using custom formats +if (Clipboard.TryGetData("NumberData", out int numberData)) +{ + ProcessNumber(numberData); +} + +// Using standard formats for common data types +if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText)) +{ + ProcessUnicodeText(unicodeText); +} + +// Control OLE data conversion +if (Clipboard.TryGetData(DataFormats.Text, autoConvert: false, out string rawText)) +{ + ProcessRawText(rawText); +} + +// Working with file drops using standard format +if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) +{ + ProcessFiles(files); +} +``` + +#### Custom JSON types + +```csharp +// Retrieve custom types stored with SetDataAsJson() +if (Clipboard.TryGetData("Person", out Person person)) +{ + ProcessPerson(person); +} + +// Handle application-specific data formats +if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings)) +{ + ApplySettings(settings); +} + +// Work with complex custom objects +if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) +{ + LoadDocument(doc); +} +``` + +#### Type resolver for legacy binary data (requires BinaryFormatter - not recommended) + +> [!WARNING] +> Type resolvers only work when BinaryFormatter support is enabled, which is **not recommended** due to security risks. See [Enabling BinaryFormatter support](#enabling-binaryformatter-support-not-recommended) for more information. + +Type resolvers allow you to handle legacy binary data by mapping type names to actual types during deserialization: + +```csharp +// Create a type resolver that maps old type names to current types +Func resolver = typeName => +{ + // Only allow specific known safe types + return typeName.FullName switch + { + "MyApp.Person" => typeof(Person), + "MyApp.Settings" => typeof(AppSettings), + "System.String" => typeof(string), + "System.Int32" => typeof(int), + _ => throw new InvalidOperationException($"Type not allowed: {typeName.FullName}") + }; +}; + +// Use resolver with legacy binary data +if (Clipboard.TryGetData("LegacyFormat", resolver, out Person person)) +{ + ProcessPerson(person); +} + +// Combined resolver with conversion control +if (Clipboard.TryGetData("OldCustomData", resolver, autoConvert: true, out MyType data)) +{ + ProcessCustomData(data); +} +``` + +**Important security considerations for type resolvers:** + +- Always use an explicit allow-list of permitted types +- Never allow dynamic type loading or assembly resolution +- Validate type names before mapping to actual types +- Throw exceptions for any unauthorized or unknown types +- Consider this a temporary bridge during migration only + +### SetDataAsJson\() methods + +These methods provide automatic JSON serialization using `System.Text.Json` with type-safe storage. + +#### Automatic format inference + +```csharp +var person = new Person { Name = "Alice", Age = 25 }; + +// Format automatically inferred from type name +Clipboard.SetDataAsJson(person); // Uses "Person" as format + +// Later retrieval +if (Clipboard.TryGetData("Person", out Person retrievedPerson)) +{ + Console.WriteLine($"Retrieved: {retrievedPerson.Name}"); +} +``` + +#### Custom format specification + +```csharp +var settings = new AppSettings { Theme = "Dark", AutoSave = true }; + +// Custom format for better organization +Clipboard.SetDataAsJson("MyApp.Settings", settings); + +// Multiple formats for the same data +Clipboard.SetDataAsJson("Config.V1", settings); +Clipboard.SetDataAsJson("AppConfig", settings); +``` + +### ITypedDataObject interface + +This interface enables type-safe drag-and-drop operations by extending `IDataObject` with typed methods. + +#### Implementation in custom DataObject + +```csharp +public class TypedDataObject : DataObject, ITypedDataObject +{ + public bool TryGetData(string format, out T data) + { + // Implementation uses new type-safe logic + return base.TryGetData(format, out data); + } + + // This overload requires BinaryFormatter support (not recommended) + public bool TryGetData(string format, Func resolver, out T data) + { + return base.TryGetData(format, resolver, out data); + } +} + +#### Usage in drag-and-drop scenarios + +```csharp +private void OnDragDrop(object sender, DragEventArgs e) +{ + if (e.Data is ITypedDataObject typedData) + { + // Type-safe retrieval from drag data using standard formats + if (typedData.TryGetData(DataFormats.FileDrop, out string[] files)) + { + ProcessDroppedFiles(files); + } + + // Using standard text formats + if (typedData.TryGetData(DataFormats.Text, out string text)) + { + ProcessDroppedText(text); + } + + // Custom formats for application-specific data + if (typedData.TryGetData("CustomItem", out MyItem item)) + { + ProcessCustomItem(item); + } + } +} +``` + +## Types that don't require JSON serialization + +Many built-in .NET types continue to work with clipboard operations without requiring JSON serialization or `BinaryFormatter` support. These types are automatically serialized into the .NET Remoting Binary Format (NRBF), which provides efficient storage while maintaining type safety. + +These types use the .NET Remoting Binary Format (NRBF) for serialization, the same efficient binary format used by the legacy `BinaryFormatter`. Key characteristics of NRBF serialization: + +- **Compact binary representation** for efficient storage and transfer. +- **Built-in type information** preserves exact .NET types during round-trip operations. +- **Cross-process compatibility** works between different .NET applications. +- **No custom serialization required** - types serialize automatically. + +For detailed technical information about NRBF, see the [.NET Remoting Binary Format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). + +Classes that support working with NRBF-encoded data are implemented in the namespace. -- **Primitive types** that work without BinaryFormatter: - - `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long` - - `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string` - - `TimeSpan` and `DateTime` +### Type safety guarantees -- **Collections** of primitive types: - - Arrays of any supported primitive type - - `List` where T is a supported primitive type - - Avoid `string[]` and `List` due to null handling complexity +Windows Forms provides several safety mechanisms for these built-in types: -- **System.Drawing types**: - - `Bitmap`, `Point`, `PointF`, `Rectangle`, `RectangleF` - - `Size`, `SizeF`, `Color` +- **Exact type matching**: `TryGetData()` ensures only the requested type is returned. +- **Automatic validation**: WinForms validates type compatibility during deserialization. +- **No arbitrary code execution**: Unlike custom types with BinaryFormatter, these types can't execute malicious code. +- **Content validation required**: Developers must still validate data content and ranges for their application logic. +- **No size constraints**: Large arrays or bitmaps are not automatically limited (monitor memory usage). -- **Type safety guarantees**: - - WinForms ensures only requested types are created - - Data content validation remains developer responsibility - - No size constraints on deserialized data +### Supported primitive types + +The following primitive types work seamlessly with clipboard and `DataObject` operations without requiring any custom serialization or configuration. These built-in .NET types are automatically handled by the clipboard system: + +- `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long` +- `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string` +- `TimeSpan` and `DateTime` + +The following examples show how these primitive types work directly with `SetData()` and `TryGetData()` methods: + +```csharp +// Numeric types +Clipboard.SetData("MyInt", 42); +Clipboard.SetData("MyDouble", 3.14159); +Clipboard.SetData("MyDecimal", 123.45m); + +// Text and character types +Clipboard.SetData("MyString", "Hello World"); +Clipboard.SetData("MyChar", 'A'); + +// Boolean and date/time types +Clipboard.SetData("MyBool", true); +Clipboard.SetData("MyDateTime", DateTime.Now); +Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)); + +// Later retrieval with type safety +if (Clipboard.TryGetData("MyInt", out int value)) +{ + ProcessInteger(value); +} +``` + +### Collections of primitive types + +Arrays and generic lists of supported primitive types work without additional configuration, but there are some important limitations to be aware of: + +- All array and list elements must be of supported primitive types. +- Avoid `string[]` and `List` due to null value handling complexity in NRBF format. +- Use individual string storage or JSON serialization for string collections instead. + +The following exmaples show how arrays and lists can be set on the clipboard: + +```csharp +// Arrays of primitive types +int[] numbers = { 1, 2, 3, 4, 5 }; +Clipboard.SetData("NumberArray", numbers); + +double[] coordinates = { 1.0, 2.5, 3.7 }; +Clipboard.SetData("Coordinates", coordinates); + +// Generic lists +List intList = new List { 10, 20, 30 }; +Clipboard.SetData("IntList", intList); + +// Retrieval maintains type safety +if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers)) +{ + ProcessNumbers(retrievedNumbers); +} +``` + +### System.Drawing types + +Common graphics types from the `System.Drawing` namespace work seamlessly with clipboard and `DataObject` operations. These types are particularly useful for applications that work with visual elements and need to transfer drawing-related data between components or applications. However, when using `Bitmap` objects, be mindful of memory usage for large images. The following types are supported: + +- `Point`, `PointF`, `Rectangle`, `RectangleF` +- `Size`, `SizeF`, `Color` +- `Bitmap` (consider memory usage for large images) + +The following examples show how these graphics types can be used with clipboard operations: + +```csharp +// Geometric types +Point location = new Point(100, 200); +Rectangle bounds = new Rectangle(0, 0, 500, 300); +Size dimensions = new Size(800, 600); + +Clipboard.SetData("Location", location); +Clipboard.SetData("Bounds", bounds); +Clipboard.SetData("Size", dimensions); + +// Color information +Color backgroundColor = Color.FromArgb(255, 128, 64, 192); +Clipboard.SetData("BackColor", backgroundColor); + +// Bitmap data (use with caution for large images) +Bitmap smallIcon = new Bitmap(16, 16); +Clipboard.SetData("Icon", smallIcon); +``` ## Working with custom types From b9db3a49a7740b9eddf3adbd26ac5cccfad22efe Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 11:41:11 -0700 Subject: [PATCH 14/51] Phase 1 article: Update prereqs --- .../winforms/migration/clipboard-dataobject-net10.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index b4734473c4..9f32301617 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -20,13 +20,16 @@ This article explains how to upgrade Windows Forms clipboard and drag-and-drop o ## Prerequisites -To understand the context and implications of these changes: +To understand the context and implications of these changes you shuold understand the folowing: - Familiarity with how `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. -- Understanding of the security vulnerabilities that led to `BinaryFormatter` removal (see [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide)). +- The security vulnerabilities that led to `BinaryFormatter` removal. - Knowledge of `System.Text.Json` serialization patterns and limitations. -For background on the breaking changes, see [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). +For more information, see: + +- [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide). +- [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ## Summary of the changes From 64a8c2e9755de546fc067d9e62cc5f11961afad7 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 11:41:40 -0700 Subject: [PATCH 15/51] Phase 1 article: Remove sections I think are already covered well enough --- .../migration/clipboard-dataobject-net10.md | 62 ------------------- 1 file changed, 62 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 9f32301617..2af3d7734b 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -455,68 +455,6 @@ EXPAND THIS OUTLINE: Provide comprehensive guidance that: - Consider version compatibility when designing types - Test data exchange between different application versions -## Legacy data support - - - -- **Reading legacy NRBF data** without BinaryFormatter: - - Use `NrbfDecoder` for safe binary data access - - Work with `SerializationRecord` objects instead of direct deserialization - - Extract data manually without automatic type creation - -- **Cross-version data exchange strategies**: - - Design fallback mechanisms for mixed .NET environments - - Implement version detection and compatibility layers - - Consider maintaining dual serialization approaches during migration - -- **Safe legacy data handling**: - - Always validate data structure before processing - - Implement type checking and bounds verification - - Use allow-lists for acceptable data types and values - -## Migration strategies - - - -- **Assessment and planning**: - - Inventory existing clipboard and drag-drop functionality - - Identify custom types used in data transfer operations - - Prioritize migration based on security and functionality impact - -- **Common migration patterns**: - - Replace `GetData()` calls with `TryGetData()` - - Convert custom types to use `SetDataAsJson()` - - Update drag-drop implementations to use `ITypedDataObject` - -- **Phased migration approach**: - - Start with new development using type-safe APIs - - Update critical security-sensitive operations first - - Gradually migrate legacy functionality - - Maintain compatibility layers during transition - -- **Testing and validation strategies**: - - Test cross-process data exchange scenarios - - Validate data integrity after serialization changes - - Performance test with realistic data sizes - ## Enabling BinaryFormatter support (not recommended) +> [!CAUTION] +> `BinaryFormatter` support is **not recommended** and should only be used as a temporary migration bridge. This section is provided for legacy applications that cannot immediately migrate to the new type-safe APIs. + +If your application absolutely must continue using `BinaryFormatter` for clipboard operations during migration to .NET 10, you can enable limited support through explicit configuration. However, this approach carries significant security risks and requires multiple configuration steps. + +For comprehensive guidance on migrating _away_ from `BinaryFormatter`, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). + +### Security warnings and risks + +`BinaryFormatter` is inherently insecure and has been deprecated across the entire .NET ecosystem for the following critical security reasons: + +**Arbitrary code execution vulnerabilities**: `BinaryFormatter` can execute arbitrary code during deserialization, making applications vulnerable to remote code execution attacks when processing untrusted data from the clipboard. + +**Denial of service attacks**: Malicious clipboard data can cause applications to consume excessive memory or CPU resources, leading to application crashes or system instability. + +**Information disclosure risks**: Attackers can potentially extract sensitive information from application memory through carefully crafted serialized payloads. + +**No security boundaries**: `BinaryFormatter` cannot be made secure through configuration alone - the format itself is fundamentally unsafe for untrusted data. + +`BinaryFormatter` support should only be enabled as a temporary migration bridge while you update your application to use the new type-safe APIs. Plan to remove this dependency as quickly as possible. + +### Complete configuration requirements + +Enabling `BinaryFormatter` support for clipboard operations requires multiple configuration steps. All steps must be completed for the functionality to work. Follow these instructions in order: + +1. Install the compatibility package. + + Add the unsupported `BinaryFormatter` compatibility package to your project: + + ```xml + + + + ``` + +1. Enable unsafe serialization in the project. + + Set the `EnableUnsafeBinaryFormatterSerialization` property to `true` in your project file: + + ```xml + + net10.0 + true + + ``` + +1. Configure the Windows Forms runtime switch. + + Create or update your application's `runtimeconfig.json` file to enable the Windows Forms-specific clipboard switch: -- **Security warnings and risks**: - - BinaryFormatter is inherently insecure and deprecated - - Enables arbitrary code execution through deserialization attacks - - Should only be used as temporary migration bridge - - Requires explicit opt-in through multiple configuration steps - -- **Complete configuration requirements**: - - Reference `System.Runtime.Serialization.Formatters` package - - Set `EnableUnsafeBinaryFormatterSerialization` project property to `true` - - Configure `Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization` runtime switch - - Implement security-focused type resolvers for safe operation - -- **Type resolver implementation patterns**: - - Use explicit allow-lists of permitted types - - Verify assembly names and versions - - Throw exceptions for any unauthorized types - - Never allow implicit type loading or resolution - -- **Gradual migration approach**: - - Enable BinaryFormatter support only during transition period - - Migrate high-risk operations to new APIs first - - Plan complete removal of BinaryFormatter dependency - - Monitor and log all binary deserialization operations + ```json + { + "runtimeOptions": { + "configProperties": { + "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true + } + } + } + ``` + + Without this Windows Forms-specific switch, clipboard operations will not fall back to `BinaryFormatter` even if the general serialization support is enabled. + +### Implement security-focused type resolvers + +Even with `BinaryFormatter` enabled, you must implement type resolvers to control which types can be deserialized. This provides a crucial security boundary by allowing only explicitly permitted types. + +When implementing type resolvers, follow these critical security guidelines to protect your application from malicious clipboard data: + +- **Use explicit allow-lists**: Never allow dynamic type resolution or accept any type not explicitly approved. +- **Validate type names**: Ensure type names exactly match expected values without wildcards or partial matches. +- **Limit to essential types**: Only include types that are absolutely necessary for your application's clipboard functionality. +- **Throw exceptions for unknown types**: Always reject unauthorized types with clear error messages. +- **Review regularly**: Audit and update the allowed types list as part of your security review process. + +The following example demonstrates a secure type resolver implementation that follows all these guidelines. Notice how it uses an explicit dictionary of allowed types, validates exact matches, and throws exceptions for any unauthorized types: + +```csharp +// Create a security-focused type resolver +private static Type SecureTypeResolver(TypeName typeName) +{ + // Explicit allow-list of permitted types - only add types you specifically need + var allowedTypes = new Dictionary + { + ["MyApp.Person"] = typeof(Person), + ["MyApp.Settings"] = typeof(AppSettings), + ["System.String"] = typeof(string), + ["System.Int32"] = typeof(int), + // Add only the specific types your application requires + }; + + // Only allow explicitly listed types - exact string match required + if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType)) + { + return allowedType; + } + + // Reject any type not in the allow-list with clear error message + throw new InvalidOperationException( + $"Type '{typeName.FullName}' is not permitted for clipboard deserialization"); +} + +// Use the resolver with clipboard operations +if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data)) +{ + ProcessLegacyData(data); +} +``` ## Use Copilot to update types From 0bd9fea2a3b34580a9a4cb30099673a14498653e Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 12:20:50 -0700 Subject: [PATCH 17/51] Phase 1 article: Custom types section --- .../migration/clipboard-dataobject-net10.md | 100 +++++++++++++----- 1 file changed, 74 insertions(+), 26 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 0e97a9da6c..00fa1184f0 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -427,33 +427,81 @@ Clipboard.SetData("Icon", smallIcon); ## Working with custom types - +When using `SetDataAsJson()` and `TryGetData()` with custom types, `System.Text.Json` handles serialization automatically. Many types work perfectly without any special configuration - records, simple classes, and structs with public properties serialize seamlessly. + +### Simple types that work without attributes + +Most straightforward custom types require no special configuration: + +```csharp +// Records work perfectly without any attributes +public record PersonInfo(string Name, int Age, string Email); + +// Simple classes serialize all public properties automatically +public class DocumentMetadata +{ + public string Title { get; set; } + public DateTime Created { get; set; } + public string Author { get; set; } +} + +// Structs with public properties work seamlessly +public struct Point3D +{ + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } +} +``` + +### JSON attributes for advanced control + +Use `System.Text.Json` attributes only when you need to customize serialization behavior. For comprehensive guidance on `System.Text.Json` serialization, attributes, and advanced configuration options, see [JSON serialization and deserialization in .NET](/dotnet/standard/serialization/system-text-json/). + +The following snippet demonstrates using JSON attributes to control serialization: -- **JSON serialization best practices**: - - Design simple, serializable types for clipboard use - - Use System.Text.Json compatible attributes - - Avoid complex object hierarchies and circular references - - Consider serialization size and performance impact - -- **Alternative serialization strategies**: - - Manual string serialization for simple data - - Custom byte array handling for binary data - - Format-specific serialization (XML, custom protocols) - - Direct conversion to supported built-in types when possible - -- **Cross-process compatibility considerations**: - - JSON provides better cross-framework compatibility - - Consider version compatibility when designing types - - Test data exchange between different application versions +```csharp +public class ClipboardFriendlyType +{ + // Include a field that normally isn't serialized + [JsonInclude] + private int _privateData; + + // Public properties are always serialized + public string Name { get; set; } + + // Exclude sensitive or non-essential data + [JsonIgnore] + public string InternalId { get; set; } + + // Handle property name differences for compatibility + [JsonPropertyName("display_text")] + public string DisplayText { get; set; } + + // Control null value handling + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string OptionalField { get; set; } +} +``` + +### Usage with clipboard operations + +```csharp +var data = new ClipboardFriendlyType +{ + Name = "Sample", + DisplayText = "Sample Display Text", + InternalId = "internal-123" // This won't be serialized due to [JsonIgnore] +}; + +Clipboard.SetDataAsJson("MyAppData", data); + +if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved)) +{ + Console.WriteLine($"Retrieved: {retrieved.Name}"); + // retrieved.InternalId will be null due to [JsonIgnore] +} +``` ## Enable BinaryFormatter support (not recommended) From 3e1915732a3f818a7e9e6ec915b8574f029bbaaa Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 12:33:36 -0700 Subject: [PATCH 18/51] Phase 1 article: Make intro better --- .../winforms/migration/clipboard-dataobject-net10.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 00fa1184f0..3e5c4f1cb5 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -18,9 +18,13 @@ This article explains how to upgrade Windows Forms clipboard and drag-and-drop o `BinaryFormatter` was removed from the .NET runtime in .NET 9 due to security vulnerabilities, breaking existing clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and provide type-safe methods to restore this functionality while maintaining security and improving error handling and cross-process compatibility. +One signifigant change is that `SetData()` no longer works with custom types, and it silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and should no longer be used, even for built-in types. The modern replacements are `TryGetData()` and `SetDataAsJson()`, which provide type-safe operations and use JSON serialization to round-trip custom objects. + +The following sections provide detailed migration guidance, explain which types work without modification, and show how to handle both new development and legacy data scenarios. + ## Prerequisites -To understand the context and implications of these changes you shuold understand the folowing: +To understand the context and implications of these changes you should understand the following: - Familiarity with how `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. - The security vulnerabilities that led to `BinaryFormatter` removal. @@ -31,10 +35,6 @@ For more information, see: - [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide). - [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). -## Summary of the changes - - - ## Breaking changes from BinaryFormatter removal The removal of `BinaryFormatter` from .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality. From 1b392bac11cd8af9243fab97817022349e714c96 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 13:29:15 -0700 Subject: [PATCH 19/51] Phase 1: article: Copilot section --- .../includes/copilot-disclaimer.md | 9 ++ .../migration/clipboard-dataobject-net10.md | 113 ++++++++++++++++-- 2 files changed, 109 insertions(+), 13 deletions(-) create mode 100644 dotnet-desktop-guide/includes/copilot-disclaimer.md diff --git a/dotnet-desktop-guide/includes/copilot-disclaimer.md b/dotnet-desktop-guide/includes/copilot-disclaimer.md new file mode 100644 index 0000000000..ac9163c17f --- /dev/null +++ b/dotnet-desktop-guide/includes/copilot-disclaimer.md @@ -0,0 +1,9 @@ +--- +author: adegeo +ms.author: adegeo +ms.date: 09/26/2025 +ms.update-cycle: 1825-days +ms.topic: include +--- + +*Copilot is powered by AI, so surprises and mistakes are possible. For more information, see [Copilot general use FAQs](https://aka.ms/copilot-general-use-faqs).* diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 3e5c4f1cb5..e48b672b26 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -6,7 +6,9 @@ ms.author: [your Microsoft alias or a team alias] ms.service: dotnet-desktop ms.topic: concept-article ms.date: 09/25/2025 -ai-usage: ai-generated +ms.custom: +- copilot-scenario-highlight +ai-usage: ai-assisted #customer intent: As a Windows Forms developer, I want to understand the clipboard and DataObject changes in .NET 10 so that I can upgrade my applications and use the new type-safe APIs. @@ -613,20 +615,105 @@ if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data } ``` -## Use Copilot to update types +## Use AI to migrate clipboard code - +Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like Copilot can significantly accelerate this migration process by identifying legacy patterns, generating modern replacements, and creating comprehensive test scenarios. Rather than manually searching through your codebase and converting each clipboard operation individually, you can leverage Copilot to handle the repetitive aspects while you focus on validating the results and handling edge cases. -[Explain and give some example of using copilot to data objects.] +The following sections demonstrate specific prompt strategies for different aspects of clipboard migration, from identifying problematic code patterns to creating robust JSON-serializable types and comprehensive test suites. + +### Use AI to identify legacy clipboard patterns + +Use Copilot to scan your codebase and locate clipboard operations that need migration. This helps you understand the scope of changes required before starting the actual migration work. + +```copilot-prompt +Find all clipboard operations in my codebase that use GetData(), SetData() with custom objects, DataObject.GetData(), or IDataObject.GetData(). Show me the file paths and line numbers where these patterns occur. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to convert GetData() to TryGetData\() + +Use Copilot to convert obsolete `GetData()` calls to the new type-safe `TryGetData()` pattern. This conversion includes proper error handling and eliminates unsafe casting. + +```copilot-prompt +Convert this GetData() clipboard code to use the new TryGetData() method with proper error handling: + +[paste your existing GetData() code here] + +Make sure to eliminate casting and add appropriate error handling for when the data isn't available. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to migrate SetData() to SetDataAsJson\() + +Use Copilot to convert custom object storage from the obsolete `SetData()` method to the new `SetDataAsJson()` approach. This ensures your custom objects are properly serialized to the clipboard. + +```copilot-prompt +Take this SetData() clipboard code that stores custom objects: + +[paste your existing SetData() code here] + +Convert it to use SetDataAsJson() and make the custom types JSON-serializable. Add any necessary System.Text.Json attributes if the types have complex properties. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to create JSON-serializable data models + +Use Copilot to design custom types that work seamlessly with `SetDataAsJson()` and `TryGetData()`. This includes adding appropriate attributes for properties that need special handling. + +```copilot-prompt +Create a JSON-serializable version of this class for clipboard operations: + +[paste your existing class definition here] + +Make it work with System.Text.Json, add JsonIgnore for sensitive properties, JsonInclude for private fields that should serialize, and JsonPropertyName for any properties that need different names in JSON. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to generate type-safe wrapper methods + +Use Copilot to create wrapper methods that encapsulate the new clipboard APIs and provide clean interfaces for your application's specific data types. + +```copilot-prompt +Create a type-safe clipboard wrapper class that provides methods for storing and retrieving these custom types: + +[list your custom types here] + +Use SetDataAsJson() and TryGetData() internally, include proper error handling, and add methods like SavePersonToClipboard() and TryGetPersonFromClipboard(). +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to create comprehensive tests + +Use Copilot to generate test suites that verify your clipboard migration works correctly, including round-trip serialization tests and error handling scenarios. + +```copilot-prompt +Generate comprehensive unit tests for this clipboard code: + +[paste your migrated clipboard code here] + +Include tests for successful round-trip serialization, handling of null values, error cases when data isn't available, and verification that the migrated code produces the same results as the original for valid scenarios. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] + +### Use AI to validate migration results + +Use Copilot to review your migrated code and identify potential issues or areas where the migration might not be complete. + +```copilot-prompt +Review this migrated clipboard code for potential issues: + +[paste your migrated code here] + +Check for: missing error handling, types that might not serialize properly to JSON, performance concerns with large objects, security issues, and any remaining uses of obsolete methods. +``` + +[!INCLUDE [copilot-disclaimer](../../includes/copilot-disclaimer.md)] ## Related content From d7b5a93c723031171fba4f12ca6bf4f7327f60b5 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 14:47:07 -0700 Subject: [PATCH 20/51] Phase 1 article: Edit pass 1 --- .../migration/clipboard-dataobject-net10.md | 256 +++++++++--------- 1 file changed, 126 insertions(+), 130 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index e48b672b26..184b1ef719 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -16,36 +16,36 @@ ai-usage: ai-assisted # Windows Forms clipboard and DataObject changes in .NET 10 -This article explains how to upgrade Windows Forms clipboard and drag-and-drop operations to .NET 10's new type-safe APIs. You'll learn to use the new `TryGetData()` and `SetDataAsJson()` methods, understand which built-in types work without modification, and discover strategies for handling custom types and legacy data affected by `BinaryFormatter` removal. +This article shows you how to upgrade Windows Forms clipboard and drag-and-drop operations to .NET 10's new type-safe APIs. You'll use the new `TryGetData()` and `SetDataAsJson()` methods, see which built-in types work without changes, and learn strategies for handling custom types and legacy data after the removal of `BinaryFormatter`. -`BinaryFormatter` was removed from the .NET runtime in .NET 9 due to security vulnerabilities, breaking existing clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and provide type-safe methods to restore this functionality while maintaining security and improving error handling and cross-process compatibility. +`BinaryFormatter` was removed from the runtime in .NET 9 because of security vulnerabilities. This change broke clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and type-safe methods to restore this functionality, improve security, and provide better error handling and cross-process compatibility. -One signifigant change is that `SetData()` no longer works with custom types, and it silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and should no longer be used, even for built-in types. The modern replacements are `TryGetData()` and `SetDataAsJson()`, which provide type-safe operations and use JSON serialization to round-trip custom objects. +One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and should not be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. -The following sections provide detailed migration guidance, explain which types work without modification, and show how to handle both new development and legacy data scenarios. +The following sections provide detailed migration guidance, explain which types work without changes, and show how to handle both new development and legacy data scenarios. ## Prerequisites -To understand the context and implications of these changes you should understand the following: +Before you continue, make sure you understand the following concepts: -- Familiarity with how `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. -- The security vulnerabilities that led to `BinaryFormatter` removal. -- Knowledge of `System.Text.Json` serialization patterns and limitations. +- How `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. +- The security vulnerabilities that led to the removal of `BinaryFormatter`. +- `System.Text.Json` serialization patterns and limitations. -For more information, see: +For more information, see the following articles: - [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide). - [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ## Breaking changes from BinaryFormatter removal -The removal of `BinaryFormatter` from .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality. +Removing `BinaryFormatter` in .NET 9 fundamentally changes how Windows Forms handles clipboard and drag-and-drop operations with custom types. These changes affect existing code patterns and require careful migration to maintain functionality. ### Custom types no longer serialize automatically -Previously, you could place any serializable custom object on the clipboard using `SetData()`, and `BinaryFormatter` would handle serialization automatically. This pattern no longer works stating with .NET 9, but importantly, it fails silently without throwing exceptions. +In .NET 8 and earlier, you could place any serializable custom object on the clipboard by calling `SetData()`. `BinaryFormatter` handled serialization automatically. Starting with .NET 9, this pattern no longer works. `SetData()` silently fails for custom types and does not store data on the clipboard. -The following code doesn't work: +The following code no longer works: ```csharp [Serializable] @@ -59,28 +59,28 @@ public class Person Person person = new Person { Name = "John", Age = 30 }; Clipboard.SetData("MyApp.Person", person); // No data is stored -// Later attempts to retrieve the data returns null +// Later attempts to retrieve the data return null object data = Clipboard.GetData("MyApp.Person"); ``` -#### Behavior you encounter +#### What you might see -- `SetData()` completes without throwing an exception but doesn't actually store the data. +- `SetData()` completes without throwing an exception but does not store the data. - The clipboard operation appears to succeed from your application's perspective. - Later attempts to retrieve the data with `GetData()` return `null`. -#### Migration strategy +#### Migration guidance -Use the new `SetDataAsJson()` method or serialize manually to `string` or `byte[]`. See [Working with custom types](#working-with-custom-types) section for detailed guidance. +Use the new `SetDataAsJson()` method or manually serialize to `string` or `byte[]`. For details, see the [Working with custom types](#working-with-custom-types) section. -### GetData() is obsolete - use TryGetData\() instead +### GetData() is obsolete—use TryGetData\() instead -The legacy `GetData()` method is obsolete in .NET 10. Even for scenarios where it might still return data, migrate to the new type-safe `TryGetData()` methods that provide better error handling and type safety. +The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes returns data, migrate to the new type-safe `TryGetData()` methods for better error handling and type safety. -**Obsolete code that should be avoided:** +**Obsolete code to avoid:** ```csharp -// DON'T USE - GetData() is obsolete in .NET 10 +// Don't use - GetData() is obsolete in .NET 10 object data = Clipboard.GetData("MyApp.Person"); // Obsolete method // Always returns null on a custom object type @@ -94,34 +94,34 @@ if (data != null) **Modern approach using TryGetData\():** ```csharp -// USE THIS - Type-safe approach with TryGetData() +// Use this - type-safe approach with TryGetData() if (Clipboard.TryGetData("MyApp.Person", out Person person)) { ProcessPerson(person); // person is guaranteed to be the correct type } else { - // Handle the case where data isn't available or is wrong type + // Handle the case where data isn't available or is the wrong type ShowError("Unable to retrieve person data from clipboard"); } ``` -#### Benefits of TryGetData\(): +#### Benefits of TryGetData\() -- **Type safety**: No need for casting - the method returns the exact type you request. -- **Clear error handling**: Returns boolean success indicator instead of null/exception patterns. -- **Future-proof**: Designed to work with new serialization methods and legacy data support. +- Type safety. No need for casting—the method returns the exact type you request. +- Clear error handling. Returns a Boolean success indicator instead of using null or exception patterns. +- Future-proof. Designed to work with new serialization methods and legacy data support. #### How to identify affected code Look for: -- Any `GetData()` calls - the entire method is obsolete regardless of data type. +- Any `GetData()` calls. The entire method is obsolete regardless of data type. - `DataObject.GetData()` and `IDataObject.GetData()` usage in drag-and-drop operations. -#### Migration strategy +#### Migration guidance -Replace all `GetData()` usage with type-safe `TryGetData()` methods. See [New type-safe APIs](#new-type-safe-apis) section for comprehensive examples of all overloads. +Replace all `GetData()` usage with type-safe `TryGetData()` methods. For comprehensive examples of all overloads, see the [New type-safe APIs](#new-type-safe-apis) section. ## New type-safe APIs @@ -129,36 +129,36 @@ Replace all `GetData()` usage with type-safe `TryGetData()` methods. See [New ### TryGetData\() methods -The `TryGetData()` family replaces the obsolete `GetData()` method with type-safe retrieval and clear success/failure indication. +The `TryGetData()` family replaces the obsolete `GetData()` method with type-safe retrieval and clear success or failure indication. #### Basic type-safe retrieval ```csharp -// Simple retrieval with standard formats +// Retrieve text data using a standard format if (Clipboard.TryGetData(DataFormats.Text, out string textData)) { ProcessTextData(textData); } -// Works with any supported type using custom formats +// Retrieve an integer using a custom format if (Clipboard.TryGetData("NumberData", out int numberData)) { ProcessNumber(numberData); } -// Using standard formats for common data types +// Retrieve Unicode text using a standard format if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText)) { ProcessUnicodeText(unicodeText); } -// Control OLE data conversion +// Retrieve raw text data with OLE conversion control if (Clipboard.TryGetData(DataFormats.Text, autoConvert: false, out string rawText)) { ProcessRawText(rawText); } -// Working with file drops using standard format +// Retrieve file drops using a standard format if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) { ProcessFiles(files); @@ -168,37 +168,37 @@ if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) #### Custom JSON types ```csharp -// Retrieve custom types stored with SetDataAsJson() +// Retrieve a custom type stored with SetDataAsJson() if (Clipboard.TryGetData("Person", out Person person)) { ProcessPerson(person); } -// Handle application-specific data formats +// Retrieve application-specific data formats if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings)) { ApplySettings(settings); } -// Work with complex custom objects +// Retrieve complex custom objects if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) { LoadDocument(doc); } ``` -#### Type resolver for legacy binary data (requires BinaryFormatter - not recommended) +#### Use a type resolver for legacy binary data (requires BinaryFormatter; not recommended) > [!WARNING] -> Type resolvers only work when BinaryFormatter support is enabled, which is **not recommended** due to security risks. See [Enabling BinaryFormatter support](#enabling-binaryformatter-support-not-recommended) for more information. +> Type resolvers only work when BinaryFormatter support is enabled, which is not recommended due to security risks. For more information, see [Enable BinaryFormatter support (not recommended)](#enable-binaryformatter-support-not-recommended). -Type resolvers allow you to handle legacy binary data by mapping type names to actual types during deserialization: +Type resolvers let you handle legacy binary data by mapping type names to actual types during deserialization. ```csharp // Create a type resolver that maps old type names to current types Func resolver = typeName => { - // Only allow specific known safe types + // Only allow specific, known, safe types return typeName.FullName switch { "MyApp.Person" => typeof(Person), @@ -209,13 +209,13 @@ Func resolver = typeName => }; }; -// Use resolver with legacy binary data +// Use the resolver with legacy binary data if (Clipboard.TryGetData("LegacyFormat", resolver, out Person person)) { ProcessPerson(person); } -// Combined resolver with conversion control +// Use a resolver with conversion control if (Clipboard.TryGetData("OldCustomData", resolver, autoConvert: true, out MyType data)) { ProcessCustomData(data); @@ -224,11 +224,11 @@ if (Clipboard.TryGetData("OldCustomData", resolver, autoConvert: true, out MyTyp **Important security considerations for type resolvers:** -- Always use an explicit allow-list of permitted types -- Never allow dynamic type loading or assembly resolution -- Validate type names before mapping to actual types -- Throw exceptions for any unauthorized or unknown types -- Consider this a temporary bridge during migration only +- Always use an explicit allow-list of permitted types. +- Never allow dynamic type loading or assembly resolution. +- Validate type names before mapping to actual types. +- Throw exceptions for any unauthorized or unknown types. +- Use this approach only as a temporary bridge during migration. ### SetDataAsJson\() methods @@ -239,41 +239,41 @@ These methods provide automatic JSON serialization using `System.Text.Json` with ```csharp var person = new Person { Name = "Alice", Age = 25 }; -// Format automatically inferred from type name -Clipboard.SetDataAsJson(person); // Uses "Person" as format +// The format is automatically inferred from the type name +Clipboard.SetDataAsJson(person) // Uses "Person" as the format -// Later retrieval +// Retrieve the data later if (Clipboard.TryGetData("Person", out Person retrievedPerson)) { Console.WriteLine($"Retrieved: {retrievedPerson.Name}"); } ``` -#### Custom format specification +#### Specify a custom format ```csharp var settings = new AppSettings { Theme = "Dark", AutoSave = true }; -// Custom format for better organization -Clipboard.SetDataAsJson("MyApp.Settings", settings); +// Use a custom format for better organization +Clipboard.SetDataAsJson("MyApp.Settings", settings) -// Multiple formats for the same data -Clipboard.SetDataAsJson("Config.V1", settings); -Clipboard.SetDataAsJson("AppConfig", settings); +// Store the same data in multiple formats +Clipboard.SetDataAsJson("Config.V1", settings) +Clipboard.SetDataAsJson("AppConfig", settings) ``` ### ITypedDataObject interface -This interface enables type-safe drag-and-drop operations by extending `IDataObject` with typed methods. +The `ITypedDataObject` interface enables type-safe drag-and-drop operations by extending `IDataObject` with typed methods. -#### Implementation in custom DataObject +#### Implement ITypedDataObject in a custom DataObject ```csharp public class TypedDataObject : DataObject, ITypedDataObject { public bool TryGetData(string format, out T data) { - // Implementation uses new type-safe logic + // Use new type-safe logic return base.TryGetData(format, out data); } @@ -283,27 +283,28 @@ public class TypedDataObject : DataObject, ITypedDataObject return base.TryGetData(format, resolver, out data); } } +``` -#### Usage in drag-and-drop scenarios +#### Use ITypedDataObject in drag-and-drop scenarios ```csharp private void OnDragDrop(object sender, DragEventArgs e) { if (e.Data is ITypedDataObject typedData) { - // Type-safe retrieval from drag data using standard formats + // Retrieve files from drag data using a standard format if (typedData.TryGetData(DataFormats.FileDrop, out string[] files)) { ProcessDroppedFiles(files); } - - // Using standard text formats + + // Retrieve text using a standard format if (typedData.TryGetData(DataFormats.Text, out string text)) { ProcessDroppedText(text); } - - // Custom formats for application-specific data + + // Retrieve custom items using an application-specific format if (typedData.TryGetData("CustomItem", out MyItem item)) { ProcessCustomItem(item); @@ -314,36 +315,36 @@ private void OnDragDrop(object sender, DragEventArgs e) ## Types that don't require JSON serialization -Many built-in .NET types continue to work with clipboard operations without requiring JSON serialization or `BinaryFormatter` support. These types are automatically serialized into the .NET Remoting Binary Format (NRBF), which provides efficient storage while maintaining type safety. +Many built-in .NET types work with clipboard operations without requiring JSON serialization or `BinaryFormatter` support. These types are automatically serialized into the .NET Remoting Binary Format (NRBF), which provides efficient storage and maintains type safety. -These types use the .NET Remoting Binary Format (NRBF) for serialization, the same efficient binary format used by the legacy `BinaryFormatter`. Key characteristics of NRBF serialization: +These types use the NRBF, the same efficient binary format used by the legacy `BinaryFormatter`. Key characteristics of NRBF serialization include: - **Compact binary representation** for efficient storage and transfer. -- **Built-in type information** preserves exact .NET types during round-trip operations. -- **Cross-process compatibility** works between different .NET applications. -- **No custom serialization required** - types serialize automatically. +- **Built-in type information** that preserves exact .NET types during round-trip operations. +- **Cross-process compatibility** that works between different .NET applications. +- **No custom serialization required**. Types serialize automatically. -For detailed technical information about NRBF, see the [.NET Remoting Binary Format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). +For technical details, see the [.NET Remoting Binary Format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). -Classes that support working with NRBF-encoded data are implemented in the namespace. +Classes that support NRBF-encoded data are implemented in the namespace. ### Type safety guarantees Windows Forms provides several safety mechanisms for these built-in types: -- **Exact type matching**: `TryGetData()` ensures only the requested type is returned. -- **Automatic validation**: WinForms validates type compatibility during deserialization. -- **No arbitrary code execution**: Unlike custom types with BinaryFormatter, these types can't execute malicious code. -- **Content validation required**: Developers must still validate data content and ranges for their application logic. -- **No size constraints**: Large arrays or bitmaps are not automatically limited (monitor memory usage). +- **Exact type matching**. `TryGetData()` returns only the requested type. +- **Automatic validation**. Windows Forms validates type compatibility during deserialization. +- **No arbitrary code execution**. Unlike custom types with BinaryFormatter, these types can't execute malicious code. +- **Content validation required**. You must still validate data content and ranges for your application logic. +- **No size constraints**. Large arrays or bitmaps are not automatically limited. Monitor memory usage. ### Supported primitive types -The following primitive types work seamlessly with clipboard and `DataObject` operations without requiring any custom serialization or configuration. These built-in .NET types are automatically handled by the clipboard system: +The following primitive types work seamlessly with clipboard and `DataObject` operations. You do not need custom serialization or configuration. The clipboard system automatically handles these built-in .NET types: -- `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, `long` -- `sbyte`, `ushort`, `uint`, `ulong`, `float`, `string` -- `TimeSpan` and `DateTime` +- `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, and `long`. +- `sbyte`, `ushort`, `uint`, `ulong`, `float`, and `string`. +- `TimeSpan` and `DateTime`. The following examples show how these primitive types work directly with `SetData()` and `TryGetData()` methods: @@ -371,13 +372,13 @@ if (Clipboard.TryGetData("MyInt", out int value)) ### Collections of primitive types -Arrays and generic lists of supported primitive types work without additional configuration, but there are some important limitations to be aware of: +Arrays and generic lists of supported primitive types work without additional configuration. However, keep these limitations in mind: -- All array and list elements must be of supported primitive types. -- Avoid `string[]` and `List` due to null value handling complexity in NRBF format. -- Use individual string storage or JSON serialization for string collections instead. +- All array and list elements must be supported primitive types. +- Avoid `string[]` and `List` because NRBF format has complexity handling null values in string collections. +- Store strings individually or use JSON serialization for string collections. -The following exmaples show how arrays and lists can be set on the clipboard: +The following examples show how arrays and lists can be set on the clipboard: ```csharp // Arrays of primitive types @@ -400,11 +401,11 @@ if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers)) ### System.Drawing types -Common graphics types from the `System.Drawing` namespace work seamlessly with clipboard and `DataObject` operations. These types are particularly useful for applications that work with visual elements and need to transfer drawing-related data between components or applications. However, when using `Bitmap` objects, be mindful of memory usage for large images. The following types are supported: +Common graphics types from the `System.Drawing` namespace work seamlessly with clipboard and `DataObject` operations. These types are useful for applications that work with visual elements and need to transfer drawing-related data between components or applications. Be aware that serializing a `Bitmap` can consume a large amount of memory, especially for large images. The following types are supported: -- `Point`, `PointF`, `Rectangle`, `RectangleF` -- `Size`, `SizeF`, `Color` -- `Bitmap` (consider memory usage for large images) +- `Point`, `PointF`, `Rectangle`, `RectangleF`. +- `Size`, `SizeF`, `Color`. +- `Bitmap` (can consume significant memory when serialized). The following examples show how these graphics types can be used with clipboard operations: @@ -427,19 +428,19 @@ Bitmap smallIcon = new Bitmap(16, 16); Clipboard.SetData("Icon", smallIcon); ``` -## Working with custom types +## Work with custom types -When using `SetDataAsJson()` and `TryGetData()` with custom types, `System.Text.Json` handles serialization automatically. Many types work perfectly without any special configuration - records, simple classes, and structs with public properties serialize seamlessly. +When you use `SetDataAsJson()` and `TryGetData()` with custom types, `System.Text.Json` handles serialization automatically. Many types work without any special configuration—records, simple classes, and structs with public properties serialize seamlessly. ### Simple types that work without attributes -Most straightforward custom types require no special configuration: +Most straightforward custom types don't require special configuration: ```csharp -// Records work perfectly without any attributes +// Records work without any attributes. public record PersonInfo(string Name, int Age, string Email); -// Simple classes serialize all public properties automatically +// Simple classes serialize all public properties automatically. public class DocumentMetadata { public string Title { get; set; } @@ -447,7 +448,7 @@ public class DocumentMetadata public string Author { get; set; } } -// Structs with public properties work seamlessly +// Structs with public properties work seamlessly. public struct Point3D { public double X { get; set; } @@ -456,11 +457,11 @@ public struct Point3D } ``` -### JSON attributes for advanced control +### Use JSON attributes for advanced control Use `System.Text.Json` attributes only when you need to customize serialization behavior. For comprehensive guidance on `System.Text.Json` serialization, attributes, and advanced configuration options, see [JSON serialization and deserialization in .NET](/dotnet/standard/serialization/system-text-json/). -The following snippet demonstrates using JSON attributes to control serialization: +The following example shows how you can use JSON attributes to control serialization: ```csharp public class ClipboardFriendlyType @@ -486,14 +487,14 @@ public class ClipboardFriendlyType } ``` -### Usage with clipboard operations +### Example: Clipboard operations with custom types ```csharp var data = new ClipboardFriendlyType { Name = "Sample", DisplayText = "Sample Display Text", - InternalId = "internal-123" // This won't be serialized due to [JsonIgnore] + InternalId = "internal-123" // This property isn't serialized due to [JsonIgnore] }; Clipboard.SetDataAsJson("MyAppData", data); @@ -501,36 +502,33 @@ Clipboard.SetDataAsJson("MyAppData", data); if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved)) { Console.WriteLine($"Retrieved: {retrieved.Name}"); - // retrieved.InternalId will be null due to [JsonIgnore] + // retrieved.InternalId is null because of [JsonIgnore] } ``` ## Enable BinaryFormatter support (not recommended) > [!CAUTION] -> `BinaryFormatter` support is **not recommended** and should only be used as a temporary migration bridge. This section is provided for legacy applications that cannot immediately migrate to the new type-safe APIs. +> `BinaryFormatter` support is **not recommended**. Use it only as a temporary migration bridge for legacy applications that cannot immediately migrate to the new type-safe APIs. -If your application absolutely must continue using `BinaryFormatter` for clipboard operations during migration to .NET 10, you can enable limited support through explicit configuration. However, this approach carries significant security risks and requires multiple configuration steps. +If you must continue using `BinaryFormatter` for clipboard operations in .NET 10, enable limited support through explicit configuration. This approach carries significant security risks and requires several steps. -For comprehensive guidance on migrating _away_ from `BinaryFormatter`, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). +For complete migration guidance, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ### Security warnings and risks -`BinaryFormatter` is inherently insecure and has been deprecated across the entire .NET ecosystem for the following critical security reasons: - -**Arbitrary code execution vulnerabilities**: `BinaryFormatter` can execute arbitrary code during deserialization, making applications vulnerable to remote code execution attacks when processing untrusted data from the clipboard. +`BinaryFormatter` is inherently insecure and deprecated because: -**Denial of service attacks**: Malicious clipboard data can cause applications to consume excessive memory or CPU resources, leading to application crashes or system instability. +- **Arbitrary code execution vulnerabilities.** It can execute arbitrary code during deserialization, exposing your application to remote attacks. +- **Denial of service attacks.** Malicious clipboard data can consume excessive memory or CPU, causing crashes or instability. +- **Information disclosure risks.** Attackers may extract sensitive data from memory. +- **No security boundaries.** The format is fundamentally unsafe; configuration cannot secure it. -**Information disclosure risks**: Attackers can potentially extract sensitive information from application memory through carefully crafted serialized payloads. - -**No security boundaries**: `BinaryFormatter` cannot be made secure through configuration alone - the format itself is fundamentally unsafe for untrusted data. - -`BinaryFormatter` support should only be enabled as a temporary migration bridge while you update your application to use the new type-safe APIs. Plan to remove this dependency as quickly as possible. +Enable this support only as a temporary bridge while updating your application to use the new type-safe APIs. ### Complete configuration requirements -Enabling `BinaryFormatter` support for clipboard operations requires multiple configuration steps. All steps must be completed for the functionality to work. Follow these instructions in order: +Follow these steps to enable `BinaryFormatter` support for clipboard operations: 1. Install the compatibility package. @@ -542,7 +540,7 @@ Enabling `BinaryFormatter` support for clipboard operations requires multiple co ``` -1. Enable unsafe serialization in the project. +1. Enable unsafe serialization in your project file. Set the `EnableUnsafeBinaryFormatterSerialization` property to `true` in your project file: @@ -567,27 +565,25 @@ Enabling `BinaryFormatter` support for clipboard operations requires multiple co } ``` - Without this Windows Forms-specific switch, clipboard operations will not fall back to `BinaryFormatter` even if the general serialization support is enabled. + Without this switch, clipboard operations will not fall back to `BinaryFormatter` even if general serialization support is enabled. ### Implement security-focused type resolvers -Even with `BinaryFormatter` enabled, you must implement type resolvers to control which types can be deserialized. This provides a crucial security boundary by allowing only explicitly permitted types. - -When implementing type resolvers, follow these critical security guidelines to protect your application from malicious clipboard data: +Even with `BinaryFormatter` enabled, you must implement type resolvers to restrict deserialization to explicitly approved types. Follow these guidelines: -- **Use explicit allow-lists**: Never allow dynamic type resolution or accept any type not explicitly approved. -- **Validate type names**: Ensure type names exactly match expected values without wildcards or partial matches. -- **Limit to essential types**: Only include types that are absolutely necessary for your application's clipboard functionality. -- **Throw exceptions for unknown types**: Always reject unauthorized types with clear error messages. -- **Review regularly**: Audit and update the allowed types list as part of your security review process. +- **Use explicit allow-lists.** Reject any type not explicitly approved. +- **Validate type names.** Ensure type names exactly match expected values. +- **Limit to essential types.** Include only types required for your clipboard functionality. +- **Throw exceptions for unknown types.** Clearly reject unauthorized types. +- **Review regularly.** Audit and update the allowed list as needed. -The following example demonstrates a secure type resolver implementation that follows all these guidelines. Notice how it uses an explicit dictionary of allowed types, validates exact matches, and throws exceptions for any unauthorized types: +The following example shows a secure type resolver implementation: ```csharp // Create a security-focused type resolver private static Type SecureTypeResolver(TypeName typeName) { - // Explicit allow-list of permitted types - only add types you specifically need + // Explicit allow-list of permitted types—add only what you need var allowedTypes = new Dictionary { ["MyApp.Person"] = typeof(Person), @@ -617,7 +613,7 @@ if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data ## Use AI to migrate clipboard code -Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like Copilot can significantly accelerate this migration process by identifying legacy patterns, generating modern replacements, and creating comprehensive test scenarios. Rather than manually searching through your codebase and converting each clipboard operation individually, you can leverage Copilot to handle the repetitive aspects while you focus on validating the results and handling edge cases. +Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like Copilot can accelerate this migration process by identifying legacy patterns, generating modern replacements, and creating comprehensive test scenarios. Instead of manually searching through your codebase and converting each clipboard operation individually, leverage Copilot to handle repetitive tasks while you focus on validating results and handling edge cases. The following sections demonstrate specific prompt strategies for different aspects of clipboard migration, from identifying problematic code patterns to creating robust JSON-serializable types and comprehensive test suites. From 599523b7c9be35cd5c0b02ff136ce7c411956c8d Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 15:00:23 -0700 Subject: [PATCH 21/51] Phase 1 article: Edit pass 2 (claude) --- .../migration/clipboard-dataobject-net10.md | 88 ++++++++++--------- 1 file changed, 46 insertions(+), 42 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 184b1ef719..52b161e7bd 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -1,13 +1,13 @@ --- title: "Windows Forms clipboard and DataObject changes in .NET 10" description: "Learn about the major clipboard and drag-and-drop changes in .NET 10, including new type-safe APIs, JSON serialization, and migration from BinaryFormatter." -author: [your GitHub alias] -ms.author: [your Microsoft alias or a team alias] +author: adegeo +ms.author: adegeo ms.service: dotnet-desktop ms.topic: concept-article -ms.date: 09/25/2025 +ms.date: 09/26/2025 ms.custom: -- copilot-scenario-highlight + - copilot-scenario-highlight ai-usage: ai-assisted #customer intent: As a Windows Forms developer, I want to understand the clipboard and DataObject changes in .NET 10 so that I can upgrade my applications and use the new type-safe APIs. @@ -16,23 +16,23 @@ ai-usage: ai-assisted # Windows Forms clipboard and DataObject changes in .NET 10 -This article shows you how to upgrade Windows Forms clipboard and drag-and-drop operations to .NET 10's new type-safe APIs. You'll use the new `TryGetData()` and `SetDataAsJson()` methods, see which built-in types work without changes, and learn strategies for handling custom types and legacy data after the removal of `BinaryFormatter`. +This article shows you how to upgrade your Windows Forms clipboard and drag-and-drop operations to the new type-safe APIs in .NET 10. You'll learn how to use the new `TryGetData()` and `SetDataAsJson()` methods, understand which built-in types work without changes, and discover strategies for handling custom types and legacy data after the removal of `BinaryFormatter`. `BinaryFormatter` was removed from the runtime in .NET 9 because of security vulnerabilities. This change broke clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and type-safe methods to restore this functionality, improve security, and provide better error handling and cross-process compatibility. -One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and should not be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. +One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and shouldn't be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. The following sections provide detailed migration guidance, explain which types work without changes, and show how to handle both new development and legacy data scenarios. ## Prerequisites -Before you continue, make sure you understand the following concepts: +Before you continue, review these concepts: -- How `BinaryFormatter` was used in clipboard and drag-and-drop scenarios before .NET 9. +- How applications used `BinaryFormatter` in clipboard and drag-and-drop scenarios before .NET 9. - The security vulnerabilities that led to the removal of `BinaryFormatter`. -- `System.Text.Json` serialization patterns and limitations. +- How to work with `System.Text.Json` serialization patterns and their limitations. -For more information, see the following articles: +For more information, see these articles: - [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide). - [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). @@ -43,7 +43,7 @@ Removing `BinaryFormatter` in .NET 9 fundamentally changes how Windows Forms han ### Custom types no longer serialize automatically -In .NET 8 and earlier, you could place any serializable custom object on the clipboard by calling `SetData()`. `BinaryFormatter` handled serialization automatically. Starting with .NET 9, this pattern no longer works. `SetData()` silently fails for custom types and does not store data on the clipboard. +In .NET 8 and earlier, you could place any serializable custom object on the clipboard by calling `SetData()`. The `BinaryFormatter` handled serialization automatically. Starting with .NET 9, this pattern no longer works. The `SetData()` method silently fails for custom types and doesn't store data on the clipboard. The following code no longer works: @@ -65,17 +65,17 @@ object data = Clipboard.GetData("MyApp.Person"); #### What you might see -- `SetData()` completes without throwing an exception but does not store the data. +- The `SetData()` method completes without throwing an exception but doesn't store the data. - The clipboard operation appears to succeed from your application's perspective. - Later attempts to retrieve the data with `GetData()` return `null`. #### Migration guidance -Use the new `SetDataAsJson()` method or manually serialize to `string` or `byte[]`. For details, see the [Working with custom types](#working-with-custom-types) section. +Use the new `SetDataAsJson()` method or manually serialize to a `string` or `byte[]`. For details, see the [Working with custom types](#working-with-custom-types) section. -### GetData() is obsolete—use TryGetData\() instead +### GetData() is obsolete - use TryGetData\() instead -The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes returns data, migrate to the new type-safe `TryGetData()` methods for better error handling and type safety. +The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes returns data, you should migrate to the new type-safe `TryGetData()` methods for better error handling and type safety. **Obsolete code to avoid:** @@ -108,15 +108,15 @@ else #### Benefits of TryGetData\() -- Type safety. No need for casting—the method returns the exact type you request. -- Clear error handling. Returns a Boolean success indicator instead of using null or exception patterns. -- Future-proof. Designed to work with new serialization methods and legacy data support. +- Type safety: No need for casting—the method returns the exact type you request. +- Clear error handling: Returns a Boolean success indicator instead of using null or exception patterns. +- Future-proof: Designed to work with new serialization methods and legacy data support. #### How to identify affected code Look for: -- Any `GetData()` calls. The entire method is obsolete regardless of data type. +- Any `GetData()` calls, as the entire method is obsolete regardless of data type. - `DataObject.GetData()` and `IDataObject.GetData()` usage in drag-and-drop operations. #### Migration guidance @@ -125,11 +125,15 @@ Replace all `GetData()` usage with type-safe `TryGetData()` methods. For comp ## New type-safe APIs -.NET 10 introduces three new API families that provide type safety, better error handling, and JSON serialization support for clipboard and drag-and-drop operations. +.NET 10 introduces three new API families that provide type safety, better error handling, and JSON serialization support for clipboard and drag-and-drop operations: + +- `TryGetData()` methods for retrieving data +- `SetDataAsJson()` methods for storing data +- `ITypedDataObject` interface for drag-and-drop operations ### TryGetData\() methods -The `TryGetData()` family replaces the obsolete `GetData()` method with type-safe retrieval and clear success or failure indication. +The `TryGetData()` family replaces the obsolete `GetData()` method. It provides type-safe retrieval and clear success or failure indication for your clipboard operations. #### Basic type-safe retrieval @@ -190,7 +194,7 @@ if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) #### Use a type resolver for legacy binary data (requires BinaryFormatter; not recommended) > [!WARNING] -> Type resolvers only work when BinaryFormatter support is enabled, which is not recommended due to security risks. For more information, see [Enable BinaryFormatter support (not recommended)](#enable-binaryformatter-support-not-recommended). +> Type resolvers only work when BinaryFormatter support is enabled, which isn't recommended due to security risks. For more information, see [Enable BinaryFormatter support (not recommended)](#enable-binaryformatter-support-not-recommended). Type resolvers let you handle legacy binary data by mapping type names to actual types during deserialization. @@ -224,7 +228,7 @@ if (Clipboard.TryGetData("OldCustomData", resolver, autoConvert: true, out MyTyp **Important security considerations for type resolvers:** -- Always use an explicit allow-list of permitted types. +- Always use an explicit allowlist of permitted types. - Never allow dynamic type loading or assembly resolution. - Validate type names before mapping to actual types. - Throw exceptions for any unauthorized or unknown types. @@ -315,14 +319,14 @@ private void OnDragDrop(object sender, DragEventArgs e) ## Types that don't require JSON serialization -Many built-in .NET types work with clipboard operations without requiring JSON serialization or `BinaryFormatter` support. These types are automatically serialized into the .NET Remoting Binary Format (NRBF), which provides efficient storage and maintains type safety. +Many built-in .NET types work with clipboard operations without requiring JSON serialization or `BinaryFormatter` support. These types automatically serialize into the .NET Remoting Binary Format (NRBF), which provides efficient storage and maintains type safety. -These types use the NRBF, the same efficient binary format used by the legacy `BinaryFormatter`. Key characteristics of NRBF serialization include: +These types use NRBF, the same efficient binary format used by the legacy `BinaryFormatter`. NRBF serialization provides these key benefits: -- **Compact binary representation** for efficient storage and transfer. -- **Built-in type information** that preserves exact .NET types during round-trip operations. -- **Cross-process compatibility** that works between different .NET applications. -- **No custom serialization required**. Types serialize automatically. +- **Compact binary representation**: Enables efficient storage and transfer. +- **Built-in type information**: Preserves exact .NET types during round-trip operations. +- **Cross-process compatibility**: Works between different .NET applications. +- **Automatic serialization**: Types serialize without custom code. For technical details, see the [.NET Remoting Binary Format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). @@ -336,11 +340,11 @@ Windows Forms provides several safety mechanisms for these built-in types: - **Automatic validation**. Windows Forms validates type compatibility during deserialization. - **No arbitrary code execution**. Unlike custom types with BinaryFormatter, these types can't execute malicious code. - **Content validation required**. You must still validate data content and ranges for your application logic. -- **No size constraints**. Large arrays or bitmaps are not automatically limited. Monitor memory usage. +- **No size constraints**. Large arrays or bitmaps aren't automatically limited. Monitor memory usage. ### Supported primitive types -The following primitive types work seamlessly with clipboard and `DataObject` operations. You do not need custom serialization or configuration. The clipboard system automatically handles these built-in .NET types: +The following primitive types work seamlessly with clipboard and `DataObject` operations. You don't need custom serialization or configuration. The clipboard system automatically handles these built-in .NET types: - `bool`, `byte`, `char`, `decimal`, `double`, `short`, `int`, and `long`. - `sbyte`, `ushort`, `uint`, `ulong`, `float`, and `string`. @@ -372,7 +376,7 @@ if (Clipboard.TryGetData("MyInt", out int value)) ### Collections of primitive types -Arrays and generic lists of supported primitive types work without additional configuration. However, keep these limitations in mind: +Arrays and generic lists of supported primitive types work without extra configuration. However, keep these limitations in mind: - All array and list elements must be supported primitive types. - Avoid `string[]` and `List` because NRBF format has complexity handling null values in string collections. @@ -509,7 +513,7 @@ if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved)) ## Enable BinaryFormatter support (not recommended) > [!CAUTION] -> `BinaryFormatter` support is **not recommended**. Use it only as a temporary migration bridge for legacy applications that cannot immediately migrate to the new type-safe APIs. +> `BinaryFormatter` support is **not recommended**. Use it only as a temporary migration bridge for legacy applications that can't immediately migrate to the new type-safe APIs. If you must continue using `BinaryFormatter` for clipboard operations in .NET 10, enable limited support through explicit configuration. This approach carries significant security risks and requires several steps. @@ -517,14 +521,14 @@ For complete migration guidance, see the [BinaryFormatter migration guide](/dotn ### Security warnings and risks -`BinaryFormatter` is inherently insecure and deprecated because: +`BinaryFormatter` is inherently insecure and deprecated for these reasons: -- **Arbitrary code execution vulnerabilities.** It can execute arbitrary code during deserialization, exposing your application to remote attacks. -- **Denial of service attacks.** Malicious clipboard data can consume excessive memory or CPU, causing crashes or instability. -- **Information disclosure risks.** Attackers may extract sensitive data from memory. -- **No security boundaries.** The format is fundamentally unsafe; configuration cannot secure it. +- **Arbitrary code execution vulnerabilities**: Attackers can execute malicious code during deserialization, exposing your application to remote attacks. +- **Denial of service attacks**: Malicious clipboard data can consume excessive memory or CPU resources, causing crashes or instability. +- **Information disclosure risks**: Attackers might extract sensitive data from memory. +- **No security boundaries**: The format is fundamentally unsafe, and configuration settings can't secure it. -Enable this support only as a temporary bridge while updating your application to use the new type-safe APIs. +Only enable this support as a temporary bridge while you update your application to use the new type-safe APIs. ### Complete configuration requirements @@ -565,7 +569,7 @@ Follow these steps to enable `BinaryFormatter` support for clipboard operations: } ``` - Without this switch, clipboard operations will not fall back to `BinaryFormatter` even if general serialization support is enabled. + Without this switch, clipboard operations won't fall back to `BinaryFormatter` even if general serialization support is enabled. ### Implement security-focused type resolvers @@ -613,9 +617,9 @@ if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data ## Use AI to migrate clipboard code -Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like Copilot can accelerate this migration process by identifying legacy patterns, generating modern replacements, and creating comprehensive test scenarios. Instead of manually searching through your codebase and converting each clipboard operation individually, leverage Copilot to handle repetitive tasks while you focus on validating results and handling edge cases. +Migrating clipboard operations from .NET 8 to .NET 10 involves systematic code changes across multiple files and classes. AI tools like GitHub Copilot can help accelerate your migration by identifying legacy patterns, suggesting modern replacements, and creating test scenarios. Instead of manually searching through your codebase and converting each clipboard operation individually, you can use AI to handle repetitive tasks while you focus on validating results and handling edge cases. -The following sections demonstrate specific prompt strategies for different aspects of clipboard migration, from identifying problematic code patterns to creating robust JSON-serializable types and comprehensive test suites. +The following sections show specific prompt strategies for different aspects of clipboard migration, from finding problematic code patterns to creating robust JSON-serializable types and comprehensive test suites. ### Use AI to identify legacy clipboard patterns From 3d0decaddcf766ac320f03b114f26f0f145c24de Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 15:09:21 -0700 Subject: [PATCH 22/51] Phase 1 complete --- .github/instructions/plan.clipboard.instructions.md | 7 ++++--- .../winforms/migration/clipboard-dataobject-net10.md | 2 +- dotnet-desktop-guide/winforms/toc.yml | 4 +++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/instructions/plan.clipboard.instructions.md b/.github/instructions/plan.clipboard.instructions.md index cd44257df4..1349fafcb4 100644 --- a/.github/instructions/plan.clipboard.instructions.md +++ b/.github/instructions/plan.clipboard.instructions.md @@ -32,12 +32,12 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar ## Detailed Update Plan -### Phase 1: Create New Comprehensive Overview Article +### Phase 1: Create New Comprehensive Overview Article ✅ -**New Article: `clipboard-dataobject-net10.md`** +**New Article: `clipboard-dataobject-net10.md`** (COMPLETED) - **Location**: dontnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md -- **Priority**: High +- **Priority**: High (COMPLETED) - **Content Focus**: - Overview of .NET 10 changes and BinaryFormatter removal - Comparison table: old vs new APIs @@ -46,6 +46,7 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - Security improvements and implications - **Target Audience**: Developers migrating existing applications - **Estimated Length**: 2,000-2,500 words +- **Status**: Completed ### Phase 2: Update Existing Core Articles diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 52b161e7bd..ff6c10f937 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -1,5 +1,5 @@ --- -title: "Windows Forms clipboard and DataObject changes in .NET 10" +title: "Clipboard and DataObject changes in .NET 10" description: "Learn about the major clipboard and drag-and-drop changes in .NET 10, including new type-safe APIs, JSON serialization, and migration from BinaryFormatter." author: adegeo ms.author: adegeo diff --git a/dotnet-desktop-guide/winforms/toc.yml b/dotnet-desktop-guide/winforms/toc.yml index cdf4238f58..7925d67f11 100644 --- a/dotnet-desktop-guide/winforms/toc.yml +++ b/dotnet-desktop-guide/winforms/toc.yml @@ -23,10 +23,12 @@ items: items: - name: Create an app href: get-started/create-app-visual-studio.md -- name: Migration +- name: Upgrade items: - name: How to upgrade to the latest .NET href: migration/index.md + - name: Clipboard and DataObject changes in .NET 10 + href: migration/clipboard-dataobject-net10.md - name: Accessibility improvements with .NET href: windows-forms-accessibility-improvements.md - name: Advanced topics From fc4c1136a451c59af2ece8b3e25c581bac9ce8a2 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 15:26:11 -0700 Subject: [PATCH 23/51] Fix build errs --- .../migration/clipboard-dataobject-net10.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index ff6c10f937..46dbf926d2 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -20,7 +20,7 @@ This article shows you how to upgrade your Windows Forms clipboard and drag-and- `BinaryFormatter` was removed from the runtime in .NET 9 because of security vulnerabilities. This change broke clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and type-safe methods to restore this functionality, improve security, and provide better error handling and cross-process compatibility. -One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and shouldn't be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. +One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and shouldn't be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. The following sections provide detailed migration guidance, explain which types work without changes, and show how to handle both new development and legacy data scenarios. @@ -28,7 +28,7 @@ The following sections provide detailed migration guidance, explain which types Before you continue, review these concepts: -- How applications used `BinaryFormatter` in clipboard and drag-and-drop scenarios before .NET 9. +- How applications used `BinaryFormatter` in clipboard and drag-and-drop scenarios before .NET 9. - The security vulnerabilities that led to the removal of `BinaryFormatter`. - How to work with `System.Text.Json` serialization patterns and their limitations. @@ -71,7 +71,7 @@ object data = Clipboard.GetData("MyApp.Person"); #### Migration guidance -Use the new `SetDataAsJson()` method or manually serialize to a `string` or `byte[]`. For details, see the [Working with custom types](#working-with-custom-types) section. +Use the new `SetDataAsJson()` method or manually serialize to a `string` or `byte[]`. For details, see the [Work with custom types](#work-with-custom-types) section. ### GetData() is obsolete - use TryGetData\() instead @@ -328,7 +328,7 @@ These types use NRBF, the same efficient binary format used by the legacy `Binar - **Cross-process compatibility**: Works between different .NET applications. - **Automatic serialization**: Types serialize without custom code. -For technical details, see the [.NET Remoting Binary Format specification](https://learn.microsoft.com/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). +For technical details, see the [.NET Remoting Binary Format specification](/openspecs/windows_protocols/ms-nrbf/75b9fe09-be15-475f-85b8-ae7b7558cfe5). Classes that support NRBF-encoded data are implemented in the namespace. @@ -463,7 +463,7 @@ public struct Point3D ### Use JSON attributes for advanced control -Use `System.Text.Json` attributes only when you need to customize serialization behavior. For comprehensive guidance on `System.Text.Json` serialization, attributes, and advanced configuration options, see [JSON serialization and deserialization in .NET](/dotnet/standard/serialization/system-text-json/). +Use `System.Text.Json` attributes only when you need to customize serialization behavior. For comprehensive guidance on `System.Text.Json` serialization, attributes, and advanced configuration options, see [JSON serialization and deserialization in .NET](/dotnet/standard/serialization/system-text-json/overview). The following example shows how you can use JSON attributes to control serialization: @@ -717,6 +717,6 @@ Check for: missing error handling, types that might not serialize properly to JS ## Related content -- [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md) -- [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) -- [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) +- [How to: Add Data to the Clipboard](../advanced/how-to-add-data-to-the-clipboard.md) +- [How to: Retrieve Data from the Clipboard](../advanced/how-to-retrieve-data-from-the-clipboard.md) +- [Drag-and-Drop Operations and Clipboard Support](../advanced/drag-and-drop-operations-and-clipboard-support.md) From e65b2df2c093473f7cdd078fd595844b9c30997c Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Fri, 26 Sep 2025 16:51:47 -0700 Subject: [PATCH 24/51] Phase 2.1: Complete --- ...d-drop-operations-and-clipboard-support.md | 31 ++++++++++++++++--- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md b/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md index 973e5d2499..1c72264798 100644 --- a/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md +++ b/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md @@ -1,14 +1,18 @@ --- title: "Drag-and-Drop Operations and Clipboard Support" -description: Learn how to enable user-drag-and-drop operations within Windows-based applications by handling a series of events. -ms.date: "03/30/2017" +description: Learn how to enable user drag-and-drop operations and clipboard support within Windows Forms applications, including the new type-safe APIs introduced in .NET 10. +ms.date: "09/26/2025" ms.service: dotnet-framework ms.update-cycle: 1825-days helpviewer_keywords: - "drag and drop [Windows Forms]" - "drag and drop [Windows Forms], Windows Forms" - "Clipboard [Windows Forms], Windows Forms" + - "TryGetData [Windows Forms]" + - "SetDataAsJson [Windows Forms]" + - "BinaryFormatter removal [Windows Forms]" ms.assetid: 7cce79b6-5835-46fd-b690-73f12ad368b2 +ai-usage: ai-assisted --- # Drag-and-Drop Operations and Clipboard Support @@ -16,6 +20,20 @@ You can enable user drag-and-drop operations within a Windows-based application You can also implement user cut/copy/paste support and user data transfer to the Clipboard within your Windows-based applications by using simple method calls. +## .NET 10 Compatibility + +Starting with .NET 9, `BinaryFormatter` was removed from the runtime due to security vulnerabilities. This removal broke clipboard and drag-and-drop operations for custom objects, creating a functionality gap for Windows Forms applications. + +.NET 10 addresses this issue by introducing new APIs that restore clipboard and drag-and-drop functionality while improving security, error handling, and cross-process compatibility. These APIs use JSON serialization and provide type-safe methods for data operations. + +Key improvements in .NET 10 include: + +- **Type-safe data retrieval** with `TryGetData()` methods that provide better error handling. +- **JSON serialization** for custom types using `SetDataAsJson()` methods. +- **Built-in support** for common data types without requiring binary serialization. + +For comprehensive guidance on updating your applications, see [Clipboard and drag-and-drop changes in .NET 10](../migration/clipboard-dataobject-net10.md). + ## In This Section [Walkthrough: Performing a Drag-and-Drop Operation in Windows Forms](walkthrough-performing-a-drag-and-drop-operation-in-windows-forms.md)\ @@ -25,10 +43,13 @@ Explains how to start a drag-and-drop operation. Illustrates how to accomplish drag-and-drop operations across applications. [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md)\ -Describes a way to programmatically insert information on the Clipboard. +Describes how to programmatically insert information on the Clipboard, including the new type-safe APIs available in .NET 10. [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md)\ -Describes how to access the data stored on the Clipboard. +Describes how to access data stored on the Clipboard using both legacy methods and the new type-safe `TryGetData()` methods. + +[Clipboard and drag-and-drop changes in .NET 10](../migration/clipboard-dataobject-net10.md)\ +Comprehensive guide for migrating clipboard and drag-and-drop code to the new .NET 10 APIs and understanding the removal of `BinaryFormatter`. ## Related Sections @@ -39,7 +60,7 @@ Describes the methods, events, and classes used to implement drag-and-drop behav Describes the intricacies of the event that asks permission to continue the drag operation. -Describes the intricacies of the method that is central to beginning a drag operation. +Describes the intricacies of the method that's central to beginning a drag operation. Also see [How to: Send Data to the Active MDI Child](how-to-send-data-to-the-active-mdi-child.md). From c5dca0ff0f4e46a2242517c6b76e1d2df6d36c01 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Mon, 29 Sep 2025 09:10:56 -0700 Subject: [PATCH 25/51] Add xref links --- .../migration/clipboard-dataobject-net10.md | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 46dbf926d2..1762b11b81 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -16,11 +16,11 @@ ai-usage: ai-assisted # Windows Forms clipboard and DataObject changes in .NET 10 -This article shows you how to upgrade your Windows Forms clipboard and drag-and-drop operations to the new type-safe APIs in .NET 10. You'll learn how to use the new `TryGetData()` and `SetDataAsJson()` methods, understand which built-in types work without changes, and discover strategies for handling custom types and legacy data after the removal of `BinaryFormatter`. +This article shows you how to upgrade your Windows Forms clipboard and drag-and-drop operations to the new type-safe APIs in .NET 10. You'll learn how to use the new and methods, understand which built-in types work without changes, and discover strategies for handling custom types and legacy data after the removal of `BinaryFormatter`. `BinaryFormatter` was removed from the runtime in .NET 9 because of security vulnerabilities. This change broke clipboard and drag-and-drop operations with custom objects. .NET 10 introduces new APIs that use JSON serialization and type-safe methods to restore this functionality, improve security, and provide better error handling and cross-process compatibility. -One significant change is that `SetData()` no longer works with custom types. It silently fails without storing data on the clipboard. `GetData()` is obsolete in .NET 10 and shouldn't be used, even for built-in types. Use the new `TryGetData()` and `SetDataAsJson()` methods for type-safe operations and JSON serialization of custom objects. +One significant change is that no longer works with custom types. It silently fails without storing data on the clipboard. is obsolete in .NET 10 and shouldn't be used, even for built-in types. Use the new and methods for type-safe operations and JSON serialization of custom objects. The following sections provide detailed migration guidance, explain which types work without changes, and show how to handle both new development and legacy data scenarios. @@ -71,11 +71,11 @@ object data = Clipboard.GetData("MyApp.Person"); #### Migration guidance -Use the new `SetDataAsJson()` method or manually serialize to a `string` or `byte[]`. For details, see the [Work with custom types](#work-with-custom-types) section. +Use the new [`SetDataAsJson()`](xref:System.Windows.Forms.Clipboard.SetDataAsJson``1(System.String,``0)) method or manually serialize to a `string` or `byte[]`. For details, see the [Work with custom types](#work-with-custom-types) section. ### GetData() is obsolete - use TryGetData\() instead -The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes returns data, you should migrate to the new type-safe `TryGetData()` methods for better error handling and type safety. +The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes returns data, you should migrate to the new type-safe [`TryGetData()`](xref:System.Windows.Forms.Clipboard.TryGetData*) methods for better error handling and type safety. **Obsolete code to avoid:** @@ -121,15 +121,15 @@ Look for: #### Migration guidance -Replace all `GetData()` usage with type-safe `TryGetData()` methods. For comprehensive examples of all overloads, see the [New type-safe APIs](#new-type-safe-apis) section. +Replace all `GetData()` usage with type-safe [`TryGetData()`](xref:System.Windows.Forms.Clipboard.TryGetData*) methods. For comprehensive examples of all overloads, see the [New type-safe APIs](#new-type-safe-apis) section. ## New type-safe APIs .NET 10 introduces three new API families that provide type safety, better error handling, and JSON serialization support for clipboard and drag-and-drop operations: -- `TryGetData()` methods for retrieving data -- `SetDataAsJson()` methods for storing data -- `ITypedDataObject` interface for drag-and-drop operations +- methods for retrieving data +- methods for storing data +- interface for drag-and-drop operations ### TryGetData\() methods @@ -268,7 +268,7 @@ Clipboard.SetDataAsJson("AppConfig", settings) ### ITypedDataObject interface -The `ITypedDataObject` interface enables type-safe drag-and-drop operations by extending `IDataObject` with typed methods. +The interface enables type-safe drag-and-drop operations by extending with typed methods. #### Implement ITypedDataObject in a custom DataObject @@ -336,7 +336,7 @@ Classes that support NRBF-encoded data are implemented in the ()` returns only the requested type. +- **Exact type matching**. returns only the requested type. - **Automatic validation**. Windows Forms validates type compatibility during deserialization. - **No arbitrary code execution**. Unlike custom types with BinaryFormatter, these types can't execute malicious code. - **Content validation required**. You must still validate data content and ranges for your application logic. @@ -434,7 +434,7 @@ Clipboard.SetData("Icon", smallIcon); ## Work with custom types -When you use `SetDataAsJson()` and `TryGetData()` with custom types, `System.Text.Json` handles serialization automatically. Many types work without any special configuration—records, simple classes, and structs with public properties serialize seamlessly. +When you use and with custom types, `System.Text.Json` handles serialization automatically. Many types work without any special configuration—records, simple classes, and structs with public properties serialize seamlessly. ### Simple types that work without attributes @@ -720,3 +720,5 @@ Check for: missing error handling, types that might not serialize properly to JS - [How to: Add Data to the Clipboard](../advanced/how-to-add-data-to-the-clipboard.md) - [How to: Retrieve Data from the Clipboard](../advanced/how-to-retrieve-data-from-the-clipboard.md) - [Drag-and-Drop Operations and Clipboard Support](../advanced/drag-and-drop-operations-and-clipboard-support.md) +- +- From 2ee9866065b7b9fddfd38ad3a2727d28e79371d4 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Mon, 29 Sep 2025 12:45:39 -0700 Subject: [PATCH 26/51] Copy code snippets to local folder --- .../how-to-add-data-to-the-clipboard.md | 20 +- .../framework/csharp/ClipboardExample.csproj | 9 + .../framework/csharp/form1.cs | 169 +++++++++++++++ .../framework/vb/ClipboardExample.vbproj | 9 + .../framework/vb/form1.vb | 193 ++++++++++++++++++ 5 files changed, 390 insertions(+), 10 deletions(-) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md index 82bebea02c..1fd761c906 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md @@ -35,8 +35,8 @@ To add data to the Clipboard in a single, common format, use the specific method 1. Use the , , , or method. - [!code-csharp[System.Windows.Forms.Clipboard#2](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#2)] - [!code-vb[System.Windows.Forms.Clipboard#2](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#2)] + :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="2"::: + :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="2"::: ### To add data to the Clipboard in a custom format @@ -44,19 +44,19 @@ To add data to the Clipboard in a single, common format, use the specific method You can also use predefined format names with the method. For more information, see . - [!code-csharp[System.Windows.Forms.Clipboard#3](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#3)] - [!code-vb[System.Windows.Forms.Clipboard#3](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#3)] - [!code-csharp[System.Windows.Forms.Clipboard#100](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#100)] - [!code-vb[System.Windows.Forms.Clipboard#100](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#100)] + :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="3"::: + :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="3"::: + :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="100"::: + :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="100"::: ### To add data to the Clipboard in multiple formats 1. Use the method and pass in a that contains your data. - [!code-csharp[System.Windows.Forms.Clipboard#4](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#4)] - [!code-vb[System.Windows.Forms.Clipboard#4](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#4)] - [!code-csharp[System.Windows.Forms.Clipboard#100](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#100)] - [!code-vb[System.Windows.Forms.Clipboard#100](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#100)] + :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="4"::: + :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="4"::: + :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="100"::: + :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="100"::: ## See also diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj new file mode 100644 index 0000000000..d161c73f49 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj @@ -0,0 +1,9 @@ + + + + WinExe + net48 + true + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs new file mode 100644 index 0000000000..d6fe2ca949 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs @@ -0,0 +1,169 @@ +using System; +using System.Windows.Forms; + +public class Form1 : Form +{ + [STAThread] + public static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + + // + [Serializable] + public class Customer + { + private string nameValue = string.Empty; + public Customer(String name) + { + nameValue = name; + } + public string Name + { + get { return nameValue; } + set { nameValue = value; } + } + } + // + + public Form1() + { + // + Clipboard.Clear(); + // + } + + // + // Demonstrates SetData, ContainsData, and GetData + // using a custom format name and a business object. + public Customer TestCustomFormat + { + get + { + Clipboard.SetData("CustomerFormat", new Customer("Customer Name")); + if (Clipboard.ContainsData("CustomerFormat")) + { + return Clipboard.GetData("CustomerFormat") as Customer; + } + return null; + } + } + // + + // + // Demonstrates how to use a DataObject to add + // data to the Clipboard in multiple formats. + public void TestClipboardMultipleFormats() + { + DataObject data = new DataObject(); + + // Add a Customer object using the type as the format. + data.SetData(new Customer("Customer as Customer object")); + + // Add a ListViewItem object using a custom format name. + data.SetData("CustomFormat", + new ListViewItem("Customer as ListViewItem")); + + Clipboard.SetDataObject(data); + DataObject retrievedData = (DataObject)Clipboard.GetDataObject(); + + if (retrievedData.GetDataPresent("CustomFormat")) + { + ListViewItem item = + retrievedData.GetData("CustomFormat") as ListViewItem; + if (item != null) + { + MessageBox.Show(item.Text); + } + } + + if (retrievedData.GetDataPresent(typeof(Customer))) + { + Customer customer = + retrievedData.GetData(typeof(Customer)) as Customer; + if (customer != null) + { + MessageBox.Show(customer.Name); + } + } + } + // + + // + // Demonstrates SetData, ContainsData, and GetData. + public Object SwapClipboardFormattedData(String format, Object data) + { + Object returnObject = null; + if (Clipboard.ContainsData(format)) + { + returnObject = Clipboard.GetData(format); + Clipboard.SetData(format, data); + } + return returnObject; + } + // + + // + // + // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. + public System.IO.Stream SwapClipboardAudio( + System.IO.Stream replacementAudioStream) + { + System.IO.Stream returnAudioStream = null; + if (Clipboard.ContainsAudio()) + { + returnAudioStream = Clipboard.GetAudioStream(); + Clipboard.SetAudio(replacementAudioStream); + } + return returnAudioStream; + } + // + + // + // Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList + public System.Collections.Specialized.StringCollection + SwapClipboardFileDropList( + System.Collections.Specialized.StringCollection replacementList) + { + System.Collections.Specialized.StringCollection returnList = null; + if (Clipboard.ContainsFileDropList()) + { + returnList = Clipboard.GetFileDropList(); + Clipboard.SetFileDropList(replacementList); + } + return returnList; + } + // + + // + // Demonstrates SetImage, ContainsImage, and GetImage. + public System.Drawing.Image SwapClipboardImage( + System.Drawing.Image replacementImage) + { + System.Drawing.Image returnImage = null; + if (Clipboard.ContainsImage()) + { + returnImage = Clipboard.GetImage(); + Clipboard.SetImage(replacementImage); + } + return returnImage; + } + // + + // + // Demonstrates SetText, ContainsText, and GetText. + public String SwapClipboardHtmlText(String replacementHtmlText) + { + String returnHtmlText = null; + if (Clipboard.ContainsText(TextDataFormat.Html)) + { + returnHtmlText = Clipboard.GetText(TextDataFormat.Html); + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html); + } + return returnHtmlText; + } + // + // +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj new file mode 100644 index 0000000000..d161c73f49 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj @@ -0,0 +1,9 @@ + + + + WinExe + net48 + true + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb new file mode 100644 index 0000000000..60637fe58a --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb @@ -0,0 +1,193 @@ +Imports System.Windows.Forms + +Module Program + + Sub Main() + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New Form1()) + End Sub +End Module + +Public Class Form1 + Inherits Form + + ' + Public Class Customer + + Private nameValue As String = String.Empty + + Public Sub New(ByVal name As String) + nameValue = name + End Sub + + Public Property Name() As String + Get + Return nameValue + End Get + Set(ByVal value As String) + nameValue = value + End Set + End Property + + End Class + ' + + Public Sub New() + ' + Clipboard.Clear() + ' + End Sub + + ' + ' Demonstrates SetData, ContainsData, and GetData + ' using a custom format name and a business object. + Public ReadOnly Property TestCustomFormat() As Customer + Get + Clipboard.SetData("CustomerFormat", New Customer("Customer Name")) + + If Clipboard.ContainsData("CustomerFormat") Then + Return CType(Clipboard.GetData("CustomerFormat"), Customer) + End If + + Return Nothing + End Get + End Property + ' + + ' + ' Demonstrates how to use a DataObject to add + ' data to the Clipboard in multiple formats. + Public Sub TestClipboardMultipleFormats() + + Dim data As New DataObject() + + ' Add a Customer object using the type as the format. + data.SetData(New Customer("Customer as Customer object")) + + ' Add a ListViewItem object using a custom format name. + data.SetData("CustomFormat", _ + New ListViewItem("Customer as ListViewItem")) + + Clipboard.SetDataObject(data) + Dim retrievedData As DataObject = _ + CType(Clipboard.GetDataObject(), DataObject) + + If (retrievedData.GetDataPresent("CustomFormat")) Then + + Dim item As ListViewItem = _ + TryCast(retrievedData.GetData("CustomFormat"), ListViewItem) + + If item IsNot Nothing Then + MessageBox.Show(item.Text) + End If + + End If + + If retrievedData.GetDataPresent(GetType(Customer)) Then + + Dim customer As Customer = _ + CType(retrievedData.GetData(GetType(Customer)), Customer) + + If customer IsNot Nothing Then + + MessageBox.Show(customer.Name) + End If + + End If + + End Sub + ' + + ' + ' Demonstrates SetData, ContainsData, and GetData. + Public Function SwapClipboardFormattedData( _ + ByVal format As String, ByVal data As Object) As Object + + Dim returnObject As Object = Nothing + + If (Clipboard.ContainsData(format)) Then + returnObject = Clipboard.GetData(format) + Clipboard.SetData(format, data) + End If + + Return returnObject + + End Function + ' + + ' + ' + ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. + Public Function SwapClipboardAudio( _ + ByVal replacementAudioStream As System.IO.Stream) _ + As System.IO.Stream + + Dim returnAudioStream As System.IO.Stream = Nothing + + If (Clipboard.ContainsAudio()) Then + returnAudioStream = Clipboard.GetAudioStream() + Clipboard.SetAudio(replacementAudioStream) + End If + + Return returnAudioStream + + End Function + ' + + ' + ' Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList + Public Function SwapClipboardFileDropList(ByVal replacementList _ + As System.Collections.Specialized.StringCollection) _ + As System.Collections.Specialized.StringCollection + + Dim returnList As System.Collections.Specialized.StringCollection _ + = Nothing + + If Clipboard.ContainsFileDropList() Then + + returnList = Clipboard.GetFileDropList() + Clipboard.SetFileDropList(replacementList) + End If + + Return returnList + + End Function + ' + + ' + ' Demonstrates SetImage, ContainsImage, and GetImage. + Public Function SwapClipboardImage( _ + ByVal replacementImage As System.Drawing.Image) _ + As System.Drawing.Image + + Dim returnImage As System.Drawing.Image = Nothing + + If Clipboard.ContainsImage() Then + returnImage = Clipboard.GetImage() + Clipboard.SetImage(replacementImage) + End If + + Return returnImage + End Function + ' + + ' + ' Demonstrates SetText, ContainsText, and GetText. + Public Function SwapClipboardHtmlText( _ + ByVal replacementHtmlText As String) As String + + Dim returnHtmlText As String = Nothing + + If (Clipboard.ContainsText(TextDataFormat.Html)) Then + returnHtmlText = Clipboard.GetText(TextDataFormat.Html) + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html) + End If + + Return returnHtmlText + + End Function + ' + ' + +End Class \ No newline at end of file From 6dd1c941586b62c91ca24ac01f02eea6473124d2 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Tue, 30 Sep 2025 10:38:09 -0700 Subject: [PATCH 27/51] Add instruction files --- .github/instructions/EditPass.instructions.md | 52 +++++++ ...md => Plans.ClipboardWork.instructions.md} | 0 .../Snippets.Migrate.instructions.md | 135 ++++++++++++++++++ .../Snippets.Upgrade.instructions.md | 103 +++++++++++++ 4 files changed, 290 insertions(+) create mode 100644 .github/instructions/EditPass.instructions.md rename .github/instructions/{plan.clipboard.instructions.md => Plans.ClipboardWork.instructions.md} (100%) create mode 100644 .github/instructions/Snippets.Migrate.instructions.md create mode 100644 .github/instructions/Snippets.Upgrade.instructions.md diff --git a/.github/instructions/EditPass.instructions.md b/.github/instructions/EditPass.instructions.md new file mode 100644 index 0000000000..a68fac397e --- /dev/null +++ b/.github/instructions/EditPass.instructions.md @@ -0,0 +1,52 @@ +--- +description: Edit the content according to the Microsoft Style Guide +--- + +# Instructions for Editing Articles + +When editing articles in this repository, follow these rules: + +## Disclosure + +- For any markdown file you edit, **IF** the `ai-usage` frontmatter is missing, add it and set it to `ai-assisted`. + +## Writing Style + +IMPORTANT: + +- Use active voice and address the reader directly. +- Use a conversational tone with contractions. +- Use present tense for instructions and descriptions. +- Use imperative mood for instructions (for example, "Call the method" instead of "You should call the method"). +- Use "might" for possibility and "can" for permissible actions. +- Do not use "we" or "our" to refer to documentation authors or product teams. + +## Structure and Format + +- Place blank lines around markdown elements, but do not add extra blank lines if they already exist. +- Use sentence case for headings. Do not use gerunds in titles. +- Be concise and break up long sentences. +- Use the Oxford comma in all lists. +- Number all ordered list items as "1." (not sequentially). +- Use bullets for unordered lists. +- All list items (ordered and unordered) must be complete sentences with proper punctuation, ending with a period if more than three words, unless you're editing a code comment in a code block. +- Do not use "etc." or "and so on." Provide complete lists or use "for example." +- Do not place consecutive headings without content between them. + +## Formatting Conventions + +- Use **bold** for UI elements. +- Use `code style` for file names, folders, custom types, and non-localizable text. +- Use raw URLs in angle brackets. +- Use relative links for files in this repo. +- Remove `https://learn.microsoft.com/en-us` from learn.microsoft.com links. + +## API References + +- Use `` for API cross-references. +- To find API doc IDs, check the official dotnet-api-docs repository or use the API browser. + +## Code Snippets + +- IMPORTANT: If there is a code block in an article, ONLY edit the code comments. +- IMPORTANT: Do not edit the code itself even if there's an error. diff --git a/.github/instructions/plan.clipboard.instructions.md b/.github/instructions/Plans.ClipboardWork.instructions.md similarity index 100% rename from .github/instructions/plan.clipboard.instructions.md rename to .github/instructions/Plans.ClipboardWork.instructions.md diff --git a/.github/instructions/Snippets.Migrate.instructions.md b/.github/instructions/Snippets.Migrate.instructions.md new file mode 100644 index 0000000000..d90a18308f --- /dev/null +++ b/.github/instructions/Snippets.Migrate.instructions.md @@ -0,0 +1,135 @@ +--- +description: Migrate code from the old ~/samples/snippets/ location to the relative ./snippets location. +--- + +# Migrate code snippets + +**IMPORTANT**: Unless otherwise asked to, **only** edit the article file in context. At the end of your operations you may ask for permission to edit other articles referencing the same snippets. + +## Repository structure for code snippets + +**IMPORTANT**: This repository has TWO different locations for code snippets: + +### Old location (legacy - to be migrated FROM) +- Path: `~/samples/snippets/` +- Example: `~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs` +- Status: Legacy, should be migrated to new location + +### New location (current standard - migrate TO) +- Path pattern: `./snippets/{doc-file}/[net-or-framework]/{code-language}/` +- Example: `./snippets/how-to-add-data-to-the-clipboard/net/csharp/form1.cs` + +**Path components explained:** +- `{doc-file}`: The markdown article filename WITHOUT the `.md` extension + - Example: For article `how-to-add-data-to-the-clipboard.md` → use `how-to-add-data-to-the-clipboard` +- `[net-or-framework]`: Choose based on target framework: + - `net`: For .NET (.NET 6 and newer) + - `framework`: For .NET Framework (4.8 and older) + - **Rule**: Only include this subfolder when the article demonstrates BOTH .NET and .NET Framework approaches +- `{code-language}`: + - `csharp`: For C# code + - `vb`: For Visual Basic code + +## Legacy code characteristics (migrate FROM these) + +**Location**: `~/samples/snippets/` folder +**Problems with legacy code:** +- Written for .NET Framework (outdated) +- Often incomplete or non-compilable +- May lack project files +- Uses outdated syntax and patterns + +**Legacy article references look like this:** +```markdown +[!code-{code-language}[description](~/samples/snippets/{path-to-file}#{snippet-identifier})] +``` + +## Current code requirements (migrate TO these) + +**Location**: `./snippets/{doc-file}/[framework]/{code-language}/` + +**Requirements for current code standards:** +- ✅ MUST be complete and compilable +- ✅ MUST include a project file +- ✅ MUST target appropriate .NET version (see targeting rules below) +- ✅ MUST provide BOTH C# and Visual Basic versions +- ✅ MUST use appropriate syntax for the target framework + +**Current article references look like this:** +```markdown +:::code language="{code-language}" source="{file-path}" id="{snippet-identifier}"::: +``` + +**Framework targeting rules:** +- **Migration vs. Modernization**: + - **Migration**: Move code to new location with minimal changes + - **Modernization**: Update code to use latest .NET features and best practices +- **When to migrate only**: When article has `ms.service: dotnet-framework` frontmatter or is specifically about .NET Framework features +- **When to modernize**: When article demonstrates both .NET and .NET Framework, or when specifically requested +- **Default targeting**: + - For .NET Framework-specific articles: Keep targeting .NET Framework + - For general articles: Target latest .NET version (e.g., .NET 10) + - For mixed articles: Create separate snippets in `net/` and `framework/` subfolders + +## Migration steps (follow in order) + +**WHEN TO MIGRATE**: Migrate code when you encounter articles with references to `~/samples/snippets/` paths. + +**STEP-BY-STEP PROCESS:** + +### 1. Analyze existing code and article context +- **Find**: Locate the legacy snippet file in `~/samples/snippets/` +- **Check frontmatter**: Look for `ms.service: dotnet-framework` in the article's frontmatter +- **Determine scope**: + - If frontmatter has `ms.service: dotnet-framework` → this is likely a .NET Framework-specific article + - if frontmatter has `ms.service: dotnet-desktop` or similar → this is likely a dual-framework or general article + - If article demonstrates both .NET and .NET Framework → prepare for dual targeting + - If article is general purpose → consider targeting current .NET +- **Identify**: Determine the programming language (C# or Visual Basic) +- **Extract**: Note the snippet identifier used in the article reference + +### 2. Create new folder structure +- **Pattern**: `./snippets/{doc-file}/[net-or-framework]/{code-language}/` +- **Example**: For article `clipboard-operations.md` → create `./snippets/clipboard-operations/net/csharp/` +- **Decision tree for framework folder**: + - Article has `ms.service: dotnet-framework` frontmatter → use `./snippets/{doc-file}/framework/{code-language}/` + - Article shows ONLY current .NET examples → use `./snippets/{doc-file}/{code-language}/` (omit framework folder) + - Article shows BOTH .NET and .NET Framework → create both `./snippets/{doc-file}/net/{code-language}/` and `./snippets/{doc-file}/framework/{code-language}/` + +### 3. Migrate and update code +- **Copy**: Move the code file to the new location +- **Update approach**: + - **For .NET Framework articles**: Migrate with minimal changes, keep .NET Framework targeting + - **For dual-framework articles**: Create both versions with appropriate targeting and update frontmatter to `ms.service: dotnet-desktop` + - **For general articles**: Update to target current .NET only if specifically requested or if article demonstrates modernization +- **Complete**: Ensure code is fully functional and compilable +- **Project file**: Create or update project file with appropriate target framework + +### 4. Create both language versions +- **Requirement**: MUST provide both C# and Visual Basic versions +- **C# path**: `./snippets/{doc-file}/[framework]/csharp/` +- **VB path**: `./snippets/{doc-file}/[framework]/vb/` + +### 5. Update article references +- **Replace**: Change from legacy `[!code-...]` format to modern `:::code...:::` format +- **Before**: `[!code-csharp[description](~/samples/snippets/path/file.cs#snippet1)]` +- **After**: `:::code language="csharp" source="./snippets/doc-name/net/csharp/file.cs" id="snippet1":::` + +### 6. Validate +- **Build**: Ensure all code compiles successfully +- **Test**: Verify snippet references work in the article +- **Clean**: Remove unused legacy files (if no other articles reference them) + +### 7. Delete +- **Identify**: Check if the old snippet file is used by any other articles +- **Delete**: If old snippet is no longer used by any article, delete it. + +## Common mistakes to avoid + +- ❌ **Don't** assume all code needs to be modernized - check article context first +- ❌ **Don't** modernize .NET Framework-specific articles unless specifically requested +- ❌ **Don't** ignore the `ms.service: dotnet-framework` frontmatter indicator +- ❌ **Don't** forget to create both C# and VB versions +- ❌ **Don't** mix up the framework targeting (net vs framework) +- ❌ **Don't** forget to update ALL article references to the migrated code +- ❌ **Don't** leave incomplete or non-compilable code diff --git a/.github/instructions/Snippets.Upgrade.instructions.md b/.github/instructions/Snippets.Upgrade.instructions.md new file mode 100644 index 0000000000..fac19c8e22 --- /dev/null +++ b/.github/instructions/Snippets.Upgrade.instructions.md @@ -0,0 +1,103 @@ +--- +description: Upgrade snippets to the latest .NET and possibly migrate from .NET Framework +--- + +# Code Snippet Upgrade Instructions + +## When to Apply These Instructions + +Apply these instructions when working with code snippets that need modernization, especially when: +- Migrating snippets from old locations +- Upgrading .NET Framework code to modern .NET +- Improving snippet quality and completeness +- Adding missing language versions (C# or VB) + +## Snippet Structure Requirements + +All snippets must follow this folder structure relative to the referencing article: + +``` +./snippets/{article-name}/[net|framework]/{language}/ +``` + +**Examples:** +- `./snippets/how-to-add-data-to-the-clipboard/net/csharp/MainForm.cs` +- `./snippets/how-to-add-data-to-the-clipboard/framework/vb/MainForm.vb` + +## Required Upgrade Actions + +### 1. File Naming and Organization +- **USE** PascalCase for class names and file names (e.g., `MainForm.cs`, `DataProcessor.cs`) +- **ORGANIZE** files logically within the language folder + +### 2. Snippet naming +- **REPLACE** simplistic identifiers (like single numbers) with descriptive snippet names + +### 3. .NET Version and Syntax Modernization +- **TARGET** the latest stable .NET version for `/net/` folders +- **USE** modern C# features for .NET snippets: + - File-scoped namespaces + - Top-level statements where appropriate + - Pattern matching + - String interpolation + - var keyword where type is obvious + - Modern using statements + +### 4. Project File Requirements +- **USE** `dotnet new` to create the projects. Fallback to manual project creation if `dotnet new` is failing. +- **CREATE** a complete, compilable project structure +- **INCLUDE** appropriate `.csproj` or `.vbproj` file +- **TARGET** latest .NET version: `net8.0-windows` +- **ADD** necessary package references and properties + +### 5. Code Quality Standards +- **ENSURE** code compiles without warnings +- **FOLLOW** .NET naming conventions +- **USE** appropriate access modifiers +- **INCLUDE** necessary using/import statements +- **ADD** minimal but helpful code comments for complex logic + +### 6. Language Parity +- **CREATE** both C# and VB.NET versions unless the parent article is in a language-specific folder +- **MAINTAIN** functional equivalence between language versions +- **ADAPT** language-specific idioms appropriately + +## Framework-Specific Considerations + +### For .NET Framework Snippets (`/framework/` folders) +- **MAINTAIN** .NET Framework compatibility +- **AVOID** modern C# features not available in the target framework version +- **USE** classic C# syntax and patterns +- **TARGET** appropriate framework version (typically .NET Framework 4.8) + +### For Modern .NET Snippets (`/net/` folders) +- **USE** latest .NET features and syntax +- **TARGET** latest stable .NET version +- **LEVERAGE** modern performance patterns +- **UTILIZE** new APIs where beneficial + +## Example Transformation + +**Before (simple identifier):** +``` +./snippets/clipboard-article/code.cs +``` + +**After (descriptive structure):** +``` +./snippets/how-to-add-data-to-the-clipboard/net/csharp/ +├── ClipboardExample.csproj +├── MainForm.cs +└── Program.cs +``` + +## Validation Checklist + +Before completing snippet upgrades, verify: +- [ ] Files have descriptive, meaningful names +- [ ] Project compiles without errors or warnings +- [ ] Code follows .NET naming conventions +- [ ] Appropriate target framework is specified +- [ ] Both C# and VB versions exist (when required) +- [ ] Modern syntax is used for .NET snippets +- [ ] Framework-compatible syntax for .NET Framework snippets \ No newline at end of file From d4a278a5b2811ef3953569bf97e8eae13e11a425 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 09:01:55 -0700 Subject: [PATCH 28/51] Update how-to-add-data --- dotnet-desktop-guide/docfx.json | 3 +- .../how-to-add-data-to-the-clipboard.md | 102 ++++++- .../{form1.cs => ClipboardOperations.cs} | 40 +-- ...mple.csproj => ClipboardOperations.csproj} | 0 .../vb/{form1.vb => ClipboardOperations.vb} | 40 +-- ...mple.vbproj => ClipboardOperations.vbproj} | 0 .../net/csharp/ClipboardImageTest.Designer.cs | 130 ++++++++ .../net/csharp/ClipboardImageTest.cs | 125 ++++++++ .../net/csharp/ClipboardImageTest.resx | 120 ++++++++ .../ClipboardMultipleFormatsTest.Designer.cs | 141 +++++++++ .../csharp/ClipboardMultipleFormatsTest.cs | 125 ++++++++ .../csharp/ClipboardMultipleFormatsTest.resx | 61 ++++ .../net/csharp/ClipboardOperations.csproj | 35 +++ .../net/csharp/ClipboardTextTest.Designer.cs | 282 ++++++++++++++++++ .../net/csharp/ClipboardTextTest.cs | 105 +++++++ .../net/csharp/ClipboardTextTest.resx | 120 ++++++++ .../csharp/FileDropClipboardTest.Designer.cs | 65 ++++ .../net/csharp/FileDropClipboardTest.cs | 82 +++++ .../net/csharp/FileDropClipboardTest.resx | 120 ++++++++ .../net/csharp/Form1.Designer.cs | 44 +++ .../net/csharp/Form1.cs | 140 +++++++++ .../net/csharp/Form1.resx | 120 ++++++++ .../net/csharp/Program.cs | 24 ++ .../csharp/Properties/Resources.Designer.cs | 63 ++++ .../net/csharp/Properties/Resources.resx | 120 ++++++++ .../net/csharp/image1.png | Bin 0 -> 5872 bytes .../net/csharp/image2.png | Bin 0 -> 4835 bytes .../net/vb/ClipboardOperations.vbproj | 17 ++ .../net/vb/Form1.Designer.vb | 31 ++ .../net/vb/Form1.vb | 146 +++++++++ .../net/vb/Program.vb | 11 + dotnet-desktop-guide/zone-pivot-groups.yml | 11 + 32 files changed, 2366 insertions(+), 57 deletions(-) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/{form1.cs => ClipboardOperations.cs} (89%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/{ClipboardExample.csproj => ClipboardOperations.csproj} (100%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/{form1.vb => ClipboardOperations.vb} (90%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/{ClipboardExample.vbproj => ClipboardOperations.vbproj} (100%) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardOperations.csproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Program.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.resx create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image1.png create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image2.png create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/ClipboardOperations.vbproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.Designer.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Program.vb create mode 100644 dotnet-desktop-guide/zone-pivot-groups.yml diff --git a/dotnet-desktop-guide/docfx.json b/dotnet-desktop-guide/docfx.json index dfaafeaf4d..b579ad2d5e 100644 --- a/dotnet-desktop-guide/docfx.json +++ b/dotnet-desktop-guide/docfx.json @@ -20,7 +20,8 @@ "feedback_product_url": "https://developercommunity.visualstudio.com/VisualStudio", "author": "adegeo", "uhfHeaderId": "MSDocsHeader-DotNet", - "ms.author": "adegeo" + "ms.author": "adegeo", + "_zonePivotGroups": "zone-pivot-groups.yml" }, "fileMetadata": { "titleSuffix": { diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md index 1fd761c906..73a93bfd91 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md @@ -1,8 +1,9 @@ --- title: "How to: Add Data to the Clipboard" -ms.date: "03/30/2017" +ms.date: 10/02/2025 ms.service: dotnet-framework ms.update-cycle: 1825-days +zone_pivot_groups: dotnet-version dev_langs: - "csharp" - "vb" @@ -20,45 +21,114 @@ When you add data to the Clipboard, you can indicate the data format so that oth A Clipboard format is a string that identifies the format so that an application that uses that format can retrieve the associated data. The class provides predefined format names for your use. You can also use your own format names or use the type of an object as its format. -To add data to the Clipboard in one or multiple formats, use the method. You can pass any object to this method, but to add data in multiple formats, you must first add the data to a separate object designed to work with multiple formats. Typically, you will add your data to a , but you can use any type that implements the interface. - -To add data to the Clipboard in a single, common format, use the specific method for that format, such as for text. - > [!NOTE] > All Windows-based applications share the Clipboard. Therefore, the contents are subject to change when you switch to another application. > > The class can only be used in threads set to single thread apartment (STA) mode. To use this class, ensure that your `Main` method is marked with the attribute. -> + +To add data to the Clipboard in one or multiple formats, use the method. You can pass any object to this method, but to add data in multiple formats, you must first add the data to a separate object designed to work with multiple formats. Typically, you will add your data to a , but you can use any type that implements the interface. + +To add data to the Clipboard in a single, common format, use the specific method for that format, such as for text. + +::: zone pivot="dotnet" + +> [!IMPORTANT] +> Custom objects must be serializable to JSON for them to be put on the Clipboard. Use the new type-safe methods like which automatically handle JSON serialization. The legacy `SetData()` method no longer works with custom objects starting with .NET 9 due to the removal of `BinaryFormatter`. + +::: zone-end + +::: zone pivot="dotnetframework" + +> [!IMPORTANT] > An object must be serializable for it to be put on the Clipboard. To make a type serializable, mark it with the attribute. If you pass a non-serializable object to a Clipboard method, the method will fail without throwing an exception. For more information about serialization, see . +::: zone-end + ### To add data to the Clipboard in a single, common format 1. Use the , , , or method. - :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="2"::: - :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="2"::: +::: zone pivot="dotnet" + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs" id="SetTextExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb" id="SetTextExample"::: + +::: zone-end + +::: zone pivot="dotnetframework" + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs" id="SetTextExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb" id="SetTextExample"::: + +::: zone-end ### To add data to the Clipboard in a custom format +::: zone pivot="dotnet" + +1. Use the method with a custom format name and your object. + + The `SetDataAsJson()` method automatically serializes your custom objects using `System.Text.Json`. This is the recommended approach in .NET 10 and later for storing custom types on the clipboard, as it provides type safety and security advantages over the legacy `SetData()` method. + + > [!IMPORTANT] + > The legacy method no longer works with custom objects in .NET 9 and later due to the removal of `BinaryFormatter`. Use `SetDataAsJson()` instead for custom types. + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs" id="CustomFormatExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb" id="CustomFormatExample"::: + +The `Customer` class used in the previous snippet: + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs" id="CustomerClass"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb" id="CustomerClass"::: + +::: zone-end + +::: zone pivot="dotnetframework" + 1. Use the method with a custom format name. You can also use predefined format names with the method. For more information, see . - :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="3"::: - :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="3"::: - :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="100"::: - :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="100"::: +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs" id="CustomFormatExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb" id="CustomFormatExample"::: + +The `Customer` class used in the previous snippet: + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs" id="CustomerClass"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb" id="CustomerClass"::: + +::: zone-end ### To add data to the Clipboard in multiple formats 1. Use the method and pass in a that contains your data. - :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="4"::: - :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="4"::: - :::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs" id="100"::: - :::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb" id="100"::: +::: zone pivot="dotnet" + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs" id="MultipleFormatsExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb" id="MultipleFormatsExample"::: + +The `Customer` class used in the previous snippet: + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs" id="CustomerClass"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb" id="CustomerClass"::: + +::: zone-end + +::: zone pivot="dotnetframework" + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs" id="MultipleFormatsExample"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb" id="MultipleFormatsExample"::: + +The `Customer` class used in the previous snippet: + +:::code language="csharp" source="./snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs" id="CustomerClass"::: +:::code language="vb" source="./snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb" id="CustomerClass"::: + +::: zone-end ## See also - [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) - [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) +- [Windows Forms clipboard and DataObject changes in .NET 10](../../migration/clipboard-dataobject-net10.md) diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs similarity index 89% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs index d6fe2ca949..a87b24800a 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/form1.cs +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.cs @@ -11,7 +11,7 @@ public static void Main() Application.Run(new Form1()); } - // + // [Serializable] public class Customer { @@ -26,16 +26,16 @@ public string Name set { nameValue = value; } } } - // + // public Form1() { - // + // Clipboard.Clear(); - // + // } - // + // // Demonstrates SetData, ContainsData, and GetData // using a custom format name and a business object. public Customer TestCustomFormat @@ -50,9 +50,9 @@ public Customer TestCustomFormat return null; } } - // + // - // + // // Demonstrates how to use a DataObject to add // data to the Clipboard in multiple formats. public void TestClipboardMultipleFormats() @@ -89,9 +89,9 @@ public void TestClipboardMultipleFormats() } } } - // + // - // + // // Demonstrates SetData, ContainsData, and GetData. public Object SwapClipboardFormattedData(String format, Object data) { @@ -103,10 +103,10 @@ public Object SwapClipboardFormattedData(String format, Object data) } return returnObject; } - // + // - // - // + // + // // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. public System.IO.Stream SwapClipboardAudio( System.IO.Stream replacementAudioStream) @@ -119,9 +119,9 @@ public System.IO.Stream SwapClipboardAudio( } return returnAudioStream; } - // + // - // + // // Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList public System.Collections.Specialized.StringCollection SwapClipboardFileDropList( @@ -135,9 +135,9 @@ public System.Collections.Specialized.StringCollection } return returnList; } - // + // - // + // // Demonstrates SetImage, ContainsImage, and GetImage. public System.Drawing.Image SwapClipboardImage( System.Drawing.Image replacementImage) @@ -150,9 +150,9 @@ public System.Drawing.Image SwapClipboardImage( } return returnImage; } - // + // - // + // // Demonstrates SetText, ContainsText, and GetText. public String SwapClipboardHtmlText(String replacementHtmlText) { @@ -164,6 +164,6 @@ public String SwapClipboardHtmlText(String replacementHtmlText) } return returnHtmlText; } - // - // + // + // } \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.csproj similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardExample.csproj rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/csharp/ClipboardOperations.csproj diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb similarity index 90% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb index 60637fe58a..386dc9e977 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/form1.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vb @@ -12,7 +12,7 @@ End Module Public Class Form1 Inherits Form - ' + ' Public Class Customer Private nameValue As String = String.Empty @@ -31,15 +31,15 @@ Public Class Form1 End Property End Class - ' + ' Public Sub New() - ' + ' Clipboard.Clear() - ' + ' End Sub - ' + ' ' Demonstrates SetData, ContainsData, and GetData ' using a custom format name and a business object. Public ReadOnly Property TestCustomFormat() As Customer @@ -53,9 +53,9 @@ Public Class Form1 Return Nothing End Get End Property - ' + ' - ' + ' ' Demonstrates how to use a DataObject to add ' data to the Clipboard in multiple formats. Public Sub TestClipboardMultipleFormats() @@ -97,9 +97,9 @@ Public Class Form1 End If End Sub - ' + ' - ' + ' ' Demonstrates SetData, ContainsData, and GetData. Public Function SwapClipboardFormattedData( _ ByVal format As String, ByVal data As Object) As Object @@ -114,10 +114,10 @@ Public Class Form1 Return returnObject End Function - ' + ' - ' - ' + ' + ' ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. Public Function SwapClipboardAudio( _ ByVal replacementAudioStream As System.IO.Stream) _ @@ -133,9 +133,9 @@ Public Class Form1 Return returnAudioStream End Function - ' + ' - ' + ' ' Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList Public Function SwapClipboardFileDropList(ByVal replacementList _ As System.Collections.Specialized.StringCollection) _ @@ -153,9 +153,9 @@ Public Class Form1 Return returnList End Function - ' + ' - ' + ' ' Demonstrates SetImage, ContainsImage, and GetImage. Public Function SwapClipboardImage( _ ByVal replacementImage As System.Drawing.Image) _ @@ -170,9 +170,9 @@ Public Class Form1 Return returnImage End Function - ' + ' - ' + ' ' Demonstrates SetText, ContainsText, and GetText. Public Function SwapClipboardHtmlText( _ ByVal replacementHtmlText As String) As String @@ -187,7 +187,7 @@ Public Class Form1 Return returnHtmlText End Function - ' - ' + ' + ' End Class \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vbproj similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardExample.vbproj rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/framework/vb/ClipboardOperations.vbproj diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.Designer.cs new file mode 100644 index 0000000000..1867f62da3 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.Designer.cs @@ -0,0 +1,130 @@ +namespace ClipboardOperations +{ + partial class ClipboardImageTest + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + pictureBox1 = new PictureBox(); + pictureBox2 = new PictureBox(); + pictureBox3 = new PictureBox(); + btnSetImage1 = new Button(); + btnSetImage2 = new Button(); + btnGetFromClipboard = new Button(); + ((System.ComponentModel.ISupportInitialize)pictureBox1).BeginInit(); + ((System.ComponentModel.ISupportInitialize)pictureBox2).BeginInit(); + ((System.ComponentModel.ISupportInitialize)pictureBox3).BeginInit(); + SuspendLayout(); + // + // pictureBox1 + // + pictureBox1.BorderStyle = BorderStyle.FixedSingle; + pictureBox1.Location = new Point(20, 20); + pictureBox1.Name = "pictureBox1"; + pictureBox1.Size = new Size(150, 100); + pictureBox1.SizeMode = PictureBoxSizeMode.Zoom; + pictureBox1.TabIndex = 0; + pictureBox1.TabStop = false; + // + // pictureBox2 + // + pictureBox2.BorderStyle = BorderStyle.FixedSingle; + pictureBox2.Location = new Point(20, 150); + pictureBox2.Name = "pictureBox2"; + pictureBox2.Size = new Size(150, 100); + pictureBox2.SizeMode = PictureBoxSizeMode.Zoom; + pictureBox2.TabIndex = 1; + pictureBox2.TabStop = false; + // + // pictureBox3 + // + pictureBox3.BorderStyle = BorderStyle.FixedSingle; + pictureBox3.Location = new Point(300, 85); + pictureBox3.Name = "pictureBox3"; + pictureBox3.Size = new Size(150, 100); + pictureBox3.SizeMode = PictureBoxSizeMode.Zoom; + pictureBox3.TabIndex = 2; + pictureBox3.TabStop = false; + // + // btnSetImage1 + // + btnSetImage1.Location = new Point(190, 50); + btnSetImage1.Name = "btnSetImage1"; + btnSetImage1.Size = new Size(90, 30); + btnSetImage1.TabIndex = 3; + btnSetImage1.Text = "Set Image 1"; + btnSetImage1.UseVisualStyleBackColor = true; + btnSetImage1.Click += btnSetImage1_Click; + // + // btnSetImage2 + // + btnSetImage2.Location = new Point(190, 180); + btnSetImage2.Name = "btnSetImage2"; + btnSetImage2.Size = new Size(90, 30); + btnSetImage2.TabIndex = 4; + btnSetImage2.Text = "Set Image 2"; + btnSetImage2.UseVisualStyleBackColor = true; + btnSetImage2.Click += btnSetImage2_Click; + // + // btnGetFromClipboard + // + btnGetFromClipboard.Location = new Point(470, 115); + btnGetFromClipboard.Name = "btnGetFromClipboard"; + btnGetFromClipboard.Size = new Size(120, 30); + btnGetFromClipboard.TabIndex = 5; + btnGetFromClipboard.Text = "Get from Clipboard"; + btnGetFromClipboard.UseVisualStyleBackColor = true; + btnGetFromClipboard.Click += btnGetFromClipboard_Click; + // + // ClipboardImageTest + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(620, 280); + Controls.Add(btnGetFromClipboard); + Controls.Add(btnSetImage2); + Controls.Add(btnSetImage1); + Controls.Add(pictureBox3); + Controls.Add(pictureBox2); + Controls.Add(pictureBox1); + Name = "ClipboardImageTest"; + Text = "Clipboard Image Test"; + ((System.ComponentModel.ISupportInitialize)pictureBox1).EndInit(); + ((System.ComponentModel.ISupportInitialize)pictureBox2).EndInit(); + ((System.ComponentModel.ISupportInitialize)pictureBox3).EndInit(); + ResumeLayout(false); + } + + #endregion + + private PictureBox pictureBox1; + private PictureBox pictureBox2; + private PictureBox pictureBox3; + private Button btnSetImage1; + private Button btnSetImage2; + private Button btnGetFromClipboard; + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.cs new file mode 100644 index 0000000000..c5e980501a --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.cs @@ -0,0 +1,125 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Text; +using System.Windows.Forms; +using System.IO; + +namespace ClipboardOperations +{ + public partial class ClipboardImageTest : Form + { + public ClipboardImageTest() + { + InitializeComponent(); + LoadImages(); + } + + private void LoadImages() + { + try + { + // Load image1.png into pictureBox1 + if (File.Exists("image1.png")) + { + pictureBox1.Image = Image.FromFile("image1.png"); + } + else + { + // Create a simple colored rectangle if image doesn't exist + pictureBox1.Image = CreateTestImage(Color.Red, "Image 1"); + } + + // Load image2.png into pictureBox2 + if (File.Exists("image2.png")) + { + pictureBox2.Image = Image.FromFile("image2.png"); + } + else + { + // Create a simple colored rectangle if image doesn't exist + pictureBox2.Image = CreateTestImage(Color.Blue, "Image 2"); + } + } + catch (Exception ex) + { + MessageBox.Show($"Error loading images: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private Image CreateTestImage(Color backgroundColor, string text) + { + Bitmap bitmap = new Bitmap(150, 100); + using (Graphics g = Graphics.FromImage(bitmap)) + { + g.FillRectangle(new SolidBrush(backgroundColor), 0, 0, 150, 100); + g.DrawString(text, SystemFonts.DefaultFont, Brushes.White, 10, 40); + } + return bitmap; + } + + private void btnSetImage1_Click(object sender, EventArgs e) + { + try + { + if (pictureBox1.Image != null) + { + Clipboard.SetImage(pictureBox1.Image); + MessageBox.Show("Image 1 copied to clipboard!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + MessageBox.Show("No image to copy!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + catch (Exception ex) + { + MessageBox.Show($"Error copying image to clipboard: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void btnSetImage2_Click(object sender, EventArgs e) + { + try + { + if (pictureBox2.Image != null) + { + Clipboard.SetImage(pictureBox2.Image); + MessageBox.Show("Image 2 copied to clipboard!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + MessageBox.Show("No image to copy!", "Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + } + catch (Exception ex) + { + MessageBox.Show($"Error copying image to clipboard: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + + private void btnGetFromClipboard_Click(object sender, EventArgs e) + { + try + { + if (Clipboard.ContainsImage()) + { + Image clipboardImage = Clipboard.GetImage(); + pictureBox3.Image = clipboardImage; + MessageBox.Show("Image retrieved from clipboard!", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + else + { + MessageBox.Show("No image found in clipboard!", "Information", MessageBoxButtons.OK, MessageBoxIcon.Information); + pictureBox3.Image = null; + } + } + catch (Exception ex) + { + MessageBox.Show($"Error getting image from clipboard: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.resx new file mode 100644 index 0000000000..8b2ff64a11 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardImageTest.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.Designer.cs new file mode 100644 index 0000000000..914e56cb1a --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.Designer.cs @@ -0,0 +1,141 @@ +namespace ClipboardExample +{ + partial class ClipboardMultipleFormatsTest + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + btnTestMultipleFormats = new Button(); + btnClearClipboard = new Button(); + btnCheckClipboard = new Button(); + lblStatus = new Label(); + txtClipboardInfo = new TextBox(); + lblTitle = new Label(); + lblDescription = new Label(); + SuspendLayout(); + // + // btnTestMultipleFormats + // + btnTestMultipleFormats.Location = new Point(30, 80); + btnTestMultipleFormats.Name = "btnTestMultipleFormats"; + btnTestMultipleFormats.Size = new Size(150, 30); + btnTestMultipleFormats.TabIndex = 0; + btnTestMultipleFormats.Text = "Test Multiple Formats"; + btnTestMultipleFormats.UseVisualStyleBackColor = true; + btnTestMultipleFormats.Click += btnTestMultipleFormats_Click; + // + // btnClearClipboard + // + btnClearClipboard.Location = new Point(200, 80); + btnClearClipboard.Name = "btnClearClipboard"; + btnClearClipboard.Size = new Size(120, 30); + btnClearClipboard.TabIndex = 1; + btnClearClipboard.Text = "Clear Clipboard"; + btnClearClipboard.UseVisualStyleBackColor = true; + btnClearClipboard.Click += btnClearClipboard_Click; + // + // btnCheckClipboard + // + btnCheckClipboard.Location = new Point(340, 80); + btnCheckClipboard.Name = "btnCheckClipboard"; + btnCheckClipboard.Size = new Size(120, 30); + btnCheckClipboard.TabIndex = 2; + btnCheckClipboard.Text = "Check Clipboard"; + btnCheckClipboard.UseVisualStyleBackColor = true; + btnCheckClipboard.Click += btnCheckClipboard_Click; + // + // lblStatus + // + lblStatus.AutoSize = true; + lblStatus.Font = new Font("Segoe UI", 9F, FontStyle.Bold); + lblStatus.Location = new Point(30, 130); + lblStatus.Name = "lblStatus"; + lblStatus.Size = new Size(47, 15); + lblStatus.TabIndex = 3; + lblStatus.Text = "Ready."; + // + // txtClipboardInfo + // + txtClipboardInfo.Location = new Point(30, 160); + txtClipboardInfo.Multiline = true; + txtClipboardInfo.Name = "txtClipboardInfo"; + txtClipboardInfo.ReadOnly = true; + txtClipboardInfo.ScrollBars = ScrollBars.Vertical; + txtClipboardInfo.Size = new Size(430, 150); + txtClipboardInfo.TabIndex = 4; + txtClipboardInfo.Text = "Click 'Check Clipboard' to see available formats."; + // + // lblTitle + // + lblTitle.AutoSize = true; + lblTitle.Font = new Font("Segoe UI", 12F, FontStyle.Bold); + lblTitle.Location = new Point(30, 20); + lblTitle.Name = "lblTitle"; + lblTitle.Size = new Size(246, 21); + lblTitle.TabIndex = 5; + lblTitle.Text = "Clipboard Multiple Formats Test"; + // + // lblDescription + // + lblDescription.AutoSize = true; + lblDescription.Location = new Point(30, 50); + lblDescription.Name = "lblDescription"; + lblDescription.Size = new Size(398, 15); + lblDescription.TabIndex = 6; + lblDescription.Text = "Test adding multiple data formats to clipboard and retrieving them."; + // + // ClipboardMultipleFormatsTest + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(494, 341); + Controls.Add(lblDescription); + Controls.Add(lblTitle); + Controls.Add(txtClipboardInfo); + Controls.Add(lblStatus); + Controls.Add(btnCheckClipboard); + Controls.Add(btnClearClipboard); + Controls.Add(btnTestMultipleFormats); + MaximizeBox = false; + MinimumSize = new Size(510, 380); + Name = "ClipboardMultipleFormatsTest"; + StartPosition = FormStartPosition.CenterScreen; + Text = "Clipboard Multiple Formats Test"; + ResumeLayout(false); + PerformLayout(); + } + + #endregion + + private Button btnTestMultipleFormats; + private Button btnClearClipboard; + private Button btnCheckClipboard; + private Label lblStatus; + private TextBox txtClipboardInfo; + private Label lblTitle; + private Label lblDescription; + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.cs new file mode 100644 index 0000000000..9e34ab0973 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.cs @@ -0,0 +1,125 @@ +using System.Collections.Specialized; + +namespace ClipboardExample; + +public partial class ClipboardMultipleFormatsTest : Form +{ + public ClipboardMultipleFormatsTest() + { + InitializeComponent(); + } + + // Customer class used in custom clipboard format examples. + public class Customer + { + public string Name { get; set; } + + public Customer(string name) + { + Name = name; + } + } + + // Demonstrates how to use a DataObject to add + // data to the Clipboard in multiple formats. + public void TestClipboardMultipleFormats() + { + DataObject data = new(); + + Customer customer = new("Customer #2112"); + ListViewItem listViewItem = new($"Customer as ListViewItem {customer.Name}"); + + // Add a Customer object using the type as the format. + data.SetDataAsJson(customer); + + // Add a ListViewItem object using a custom format name. + data.SetDataAsJson("ListViewItemFormat", listViewItem.Text); + + Clipboard.SetDataObject(data); + + // Retrieve the data from the Clipboard. + DataObject retrievedData = (DataObject)Clipboard.GetDataObject()!; + + if (retrievedData.GetDataPresent("ListViewItemFormat")) + { + if (retrievedData.TryGetData("ListViewItemFormat", out String item)) + { + ListViewItem recreatedListViewItem = new(item); + MessageBox.Show($"Data contains ListViewItem with text of {recreatedListViewItem.Text}"); + } + } + + if (retrievedData.GetDataPresent(typeof(Customer))) + { + if (retrievedData.TryGetData(out Customer newCustomer)) + { + MessageBox.Show($"Data contains Customer with name of {newCustomer.Name}"); + } + } + } + + private void btnTestMultipleFormats_Click(object sender, EventArgs e) + { + try + { + TestClipboardMultipleFormats(); + lblStatus.Text = "Multiple formats test completed successfully!"; + lblStatus.ForeColor = Color.Green; + } + catch (Exception ex) + { + lblStatus.Text = $"Error: {ex.Message}"; + lblStatus.ForeColor = Color.Red; + } + } + + private void btnClearClipboard_Click(object sender, EventArgs e) + { + try + { + Clipboard.Clear(); + lblStatus.Text = "Clipboard cleared."; + lblStatus.ForeColor = Color.Blue; + } + catch (Exception ex) + { + lblStatus.Text = $"Error clearing clipboard: {ex.Message}"; + lblStatus.ForeColor = Color.Red; + } + } + + private void btnCheckClipboard_Click(object sender, EventArgs e) + { + try + { + var dataObject = Clipboard.GetDataObject(); + if (dataObject != null) + { + var formats = dataObject.GetFormats(); + if (formats.Length > 0) + { + txtClipboardInfo.Text = "Available formats in clipboard:\r\n" + string.Join("\r\n", formats); + lblStatus.Text = $"Found {formats.Length} format(s) in clipboard."; + lblStatus.ForeColor = Color.Blue; + } + else + { + txtClipboardInfo.Text = "No data formats found in clipboard."; + lblStatus.Text = "Clipboard is empty."; + lblStatus.ForeColor = Color.Gray; + } + } + else + { + txtClipboardInfo.Text = "Clipboard data object is null."; + lblStatus.Text = "Clipboard is empty."; + lblStatus.ForeColor = Color.Gray; + } + } + catch (Exception ex) + { + lblStatus.Text = $"Error checking clipboard: {ex.Message}"; + lblStatus.ForeColor = Color.Red; + } + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.resx new file mode 100644 index 0000000000..459ff7366d --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardMultipleFormatsTest.resx @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardOperations.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardOperations.csproj new file mode 100644 index 0000000000..6621be8cc8 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardOperations.csproj @@ -0,0 +1,35 @@ + + + + WinExe + net10.0-windows + enable + true + enable + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + Always + + + Always + + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.Designer.cs new file mode 100644 index 0000000000..61e523e249 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.Designer.cs @@ -0,0 +1,282 @@ +namespace ClipboardExample +{ + partial class ClipboardTextTest + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblText = new System.Windows.Forms.Label(); + this.txtText = new System.Windows.Forms.TextBox(); + this.btnSetText = new System.Windows.Forms.Button(); + this.lblUnicodeText = new System.Windows.Forms.Label(); + this.txtUnicodeText = new System.Windows.Forms.TextBox(); + this.btnSetUnicodeText = new System.Windows.Forms.Button(); + this.lblRtf = new System.Windows.Forms.Label(); + this.txtRtf = new System.Windows.Forms.TextBox(); + this.btnSetRtf = new System.Windows.Forms.Button(); + this.lblHtml = new System.Windows.Forms.Label(); + this.txtHtml = new System.Windows.Forms.TextBox(); + this.btnSetHtml = new System.Windows.Forms.Button(); + this.lblCommaSeparatedValue = new System.Windows.Forms.Label(); + this.txtCommaSeparatedValue = new System.Windows.Forms.TextBox(); + this.btnSetCommaSeparatedValue = new System.Windows.Forms.Button(); + this.lblOutput = new System.Windows.Forms.Label(); + this.txtOutput = new System.Windows.Forms.RichTextBox(); + this.btnGetClipboard = new System.Windows.Forms.Button(); + this.btnClearClipboard = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblText + // + this.lblText.AutoSize = true; + this.lblText.Location = new System.Drawing.Point(12, 15); + this.lblText.Name = "lblText"; + this.lblText.Size = new System.Drawing.Size(31, 15); + this.lblText.TabIndex = 0; + this.lblText.Text = "Text:"; + // + // txtText + // + this.txtText.Location = new System.Drawing.Point(12, 33); + this.txtText.Name = "txtText"; + this.txtText.Size = new System.Drawing.Size(300, 23); + this.txtText.TabIndex = 1; + this.txtText.Text = "Plain text example"; + // + // btnSetText + // + this.btnSetText.Location = new System.Drawing.Point(318, 33); + this.btnSetText.Name = "btnSetText"; + this.btnSetText.Size = new System.Drawing.Size(75, 23); + this.btnSetText.TabIndex = 2; + this.btnSetText.Text = "Set Text"; + this.btnSetText.UseVisualStyleBackColor = true; + this.btnSetText.Click += new System.EventHandler(this.btnSetText_Click); + // + // lblUnicodeText + // + this.lblUnicodeText.AutoSize = true; + this.lblUnicodeText.Location = new System.Drawing.Point(12, 65); + this.lblUnicodeText.Name = "lblUnicodeText"; + this.lblUnicodeText.Size = new System.Drawing.Size(79, 15); + this.lblUnicodeText.TabIndex = 3; + this.lblUnicodeText.Text = "Unicode Text:"; + // + // txtUnicodeText + // + this.txtUnicodeText.Location = new System.Drawing.Point(12, 83); + this.txtUnicodeText.Name = "txtUnicodeText"; + this.txtUnicodeText.Size = new System.Drawing.Size(300, 23); + this.txtUnicodeText.TabIndex = 4; + this.txtUnicodeText.Text = "Unicode text example: ñ, é, ü, 中文"; + // + // btnSetUnicodeText + // + this.btnSetUnicodeText.Location = new System.Drawing.Point(318, 83); + this.btnSetUnicodeText.Name = "btnSetUnicodeText"; + this.btnSetUnicodeText.Size = new System.Drawing.Size(75, 23); + this.btnSetUnicodeText.TabIndex = 5; + this.btnSetUnicodeText.Text = "Set Unicode"; + this.btnSetUnicodeText.UseVisualStyleBackColor = true; + this.btnSetUnicodeText.Click += new System.EventHandler(this.btnSetUnicodeText_Click); + // + // lblRtf + // + this.lblRtf.AutoSize = true; + this.lblRtf.Location = new System.Drawing.Point(12, 115); + this.lblRtf.Name = "lblRtf"; + this.lblRtf.Size = new System.Drawing.Size(29, 15); + this.lblRtf.TabIndex = 6; + this.lblRtf.Text = "RTF:"; + // + // txtRtf + // + this.txtRtf.Location = new System.Drawing.Point(12, 133); + this.txtRtf.Name = "txtRtf"; + this.txtRtf.Size = new System.Drawing.Size(300, 23); + this.txtRtf.TabIndex = 7; + this.txtRtf.Text = "{\\rtf1\\ansi\\deff0 {\\fonttbl {\\f0 Times New Roman;}} \\f0\\fs24 Hello \\b World\\b0 !}"; + // + // btnSetRtf + // + this.btnSetRtf.Location = new System.Drawing.Point(318, 133); + this.btnSetRtf.Name = "btnSetRtf"; + this.btnSetRtf.Size = new System.Drawing.Size(75, 23); + this.btnSetRtf.TabIndex = 8; + this.btnSetRtf.Text = "Set RTF"; + this.btnSetRtf.UseVisualStyleBackColor = true; + this.btnSetRtf.Click += new System.EventHandler(this.btnSetRtf_Click); + // + // lblHtml + // + this.lblHtml.AutoSize = true; + this.lblHtml.Location = new System.Drawing.Point(12, 165); + this.lblHtml.Name = "lblHtml"; + this.lblHtml.Size = new System.Drawing.Size(39, 15); + this.lblHtml.TabIndex = 9; + this.lblHtml.Text = "HTML:"; + // + // txtHtml + // + this.txtHtml.Location = new System.Drawing.Point(12, 183); + this.txtHtml.Name = "txtHtml"; + this.txtHtml.Size = new System.Drawing.Size(300, 23); + this.txtHtml.TabIndex = 10; + this.txtHtml.Text = "Hello World!"; + // + // btnSetHtml + // + this.btnSetHtml.Location = new System.Drawing.Point(318, 183); + this.btnSetHtml.Name = "btnSetHtml"; + this.btnSetHtml.Size = new System.Drawing.Size(75, 23); + this.btnSetHtml.TabIndex = 11; + this.btnSetHtml.Text = "Set HTML"; + this.btnSetHtml.UseVisualStyleBackColor = true; + this.btnSetHtml.Click += new System.EventHandler(this.btnSetHtml_Click); + // + // lblCommaSeparatedValue + // + this.lblCommaSeparatedValue.AutoSize = true; + this.lblCommaSeparatedValue.Location = new System.Drawing.Point(12, 215); + this.lblCommaSeparatedValue.Name = "lblCommaSeparatedValue"; + this.lblCommaSeparatedValue.Size = new System.Drawing.Size(32, 15); + this.lblCommaSeparatedValue.TabIndex = 12; + this.lblCommaSeparatedValue.Text = "CSV:"; + // + // txtCommaSeparatedValue + // + this.txtCommaSeparatedValue.Location = new System.Drawing.Point(12, 233); + this.txtCommaSeparatedValue.Name = "txtCommaSeparatedValue"; + this.txtCommaSeparatedValue.Size = new System.Drawing.Size(300, 23); + this.txtCommaSeparatedValue.TabIndex = 13; + this.txtCommaSeparatedValue.Text = "Name,Age,City\\r\\nJohn,25,\"New York\"\\r\\nJane,30,London"; + // + // btnSetCommaSeparatedValue + // + this.btnSetCommaSeparatedValue.Location = new System.Drawing.Point(318, 233); + this.btnSetCommaSeparatedValue.Name = "btnSetCommaSeparatedValue"; + this.btnSetCommaSeparatedValue.Size = new System.Drawing.Size(75, 23); + this.btnSetCommaSeparatedValue.TabIndex = 14; + this.btnSetCommaSeparatedValue.Text = "Set CSV"; + this.btnSetCommaSeparatedValue.UseVisualStyleBackColor = true; + this.btnSetCommaSeparatedValue.Click += new System.EventHandler(this.btnSetCommaSeparatedValue_Click); + // + // lblOutput + // + this.lblOutput.AutoSize = true; + this.lblOutput.Location = new System.Drawing.Point(12, 275); + this.lblOutput.Name = "lblOutput"; + this.lblOutput.Size = new System.Drawing.Size(101, 15); + this.lblOutput.TabIndex = 15; + this.lblOutput.Text = "Clipboard Output:"; + // + // txtOutput + // + this.txtOutput.Location = new System.Drawing.Point(12, 293); + this.txtOutput.Name = "txtOutput"; + this.txtOutput.ReadOnly = true; + this.txtOutput.ScrollBars = System.Windows.Forms.RichTextBoxScrollBars.Vertical; + this.txtOutput.Size = new System.Drawing.Size(381, 120); + this.txtOutput.TabIndex = 16; + this.txtOutput.Text = ""; + // + // btnGetClipboard + // + this.btnGetClipboard.Location = new System.Drawing.Point(12, 419); + this.btnGetClipboard.Name = "btnGetClipboard"; + this.btnGetClipboard.Size = new System.Drawing.Size(100, 30); + this.btnGetClipboard.TabIndex = 17; + this.btnGetClipboard.Text = "Get Clipboard"; + this.btnGetClipboard.UseVisualStyleBackColor = true; + this.btnGetClipboard.Click += new System.EventHandler(this.btnGetClipboard_Click); + // + // btnClearClipboard + // + this.btnClearClipboard.Location = new System.Drawing.Point(118, 419); + this.btnClearClipboard.Name = "btnClearClipboard"; + this.btnClearClipboard.Size = new System.Drawing.Size(100, 30); + this.btnClearClipboard.TabIndex = 18; + this.btnClearClipboard.Text = "Clear Clipboard"; + this.btnClearClipboard.UseVisualStyleBackColor = true; + this.btnClearClipboard.Click += new System.EventHandler(this.btnClearClipboard_Click); + // + // ClipboardTextTest + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(409, 461); + this.Controls.Add(this.btnClearClipboard); + this.Controls.Add(this.btnGetClipboard); + this.Controls.Add(this.txtOutput); + this.Controls.Add(this.lblOutput); + this.Controls.Add(this.btnSetCommaSeparatedValue); + this.Controls.Add(this.txtCommaSeparatedValue); + this.Controls.Add(this.lblCommaSeparatedValue); + this.Controls.Add(this.btnSetHtml); + this.Controls.Add(this.txtHtml); + this.Controls.Add(this.lblHtml); + this.Controls.Add(this.btnSetRtf); + this.Controls.Add(this.txtRtf); + this.Controls.Add(this.lblRtf); + this.Controls.Add(this.btnSetUnicodeText); + this.Controls.Add(this.txtUnicodeText); + this.Controls.Add(this.lblUnicodeText); + this.Controls.Add(this.btnSetText); + this.Controls.Add(this.txtText); + this.Controls.Add(this.lblText); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.MaximizeBox = false; + this.Name = "ClipboardTextTest"; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; + this.Text = "Clipboard Text Format Test"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label lblText; + private System.Windows.Forms.TextBox txtText; + private System.Windows.Forms.Button btnSetText; + private System.Windows.Forms.Label lblUnicodeText; + private System.Windows.Forms.TextBox txtUnicodeText; + private System.Windows.Forms.Button btnSetUnicodeText; + private System.Windows.Forms.Label lblRtf; + private System.Windows.Forms.TextBox txtRtf; + private System.Windows.Forms.Button btnSetRtf; + private System.Windows.Forms.Label lblHtml; + private System.Windows.Forms.TextBox txtHtml; + private System.Windows.Forms.Button btnSetHtml; + private System.Windows.Forms.Label lblCommaSeparatedValue; + private System.Windows.Forms.TextBox txtCommaSeparatedValue; + private System.Windows.Forms.Button btnSetCommaSeparatedValue; + private System.Windows.Forms.Label lblOutput; + private System.Windows.Forms.RichTextBox txtOutput; + private System.Windows.Forms.Button btnGetClipboard; + private System.Windows.Forms.Button btnClearClipboard; + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.cs new file mode 100644 index 0000000000..b4cc65d13e --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.cs @@ -0,0 +1,105 @@ +using System; +using System.Windows.Forms; + +namespace ClipboardExample +{ + public partial class ClipboardTextTest : Form + { + public ClipboardTextTest() + { + InitializeComponent(); + } + + private void btnSetText_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtText.Text)) + { + Clipboard.SetText(txtText.Text, TextDataFormat.Text); + } + } + + private void btnSetUnicodeText_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtUnicodeText.Text)) + { + Clipboard.SetText(txtUnicodeText.Text, TextDataFormat.UnicodeText); + } + } + + private void btnSetRtf_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtRtf.Text)) + { + Clipboard.SetText(txtRtf.Text, TextDataFormat.Rtf); + } + } + + private void btnSetHtml_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtHtml.Text)) + { + Clipboard.SetText(txtHtml.Text, TextDataFormat.Html); + } + } + + private void btnSetCommaSeparatedValue_Click(object sender, EventArgs e) + { + if (!string.IsNullOrEmpty(txtCommaSeparatedValue.Text)) + { + Clipboard.SetText(txtCommaSeparatedValue.Text, TextDataFormat.CommaSeparatedValue); + } + } + + private void btnGetClipboard_Click(object sender, EventArgs e) + { + txtOutput.Clear(); + + // Check if RTF is available first and display it formatted + if (Clipboard.ContainsText(TextDataFormat.Rtf)) + { + string rtfData = Clipboard.GetText(TextDataFormat.Rtf); + txtOutput.AppendText("RTF (formatted): "); + + // Store current selection position + int selectionStart = txtOutput.TextLength; + txtOutput.AppendText("\n"); + + // Insert the RTF content with formatting + int rtfStart = txtOutput.TextLength; + txtOutput.SelectedRtf = rtfData; + txtOutput.AppendText("\n\nRTF (raw): " + rtfData + "\n\n"); + } + + if (Clipboard.ContainsText(TextDataFormat.Text)) + { + txtOutput.AppendText("Text: " + Clipboard.GetText(TextDataFormat.Text) + "\n"); + } + + if (Clipboard.ContainsText(TextDataFormat.UnicodeText)) + { + txtOutput.AppendText("UnicodeText: " + Clipboard.GetText(TextDataFormat.UnicodeText) + "\n"); + } + + if (Clipboard.ContainsText(TextDataFormat.Html)) + { + txtOutput.AppendText("Html: " + Clipboard.GetText(TextDataFormat.Html) + "\n"); + } + + if (Clipboard.ContainsText(TextDataFormat.CommaSeparatedValue)) + { + txtOutput.AppendText("CommaSeparatedValue: " + Clipboard.GetText(TextDataFormat.CommaSeparatedValue) + "\n"); + } + + if (txtOutput.Text.Length == 0) + { + txtOutput.Text = "No text data found in clipboard."; + } + } + + private void btnClearClipboard_Click(object sender, EventArgs e) + { + Clipboard.Clear(); + txtOutput.Text = "Clipboard cleared."; + } + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.resx new file mode 100644 index 0000000000..83e41b1c81 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/ClipboardTextTest.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.Designer.cs new file mode 100644 index 0000000000..87281239ea --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.Designer.cs @@ -0,0 +1,65 @@ +namespace ClipboardExample +{ + partial class FileDropClipboardTest + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// The main text box control for displaying clipboard file information. + /// + private TextBox textBox; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.textBox = new TextBox(); + this.SuspendLayout(); + + // + // textBox + // + this.textBox.Location = new Point(12, 12); + this.textBox.Multiline = true; + this.textBox.Name = "textBox"; + this.textBox.ScrollBars = ScrollBars.Vertical; + this.textBox.Size = new Size(560, 437); + this.textBox.TabIndex = 0; + this.textBox.KeyDown += new KeyEventHandler(this.textBox_KeyDown); + + // + // FileDropClipboardTest + // + this.AutoScaleDimensions = new SizeF(7F, 15F); + this.AutoScaleMode = AutoScaleMode.Font; + this.ClientSize = new Size(584, 461); + this.Controls.Add(this.textBox); + this.Name = "FileDropClipboardTest"; + this.Text = "File Drop Clipboard Test"; + this.ResumeLayout(false); + this.PerformLayout(); + } + + #endregion + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.cs new file mode 100644 index 0000000000..527174e904 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.cs @@ -0,0 +1,82 @@ +using System.Collections.Specialized; + +namespace ClipboardExample; + +public partial class FileDropClipboardTest : Form +{ + public FileDropClipboardTest() + { + InitializeComponent(); + } + + private void textBox_KeyDown(object sender, KeyEventArgs e) + { + // Check for Ctrl+V key combination + if (e.Control && e.KeyCode == Keys.V) + { + // Prevent the default paste behavior + e.Handled = true; + + // Handle the clipboard file drop list + HandleClipboardFileDropList(); + } + } + + private void HandleClipboardFileDropList() + { + try + { + // Check if clipboard contains file drop list + if (Clipboard.ContainsFileDropList()) + { + // Get the file drop list from clipboard + StringCollection files = Clipboard.GetFileDropList(); + + if (files != null && files.Count > 0) + { + // Clear existing text and add file names + textBox.Clear(); + textBox.AppendText("Files from clipboard:" + Environment.NewLine); + textBox.AppendText(new string('-', 30) + Environment.NewLine); + + foreach (string file in files) + { + textBox.AppendText(file + Environment.NewLine); + } + + textBox.AppendText(Environment.NewLine + $"Total files: {files.Count}"); + } + else + { + textBox.Text = "Clipboard contains file drop list but no files found."; + } + } + else + { + // Check what other data formats are available + textBox.Clear(); + textBox.AppendText("No file drop list found in clipboard." + Environment.NewLine); + textBox.AppendText("Available clipboard formats:" + Environment.NewLine); + textBox.AppendText(new string('-', 30) + Environment.NewLine); + + IDataObject dataObject = Clipboard.GetDataObject(); + if (dataObject != null) + { + string[] formats = dataObject.GetFormats(); + foreach (string format in formats) + { + textBox.AppendText($"- {format}" + Environment.NewLine); + } + } + else + { + textBox.AppendText("Clipboard is empty or inaccessible."); + } + } + } + catch (Exception ex) + { + textBox.Text = $"Error accessing clipboard: {ex.Message}"; + } + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/FileDropClipboardTest.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.Designer.cs new file mode 100644 index 0000000000..b380e67a72 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.Designer.cs @@ -0,0 +1,44 @@ +namespace ClipboardExample; + +partial class Form1 +{ + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + SuspendLayout(); + // + // Form1 + // + AutoScaleDimensions = new SizeF(7F, 15F); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 250); + Name = "Form1"; + Text = "Clipboard Example Tester"; + ResumeLayout(false); + } + + #endregion +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs new file mode 100644 index 0000000000..6b6ae0adc7 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.cs @@ -0,0 +1,140 @@ +using System.Collections.Specialized; + +namespace ClipboardExample; + +public partial class Form1 : Form +{ + public Form1() + { + InitializeComponent(); + // + Clipboard.Clear(); + // + } + + // + // Customer class used in custom clipboard format examples. + public class Customer + { + public string Name { get; set; } + + public Customer(string name) + { + Name = name; + } + } + // + + // + // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. + public Stream SwapClipboardAudio(Stream replacementAudioStream) + { + Stream? returnAudioStream = null; + + if (Clipboard.ContainsAudio()) + { + returnAudioStream = Clipboard.GetAudioStream(); + Clipboard.SetAudio(replacementAudioStream); + } + return returnAudioStream; + } + + // Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList + public StringCollection SwapClipboardFileDropList(StringCollection replacementList) + { + StringCollection? returnList = null; + + if (Clipboard.ContainsFileDropList()) + { + returnList = Clipboard.GetFileDropList(); + Clipboard.SetFileDropList(replacementList); + } + return returnList; + } + + // Demonstrates SetImage, ContainsImage, and GetImage. + public Image SwapClipboardImage(Image replacementImage) + { + Image? returnImage = null; + + if (Clipboard.ContainsImage()) + { + returnImage = Clipboard.GetImage(); + Clipboard.SetImage(replacementImage); + } + return returnImage; + } + + // Demonstrates SetText, ContainsText, and GetText. + public string SwapClipboardHtmlText(string replacementHtmlText) + { + string? returnHtmlText = null; + + if (Clipboard.ContainsText(TextDataFormat.Html)) + { + returnHtmlText = Clipboard.GetText(TextDataFormat.Html); + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html); + } + return returnHtmlText; + } + // + + // + // Demonstrates SetDataAsJson, ContainsData, and GetData + // using a custom format name and a business object. + public Customer TestCustomFormat + { + get + { + Clipboard.SetDataAsJson("CustomerFormat", new Customer("Customer Name")); + if (Clipboard.ContainsData("CustomerFormat")) + { + if (Clipboard.TryGetData("CustomerFormat", out Customer customerData)) + return customerData; + } + + return null; + } + } + // + + // + // Demonstrates how to use a DataObject to add + // data to the Clipboard in multiple formats. + public void TestClipboardMultipleFormats() + { + DataObject data = new(); + + Customer customer = new("Customer #2112"); + ListViewItem listViewItem = new($"Customer as ListViewItem {customer.Name}"); + + // Add a Customer object using the type as the format. + data.SetDataAsJson(customer); + + // Add a ListViewItem object using a custom format name. + data.SetDataAsJson("ListViewItemFormat", listViewItem.Text); + + Clipboard.SetDataObject(data); + + // Retrieve the data from the Clipboard. + DataObject retrievedData = (DataObject)Clipboard.GetDataObject()!; + + if (retrievedData.GetDataPresent("ListViewItemFormat")) + { + if (retrievedData.TryGetData("ListViewItemFormat", out String item)) + { + ListViewItem recreatedListViewItem = new(item); + MessageBox.Show($"Data contains ListViewItem with text of {recreatedListViewItem.Text}"); + } + } + + if (retrievedData.GetDataPresent(typeof(Customer))) + { + if (retrievedData.TryGetData(out Customer newCustomer)) + { + MessageBox.Show($"Data contains Customer with name of {newCustomer.Name}"); + } + } + } + // +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.resx new file mode 100644 index 0000000000..8b2ff64a11 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Form1.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Program.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Program.cs new file mode 100644 index 0000000000..3af3751c9e --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Program.cs @@ -0,0 +1,24 @@ +namespace ClipboardExample; + +static class Program +{ + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + + // Run the Multiple Formats Clipboard Test form + Application.Run(new ClipboardMultipleFormatsTest()); + + // Alternative forms available: + // Application.Run(new ClipboardTextTest()); + // Application.Run(new FileDropClipboardTest()); + // Application.Run(new Form1()); + // Application.Run(new ClipboardOperations.ClipboardImageTest()); + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..c21825c756 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.Designer.cs @@ -0,0 +1,63 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace ClipboardOperations.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "18.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ClipboardOperations.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.resx b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/Properties/Resources.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image1.png b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image1.png new file mode 100644 index 0000000000000000000000000000000000000000..f0f92ebe9f0df8f3a3b2461ee2d0b727a570a984 GIT binary patch literal 5872 zcmZ`-2{4s!xc`>3bL>m@lO!csLbmid*_V|2e*Zsx#=mrt*tF)YxlMV0A*;*-L0){Q3-^Tb%n4sDiX`nWuhT!JUMgZ<-tpR z7;>=M1CvCY&Kj8v~sl%*s`p=v(li`>u>riH2@ zHYvw(hT#}P{ttkWGkM2A%EP*e1$8o|O$#UuQeYBlGC0h4AE1sNK*i0UJ_-51va$}8h|tZJmu`P5Y;TBQIWm(wQ7!6-Ap{ZuLqLa!H)wpXu%R6 z#ant^iw@CWvdKujS;SKz*BIhySK?QG_Kc|zMCsdX3TSly*(lak{sZK?AF}}5>vFr( z5Jvq4=5S!!1(fu9otOH+QxxKmR*R7*f#x&KL2x?rin#hm^(OMgw8RO?7e;W(agi%%%yH|x%uk+@%v{b1|KgM05d3cpSS{5@9*fkBJklj zJ<8(jpO@>^^b&$cXC?It=g@k{en3@JcNf73o~v?Az@2*qJZdaS(PX@g;r7+tX*Fes z?~aQ{srTN*o+35}{~+~fJ8-6CMQ!|60}7zGRZ^fe_ZgH{-bzQ1v0^3EQxtzq1mG*N;OE&gdj0ycRwg=a&=4^$uv0V$caY z+v3TIPyM>*?dCQ_0=@lGT^SD{t&swelq)V#uHS>NVJLDuwkg+PS;U3L$vX0z?Rqkh zSQ39)@e9}Hmx+mq*5tv#t;#C*w+&$cPI*z#1Tyb6R4)$01^R@BZaRDP4j<}yH;&j? zpw_!SgO8vK3%`=8rn;NZ$!@!#>b->_sGy*=`ZCw%#_y4a<<;85L6r>;f?%P0?z9WG zY#!qRoIT9$LxWrOYv1R;)dqO0_%Jt=rLi*BjVazgxX{VpkJ#qlYS-cYzL0Mvd$-}f z$fYZ@W{z4tbY^6pB1<_OVS6Q6gd@3E3F8Vs3m00bm`^SDtskz~u(ry)?5BDj9g(Jm zRiFdNVr{^B-P=$B>D0^{4~Hhbd|~5Zg5oc(Y8+L&ZY$_|^@c3BwG+3K83Is#kQ zohEB3G9TKqrJon&;`+-kN{;bp_n^b4wf^qA&4 zFwhoO`F?YO35}s83D6TLv!S*aQ+7bm+wxd%mK({y%77OgxBV+WhGsn)4c=H=dac?Q z1S>_&+!gD*anZa*VXG1N{b%K?<$Vdov&_^@&6*hYU76E&e+o+AeG$CWX_ZWo4(67Z zKA<{aI2!dSc{ZeZ>?Z4@YV5TWBJbB~5&*v_^h*z0Azkx~7uiNu?j2hpS0e>cw6EB` z;V^)b{NahO0KX}85uof8&d6R;IgXsR!|+jw6?U@2KwfO2j1C#KBNx`7d?We^>#^uX zmm&uF#3u{TsIWNfl%g!IPa*BTqDUA?Diq(M!UGyPS|yBHl4I0Nc|W)_&VVZdT<@Q& z(r=+uAGU?b5ad0YouCX>x>Itlc-y)ml_Ffw07`!j2}chj*|)>^XlAhjH0SNetTRKm zN)MPz21Lk-?#L|GRia6W;JLTT^MNip^6CJ)<7X|p{uPe*Uv{$39Y!3TZM^~lq`66v zCR&`P`iiQvA#Gl^?eS_>hN6NDTQ*GwypIuEPrvCV>IwJ^PF2Dr%q~#O{6^1W<1ysK z&O*%Dv+4}0N~muro>c$jKHP*DKBb>mCaKX3Bx7s<{KlN2LL%kobx?!Bb&)NBeCs5c z=*8roRq#jfKV9tpDaZdgi#zVELYvVUwbouDQ8_^HzWxylY}u=o+wY#@4u?fZAUj@s z&$*#>F{^;@kN8vh__h?1rgP4**t>bn=i-}#A8feY+h|y-QD57l)WF3ZW7nw1RGBja zmqB-Q-^Vey=Tln(cF1TRcD$Hbb^8Fm+@Y=Z9Fx4*7xZQ@cw4TMkj#7VGq70UhB$#R zTm~TpBDqsqjVITv%qpe;ZUYZN^Ij#|e#*)5AJdBnf)Cln3S2)9idb}Zpccs7eH&Mb zNm?+1*isa)k{A*GN>S0Scz~C6d7|#YTFn8lke%Dp3X|7QmJ%8=MdUp#WuarR;~_b2 ziPbEDSmpAf0L=bSj#I6i4aIX-kKJj~3_=&ENIHL4)B*KU8hdlp7}(b*JmS}70OVgf zw#ePv9YWyyqaAqzH;^&uj(T5!CyK*_JvEM%dXT^YhrzTAx7ON|$!l%07M)%7uWJ>` zp`KZFmg{|t>(ol-?rO8cH;F%|3}S*r8GWznxfPza1L5G)AJz9eG{8d2Let!vSEa=U z@I_kUK^r}$6J{Yyi1r|mlBq=I6Y*PI7AE*QA*5^sPLA+9oRkRKJ4lG6K)OY^13&Dr zw${uaztgW*>=A#L2WEfNg~iSc0rkp^3OQb%kqlC>-~swOR9;`$@gXX^&+&RyK&yuL zE`uHDb-@9PJR0_L^2X}fUyTCnI~Lg<+z7k$8STId4ZXg}upfVwdNR5_I4t2B@soF5 zTme(kMZ~__GwI;6=dfOQN9MfUVo|!8szKK*6b?I&HMRmDKi2>H7`vafld%`%H@dVDua63C zDqGZO93|%=Uwlo^sN*%nb?C}Nr}ieUHt9m40pnokA7wy^Ko2$mvK1MXIF7bNe6h;n z!yir!=Ph8JdvE$*IVZ5z1pJVu`@D;=0xu>pQL6hH$mG<;#*hg7h! z6?P!M_QB^>k$R*k`!%>FHMyx++D|N(mISz?PIovmq)S@VR?7k&b0#v>jiIae{KXO5 z-Xa%FV5Y*`w$cG65bP&_^eKq(enojq=l2NT@t0f;oabNKq@vPYU8RG_ZD$t$So`y_ zztPiiV6s6SZoa0hlf4py~C}_rWu3zRPoEM>8z}Ij5>c0>D5!QU6&72C5 z6q0@*FW@Vg9BcBCZMshGn@fNsWTCW5(JSRPnOM$MB*vHkJeT)Ka_-p=xWM7zvk+Rl zYsnGmH8j@{VN}fMY8P|jO^b}0;`*6`f}nEt^{4EO2O%4O$^2Wr?tyk{hYK^xLOhh9mmim$>$66Dz&1BA zXJA2J$?nn|UZ)Jhuey_;B7XoPl(=J)b$@mMyYJ{%+>%l1=Om}Sj&?GPkIc`)r$2E< zF8NEQh~EyQ$H%st?p^q0o-d@=YHYV}$M#eW-!z4DNHSmF7&A>}OPu_e{K}thd=B&a zEW5``!N*ZYG0zq#C}qmO3anY>0t)y38L zn~{1ez#*~DJ(Yubl~=V?tbCcNUIyp#5(WDT>-h#l`oAK?6EPLtpK1d2$9w01>F9fW zP1vSq?HxO~xu(I`smDfeXZ`ZNiy3IRQMlGJY4DQ2o(rm<>!E91QlE+)0`~5SP^Xwy z^xq`cf;n&=3r!;yy5JJ)ag=7@)Gca;1>AOfkcm-F@aVS%yD?92j$R3;ORB)e+puv` zvf{VsuY6sBIEI^$XAl=_z=eVF0vT?bqHnM`3=^mJ0GoO|NybZ@;U>%#j(qkcXXIw8 zvMH#NJ&{O=>jz*)h4T_o>6<^U3WSf$>qcp+r5YoM5AYal*La5ciH)+JMo6xxj3zg` zroqwj$8b1Bs>0(L6))4pC54PAu$CQBlS|ej?kL$ah+xT9Xwt0zZDb10A+ZssRh&yEF0Joi*?RRI}Raet)rhxe+S7ctr2z+Xubbs`xcGogXK$i|LXrXi(wfL!U^DSVQJO zWTQnfWF;+&ZWL!2!phX+P!9&d_1Rcza2eNnV6Karxy;gzRN8oz3y^v-N&k_k@wmK``6Z7VrsoFLjN+` zV?mFL_M+1L;J7hLq@TjR4ALb_YC9zGqw1)AgQgtmNH#1ic*QS0u-r7fMysc<+R&>lGH*kA;%|*4+_TBSuz$W`BH44-YEzWboJ5nZD7gYW zkeWP3W90*FyujUPumGIf7qJIS`*WXOV9%Ak7wNvtR|=9o;ApDqEzYVNE9Vn+5$R+`_zfOpfT&cde5YHqGP|lspC=90;t?YV&0tJ?W1$GlH@qVK>^>oH*p2# z5k~|-gA77}CU;*?%|tAnvE0ourfmFW2M@=hA8T-?B8e~S%Jr?Z53yg9}{rP;JAV!a~dznCyz z`Y_6Z#`#l!+otlRzv(=pc969-RQrmr)ous-E6GDcB7qHc%%;&T_c&S0V#)~JAqD*_ z?C`Cv=LqL%{?no|K-#_ZuX>gqb$PgulI%l@JEJovbMt-p#}nJVop;ich|V%`w?BaIfvOiSz0W>e&&MUs zrUT#k&E57QZHaD=rfu%zRpTAOl#nVPhy#85>qOCRW41A4W9AxrXMU{{_^=z4bA2)B zPPjH+qP&|?m3kf@Oqt&u|1CX(zdUMDdR->+M~|E>hSjOa>^pG;f6SEVReoXQ7pq~k*-6q+IXno;SpPx3I%a;&8By`&3Tt%VM=OxpcM^k+& zfE)9tb^BeV)X8MHr{$p%)x_ax@CyN&cz70CdKMTfycK+HV0qTq+DeZ44A3Wd?2hED zT)en*zaQKe(HUmU({>PEO)wlV{vr146wmVu?3ZN=aFlCy+ng?b{5S3YsrcrlXpUF_ zpvaJlDUjsG=9sUiV&@2=K5@kQT}{#v#TB0!#{Eb7Mu`h0rab%V4(`l;H}4 puq0gu5(aV0m@^OziSPe)N!2os`@1v!HvZXJ8|fX>Ev3@J{{t;P6`%kB literal 0 HcmV?d00001 diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image2.png b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/csharp/image2.png new file mode 100644 index 0000000000000000000000000000000000000000..b36c430e657dc64cd98475da77909b782c44ddb4 GIT binary patch literal 4835 zcmbVQc|4Te+rRI7Hp7@?Y>80WWhYzQktK;y3Q0{7E%r4`+#->(m6D2yct)!vA(@+G zYt)FchsPRO3fady&+~i#dH?%;-gB;V&UJmy_d1{Je6I7y`CLg90PSRoi_Aj1DDX68FECuWAid#v!s>;2bv z{|EgK=U*a-rS8!Ko#^#Dgr8ENbGWfH6KG8l$ia< z2QhtgFcad4?+Lg7dOOQfqtF)z3J44xUklN!sS=H zzZ+k-4W3hUlZqA&cO|U-Sge$w38I5{Dwfjz=7_E}Bb`@(IE=d4qsIBxs5{#kGohQ& zSt8X$)RLu#-s^gUF&Yd7EcliFF7jO&zf^A3Jcj&u4oMtB8x;Vjn0W={(;Hy^ojRC^ zQ3J4U^OPe?BR~tE0V%qBWzl~7fO`qDJ9!7gi61q*_t+C`u|`#X;;OcQH*5Tj8C$@% z8h;(e<^a>BOfax$bAZ;8C>SWDd3V?ObT4r4UevP;Xg85v+jbH=-vv<>5hF}|F8ww3 z`UNp$0x8GE9ba?1vM&`ex-YF_yaoY*R!9yxIv9o?lbs3HOCa^-n_Sb!lF^60-oB0) zNNJV{yHu~23Wm~!?xi9^7uevt%=yLf#nrCMp=29W((W5(yULG8nanGiE3O2Vp)44O zF@62uweTdUy5veQgFY=1Iacr__yk~y!cc+;&v-R>IX8464!O&`1$FbC1=@uMydB&@ zPp8X5fG<|pPEXeg{T(R_)XzMygqJoK>rRRw!TMK3!Q{!>4ZzdMh|tIkA*VSO0WOKQ z*KIA)Ag9w#lI_~a2(ylfEtR4fs%WXyut7ag&05|{UMCdpZS_CQO1{a5!qcBV<>SRNQ9!wF+aH8abKF0y$wOn-`IN5a9l9mQXiR7B#L`!rVwpQ{ z{_1ljO?t-cH*- zbds10*Wlyiu-=-E&Ukqk3*Z60n8jK?#^?+UOPvcRf#6A4@NM}j`o@|&P6;Md$8b~VQ11t+ zf!vn&2JH^ zV-a>IWPWifdTG)JP*KT5_Q8o8o1LK-f{A%w)Jriu;;eXs9Qvn5Ebq`tUpgSoSA1!S zvrpSC5`=tmS!;r@Wq}rNIP!)*LpoC=GaH#=K4OZr+wqVUCLk_Q{12LU5<1S0hB+N_ zx-1V`eH`u(<$;NgO?ykPM_cD*HL|L_eB@WWa{4F-IG{c{^P8ZFzv@~-lN3xGE$kJQS)f|?RTc9 z<~ig+6y8+IMM};Fp1}PTc`~gMT3UQ$dMHlw^Oqr(g-GU(PqIufO zK628|gD-tB5j3luiQB);db!ihccfm;N)?x}?gh5?2sTjAZmyp{tHB`Spi58x9&GPY z&gPVE?lh4W^WlwY<_(<}lAPp4*dCI4JK zrLWIB=o7d+Cg=4APmftOJ~I?Sv~y~XI4J6 zG-^Q6wgfMmC9Uos4Zm-n1pQd!D-FLQ5Y<&Z7S#J@SQ$N;8Z+*UG~<@sEI~2a|B5i6 zjL&{{PnOHG!U5Jomg z&*o>uQus_1lng%Rw9$PBcTXmT0yzXaz@SMXr2DdJG91RS;PswKfoH zAJgD+=?f&Wa4uH6^5S5qp;UIGN!LU9!ARHM+a_c2`)hyO;;Dc~ zLP={sKrR)KeUHn9CKQ1L34tX;S;)4;q^0hmIwHr_LINjSUFRbRWF<4e6N5A$Uxp6@ zM0e{burq6lUkT5cLY8~t96%A2;j<>i;dE^SO15xDF1*u#S0!LPX-$;#9MNo(Ryj0Q z2~<9ylLls$&3B{K-~_5=&%_i(c_C8^xJDU_4IBm9j7ypbG)rkZy;&hZ{4}5Y$VtmQ z6>^psA|V{`gut+d$m5s5Wl*-z=JVs#eXg83h7sud#0(OdkM=-YTjo_|F{fbPqgN@d zDse3wd-NHXFD-Gr9ti<=hAgCHe?5|@oiB|fR^9UrjpR!-hMKV=ddbT3RnB1L2K}h( zebo(a2l&=G+x6QEX@jGL?sZ`9*)}f-4XGpf0OpNP)F-6e&%myB>tj&y-44SEyev5M zSdHfVZu0UxmaC#tyvT>mPy^M{)5@2?rElMbMNSM2F9*BOm6)MtAkGq_Gi zWumxaCDcvb8loR)aE9cXUId3gg^gO z3m@rlMCf7ChdmF>>cOCTSyj*1SH01ADuS0)0Po)2kuv?^jw2%FvugTX|xg47L2srZ_Wbq7ZoV& z$vKNyS*Dr$WB;}a8QwR1DhFvQ^Ui-MEdkr!FdYfoTkAv`I{vGI;j9ylr{&%)`7oj8 z`PazlY@6FBjiB@~$7YeN-FT^{uut1*t*_5a5Ib8)ecSm?%C*ef06J|I&Gp6{_SOy` zWTX(e<)eBNX9JXAS|s`|cbcaZM?KAGR;cynz*gbAdlD zU$b`=L7m5xgFadA0rvZCGU(1uct|wh$Uv29oZd4h%Wpks%zIT=_Xa1W*puEx9}?gI zm#~dUpt?hlULPnA1ct-Mc(FH2}7z}aAX%vo6Sb*Jo zs;QOS#Taxm;=ZL4)Ml7r+q-Jw{esnP_g3#3Fz8BQk8X89W4TrYl~mvsQOW*`AIV1X zo_7hx=mu9PU>`w%rX^m`)CZn{YMK7XsRau-Tbh)0Xow?feQptV>t>5iu7y4fedjq# zbnLHLg@Q`<;5`}ZB&ru-Q^<`9CES7qU_1}mjGJMG%QM1Hv*iv5jW6P)c%DmJ`@t<7 zf8=+-o<7myk!sOMH`u6aoHzi-kUAaEL1c%K3(~4cTZ!hQv4F@+KaqGZ{WKM%?r&k1 zu;y4Amxz>fZa+LEsCjYr0%8NVy@i5`pRu3f?e(dwG0Q~XL{2qy|l#$0z=$G^IecmH*hA~xp_n3=`){#O}rFc z-c>>jcKy?T&>Faw&!*sYMLsNnG`D-oujb!|(f%Cpa%qjQ{5;BOQ|+j-r}}|5+Mpuw zRcNJ#Y;u>p&cQ+n#ls4xm%SB;&0)65Npy(8#d36~<`%RV&nF*ux`Q`&C6Nz*G)h+R zza5-3NP!pFTis@QV(DP1=>7t=C*`0)a6Mc8YGCsXP-nt8lfM`c_%B5WxAfj+b+sDL z?klwdKQ(IPb*K}Zao>@B-f zBucS@>@91`dEC+-&*&$5n;2TeN`MBo-(0gV{$%BwBA{uZ`>mzO`?MPScIw4Q1xZ(M z`en7zVX5?k9oqKcH)^<<3Am+=B#5nqLTdjHflKSRgqY;RXB$5LI%^C(9~0E}PzCQf-Duizn zhWJy(~^4ltm%jy z(k*31zn?LVjcTq6dH*@eSpS5)WrS642eIchylz3mV&R`k`A;O>8*k*F6|NIOU}JF0Pn`LV7(=yKh%SW1 z((;G8pa8LPAq8jCSsv%W;|HvpLFkdj)Z$eB*}Vu6wiAoLcm{cg(n>G7ZoKN@pN-hJ zl^dr7L*fH7;y4%Nzmz|Ubu*-;7c4Ha%@m;9K z`v5b(5_e50I`%%D!PnM9mg4ZLNwTDpnDbHeV(ouQOaC^5o92Q&p>FR9|5*Di?e{%5 Hr(OOZ6-{G( literal 0 HcmV?d00001 diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/ClipboardOperations.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/ClipboardOperations.vbproj new file mode 100644 index 0000000000..7972313c2d --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/ClipboardOperations.vbproj @@ -0,0 +1,17 @@ + + + + WinExe + net10.0-windows + ClipboardExample + Sub Main + true + + + + + + + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.Designer.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.Designer.vb new file mode 100644 index 0000000000..0a21f031de --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.Designer.vb @@ -0,0 +1,31 @@ + +Partial Class Form1 + Inherits System.Windows.Forms.Form + + 'Form overrides dispose to clean up the component list. + + Protected Overrides Sub Dispose(disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + + Private Sub InitializeComponent() + components = New System.ComponentModel.Container() + AutoScaleMode = AutoScaleMode.Font + ClientSize = New Size(800, 450) + Text = "Form1" + End Sub + +End Class diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb new file mode 100644 index 0000000000..8d8060a141 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb @@ -0,0 +1,146 @@ +Imports System.Collections.Specialized +Imports System.IO + +Public Class Form1 + + Public Sub New() + InitializeComponent() + ' + Clipboard.Clear() + ' + End Sub + + ' + 'Customer class used in custom clipboard format examples. + Public Class Customer + + Public Property Name As String + + Public Sub New(ByVal name As String) + Me.Name = name + End Sub + + End Class + ' + + ' + ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. + Public Function SwapClipboardAudio( + ByVal replacementAudioStream As Stream) As Stream + + Dim returnAudioStream As Stream = Nothing + + If Clipboard.ContainsAudio() Then + returnAudioStream = Clipboard.GetAudioStream() + Clipboard.SetAudio(replacementAudioStream) + End If + + Return returnAudioStream + + End Function + + ' Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList + Public Function SwapClipboardFileDropList(ByVal replacementList As StringCollection) As StringCollection + + Dim returnList As StringCollection = Nothing + + If Clipboard.ContainsFileDropList() Then + returnList = Clipboard.GetFileDropList() + Clipboard.SetFileDropList(replacementList) + End If + + Return returnList + + End Function + + ' Demonstrates SetImage, ContainsImage, and GetImage. + Public Function SwapClipboardImage( + ByVal replacementImage As Image) As Image + + Dim returnImage As Image = Nothing + + If Clipboard.ContainsImage() Then + returnImage = Clipboard.GetImage() + Clipboard.SetImage(replacementImage) + End If + + Return returnImage + End Function + + ' Demonstrates SetText, ContainsText, and GetText. + Public Function SwapClipboardHtmlText( + ByVal replacementHtmlText As String) As String + + Dim returnHtmlText As String = Nothing + + If Clipboard.ContainsText(TextDataFormat.Html) Then + returnHtmlText = Clipboard.GetText(TextDataFormat.Html) + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html) + End If + + Return returnHtmlText + + End Function + ' + + ' + ' Demonstrates SetDataAsJson, ContainsData, and GetData + ' using a custom format name and a business object. + Public ReadOnly Property TestCustomFormat() As Customer + Get + Clipboard.SetDataAsJson("CustomerFormat", New Customer("Customer Name")) + + If Clipboard.ContainsData("CustomerFormat") Then + Dim customerData As Customer = Nothing + + If Clipboard.TryGetData("CustomerFormat", customerData) Then + Return customerData + End If + + End If + + Return Nothing + End Get + End Property + ' + + ' + ' Demonstrates how to use a DataObject to add + ' data to the Clipboard in multiple formats. + Public Sub TestClipboardMultipleFormats() + + Dim data As New DataObject() + + Dim customer As New Customer("Customer #2112") + Dim listViewItem As New ListViewItem($"Customer as ListViewItem {customer.Name}") + + ' Add a Customer object using the type as the format. + data.SetDataAsJson(customer) + + ' Add a ListViewItem object using a custom format name. + data.SetDataAsJson("ListViewItemFormat", listViewItem.Text) + + Clipboard.SetDataObject(data) + + ' Retrieve the data from the Clipboard. + Dim retrievedData As DataObject = CType(Clipboard.GetDataObject(), DataObject) + + If retrievedData.GetDataPresent("ListViewItemFormat") Then + Dim item As String = Nothing + If retrievedData.TryGetData("ListViewItemFormat", item) Then + Dim recreatedListViewItem As New ListViewItem(item) + MessageBox.Show($"Data contains ListViewItem with text of {recreatedListViewItem.Text}") + End If + End If + + If retrievedData.GetDataPresent(GetType(Customer)) Then + Dim newCustomer As Customer = Nothing + If retrievedData.TryGetData(newCustomer) Then + MessageBox.Show($"Data contains Customer with name of {newCustomer.Name}") + End If + End If + + End Sub + ' + +End Class diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Program.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Program.vb new file mode 100644 index 0000000000..236767207e --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Program.vb @@ -0,0 +1,11 @@ +Friend Module Program + + + Friend Sub Main(args As String()) + Application.SetHighDpiMode(HighDpiMode.SystemAware) + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New Form1) + End Sub + +End Module diff --git a/dotnet-desktop-guide/zone-pivot-groups.yml b/dotnet-desktop-guide/zone-pivot-groups.yml new file mode 100644 index 0000000000..3678e6d1b6 --- /dev/null +++ b/dotnet-desktop-guide/zone-pivot-groups.yml @@ -0,0 +1,11 @@ +### YamlMime:ZonePivotGroups + +groups: + - id: dotnet-version + title: .NET Version + prompt: Choose your .NET version + pivots: + - id: dotnet + title: .NET + - id: dotnetframework + title: .NET Framework \ No newline at end of file From ada3e3c9c497c5478877c2dc63a7686db11ed688 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 09:21:45 -0700 Subject: [PATCH 29/51] Phase 2.2 Completed --- ...and-drop-operations-and-clipboard-support.md | 4 ++-- .../how-to-add-data-to-the-clipboard.md | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md b/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md index 1c72264798..69d6928d20 100644 --- a/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md +++ b/dotnet-desktop-guide/winforms/advanced/drag-and-drop-operations-and-clipboard-support.md @@ -2,8 +2,8 @@ title: "Drag-and-Drop Operations and Clipboard Support" description: Learn how to enable user drag-and-drop operations and clipboard support within Windows Forms applications, including the new type-safe APIs introduced in .NET 10. ms.date: "09/26/2025" -ms.service: dotnet-framework -ms.update-cycle: 1825-days +ms.service: dotnet-desktop +ms.update-cycle: 365-days helpviewer_keywords: - "drag and drop [Windows Forms]" - "drag and drop [Windows Forms], Windows Forms" diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md index 73a93bfd91..0fc20dcb64 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md @@ -1,8 +1,8 @@ --- title: "How to: Add Data to the Clipboard" ms.date: 10/02/2025 -ms.service: dotnet-framework -ms.update-cycle: 1825-days +ms.service: dotnet-desktop +ms.update-cycle: 365-days zone_pivot_groups: dotnet-version dev_langs: - "csharp" @@ -12,21 +12,22 @@ helpviewer_keywords: - "data [Windows Forms], copying to Clipboard" ms.assetid: 25152454-0e78-40a9-8a9e-a2a5a274e517 description: Learn how to add data to the clipboard within many applications and transfer that data from one application to another. +ai-usage: ai-assisted --- -# How to: Add Data to the Clipboard +# How to add data to the Clipboard -The class provides methods that you can use to interact with the Windows operating system Clipboard feature. Many applications use the Clipboard as a temporary repository for data. For example, word processors use the Clipboard during cut-and-paste operations. The Clipboard is also useful for transferring data from one application to another. +The class provides methods that interact with the Windows operating system Clipboard feature. Many applications use the Clipboard as a temporary repository for data. For example, word processors use the Clipboard during cut-and-paste operations. The Clipboard also transfers data from one application to another. -When you add data to the Clipboard, you can indicate the data format so that other applications can recognize the data if they can use that format. You can also add data to the Clipboard in multiple different formats to increase the number of other applications that can potentially use the data. +When you add data to the Clipboard, indicate the data format so that other applications can recognize the data if they can use that format. Add data to the Clipboard in multiple different formats to increase the number of other applications that can potentially use the data. -A Clipboard format is a string that identifies the format so that an application that uses that format can retrieve the associated data. The class provides predefined format names for your use. You can also use your own format names or use the type of an object as its format. +A Clipboard format is a string that identifies the format so that an application using that format can retrieve the associated data. The class provides predefined format names for your use. You can also use your own format names or use an object's type as its format. > [!NOTE] > All Windows-based applications share the Clipboard. Therefore, the contents are subject to change when you switch to another application. > > The class can only be used in threads set to single thread apartment (STA) mode. To use this class, ensure that your `Main` method is marked with the attribute. -To add data to the Clipboard in one or multiple formats, use the method. You can pass any object to this method, but to add data in multiple formats, you must first add the data to a separate object designed to work with multiple formats. Typically, you will add your data to a , but you can use any type that implements the interface. +To add data to the Clipboard in one or multiple formats, use the method. Pass any object to this method. To add data in multiple formats, first add the data to a separate object designed to work with multiple formats. Typically, add your data to a , but you can use any type that implements the interface. To add data to the Clipboard in a single, common format, use the specific method for that format, such as for text. @@ -40,7 +41,7 @@ To add data to the Clipboard in a single, common format, use the specific method ::: zone pivot="dotnetframework" > [!IMPORTANT] -> An object must be serializable for it to be put on the Clipboard. To make a type serializable, mark it with the attribute. If you pass a non-serializable object to a Clipboard method, the method will fail without throwing an exception. For more information about serialization, see . +> An object must be serializable for it to be put on the Clipboard. To make a type serializable, mark it with the attribute. If you pass a non-serializable object to a Clipboard method, the method fails without throwing an exception. For more information about serialization, see . ::: zone-end From 2bdcadc4d30231318ef41bda3c1a8bda2a6b9c82 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 09:21:57 -0700 Subject: [PATCH 30/51] Update instructions --- .github/copilot-instructions.md | 58 ++++- .github/instructions/EditPass.instructions.md | 230 +++++++++++++++--- .../style-copilot-section-instructions.md | 193 +++++++++++++++ 3 files changed, 443 insertions(+), 38 deletions(-) create mode 100644 .github/projects/clipboard/style-copilot-section-instructions.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f7f8b8bd99..44cef925db 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,11 +2,19 @@ ## Disclosure -IMPORTANT: For any Markdown files generated by AI, always disclose that they were created with the assistance of AI. Add the following frontmatter key/value pair: +IMPORTANT: For any Markdown files generated by AI, always disclose that they were created with the assistance of AI. Add the `ai-usage` frontmatter key/value pair: -```markdown -ai-usage: ai-generated -``` +- When Copilot generates the article through GitHub without the use of a human: + + ```markdown + ai-usage: ai-generated + ``` + +- When using an IDE with a human guiding AI: + + ```markdown + ai-usage: ai-assisted + ``` ## New articles @@ -33,6 +41,7 @@ Follow [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-g ### Structure and Format +- Markdown elements should have blank lines around them. Don't add extra blank lines if they already exist. - Sentence case headings (no gerunds in titles). - Be concise, break up long sentences. - IMPORTANT: Oxford comma in lists. @@ -71,6 +80,47 @@ For snippets >6 lines: 1. Create examples in both C# and Visual Basic unless the article referencing the snippet resides in the in the `csharp`, `fsharp`, and `visual-basic` language folders. 1. When you add code, use code comments sparingly because they don't get localized. You can use them to briefly clarify code-specific details (such as logic, parameters, or edge cases). Put any critical information and context in the markdown text of the referencing article. +## .NET Framework vs .NET differences + +When documenting differences between .NET Framework and .NET (like .NET 6 and newer), choose the appropriate system: + +### Use Tabs +Use tabbed content when the differences are code-based: + +```markdown +# [.NET](#tab/dotnet) + + + +# [.NET Framework](#tab/dotnetframework) + + + +--- +``` + +### Use Pivots +Use zone pivots when there are conceptual differences that can't easily be explained with tabs and a note. Pivots allow for more comprehensive explanations of different approaches or methodologies. + +To use zone pivots: + +1. Add `zone_pivot_groups: dotnet-version` to the article's frontmatter +2. Use zone pivot syntax in content: + +```markdown +::: zone pivot="dotnet" + +Your .NET content here + +::: zone-end + +::: zone pivot="dotnetframework" + +Your .NET Framework content here + +::: zone-end +``` + ## File Naming New Markdown files: lowercase with hyphens, omit filler words (the, a, etc.). diff --git a/.github/instructions/EditPass.instructions.md b/.github/instructions/EditPass.instructions.md index a68fac397e..f04a7ae5c1 100644 --- a/.github/instructions/EditPass.instructions.md +++ b/.github/instructions/EditPass.instructions.md @@ -2,51 +2,213 @@ description: Edit the content according to the Microsoft Style Guide --- -# Instructions for Editing Articles +# Article Editing Instructions for LLMs -When editing articles in this repository, follow these rules: +You are performing an edit pass on a Microsoft documentation article. Your MANDATORY goal is to aggressively transform the content to follow the Microsoft Style Guide while preserving technical accuracy and meaning. -## Disclosure +## EDITING APPROACH - FOLLOW THIS METHODOLOGY -- For any markdown file you edit, **IF** the `ai-usage` frontmatter is missing, add it and set it to `ai-assisted`. +1. **Read the entire document first** +2. **Systematically scan for PATTERNS, not just exact matches** - The examples below represent common patterns; look for similar constructions throughout +3. **Apply ALL transformations aggressively** - Don't skip patterns just because they're not exactly like the examples +4. **Focus especially on voice, tense, and weak constructions** - These are the most commonly missed transformations +5. **Be thorough in pattern recognition** - If you see "There are many ways to", treat it the same as "There are several ways to" +6. **Simplify aggressively while preserving meaning** - When in doubt, choose the simpler, more direct alternative -## Writing Style +## PATTERN EXAMPLES FOR RECOGNITION -IMPORTANT: +**Voice Patterns to Convert:** +- Any "X is/are done by Y" → "Y does X" +- Any "X can be done" → "Do X" or "You can do X" +- Any "X will be created" → "X creates" or "Create X" -- Use active voice and address the reader directly. -- Use a conversational tone with contractions. -- Use present tense for instructions and descriptions. -- Use imperative mood for instructions (for example, "Call the method" instead of "You should call the method"). -- Use "might" for possibility and "can" for permissible actions. -- Do not use "we" or "our" to refer to documentation authors or product teams. +**Instruction Patterns to Convert:** +- Any "You can/should/might/need to [verb]" → "[Verb]" +- Any "It's possible to [verb]" → "[Verb]" or "You can [verb]" +- Any "You have the option to" → "You can" or direct command -## Structure and Format +**Tense Patterns to Convert:** +- Any "will/would [verb]" in descriptions → "[verb]s" or "[verb]" +- Any "This would happen" → "This happens" -- Place blank lines around markdown elements, but do not add extra blank lines if they already exist. -- Use sentence case for headings. Do not use gerunds in titles. -- Be concise and break up long sentences. -- Use the Oxford comma in all lists. -- Number all ordered list items as "1." (not sequentially). -- Use bullets for unordered lists. -- All list items (ordered and unordered) must be complete sentences with proper punctuation, ending with a period if more than three words, unless you're editing a code comment in a code block. -- Do not use "etc." or "and so on." Provide complete lists or use "for example." -- Do not place consecutive headings without content between them. +## CRITICAL RULES - Follow These First -## Formatting Conventions +1. **Code Protection**: NEVER edit code within code blocks. Only edit code comments if necessary. +2. **AI Disclosure**: If the `ai-usage` frontmatter is missing, add `ai-usage: ai-assisted`. +3. **Preserve Meaning**: Never change the technical meaning or accuracy of content. +4. **Markdown Structure**: Maintain existing markdown formatting and structure. -- Use **bold** for UI elements. -- Use `code style` for file names, folders, custom types, and non-localizable text. -- Use raw URLs in angle brackets. -- Use relative links for files in this repo. -- Remove `https://learn.microsoft.com/en-us` from learn.microsoft.com links. +## MANDATORY TRANSFORMATIONS - Apply These Aggressively -## API References +You MUST systematically scan the entire document and apply ALL of these transformations. Do not skip any that apply: -- Use `` for API cross-references. -- To find API doc IDs, check the official dotnet-api-docs repository or use the API browser. +## Primary Edit Targets -## Code Snippets +When editing, focus on these areas in order of priority: -- IMPORTANT: If there is a code block in an article, ONLY edit the code comments. -- IMPORTANT: Do not edit the code itself even if there's an error. +### 1. VOICE AND TENSE - MANDATORY FIXES + +**SCAN FOR AND CONVERT ALL PASSIVE VOICE to active voice (these are examples - find ALL similar patterns):** +- ❌ "The method can be called" → ✅ "Call the method" +- ❌ "Settings are configured by..." → ✅ "Configure the settings..." +- ❌ "This can be done by..." → ✅ "Do this by..." or "To do this..." +- ❌ "The file will be created" → ✅ "The system creates the file" or "Create the file" +- Look for ANY pattern with: "is/are/was/were + past participle", "can be + verb", "will be + verb" + +**SCAN FOR AND CONVERT ALL weak instruction language to imperative mood (these are examples - find ALL similar patterns):** +- ❌ "You can call the method" → ✅ "Call the method" +- ❌ "You should configure" → ✅ "Configure" +- ❌ "You need to set" → ✅ "Set" +- ❌ "You might want to" → ✅ "Consider" or direct command +- Look for ANY pattern with: "You can/should/need to/might want to/have to + verb" + +**SCAN FOR AND CONVERT ALL future tense to present tense for descriptions (these are examples - find ALL similar patterns):** +- ❌ "This will create a file" → ✅ "This creates a file" +- ❌ "The application would start" → ✅ "The application starts" +- ❌ "You would see the result" → ✅ "You see the result" +- Look for ANY pattern with: "will/would/shall + verb" in descriptions + +**SCAN FOR AND ELIMINATE ALL weak constructions (these are examples - find ALL similar patterns):** +- ❌ "There are three ways to..." → ✅ "Use these three methods..." +- ❌ "It's possible to..." → ✅ "You can..." or start with the action +- ❌ "One way to do this is..." → ✅ "To do this..." +- ❌ "What this means is..." → ✅ "This means..." +- Look for ANY pattern starting with: "There are/is", "It's possible", "One way", "What this" + +### 2. CONTRACTIONS - MANDATORY ADDITIONS + +**SCAN FOR AND ADD contractions wherever appropriate (these are examples - find ALL similar patterns):** +- ❌ "it is" → ✅ "it's" +- ❌ "you are" → ✅ "you're" +- ❌ "do not" → ✅ "don't" +- ❌ "cannot" → ✅ "can't" +- ❌ "will not" → ✅ "won't" +- ❌ "does not" → ✅ "doesn't" +- ❌ "is not" → ✅ "isn't" +- ❌ "are not" → ✅ "aren't" +- ❌ "have not" → ✅ "haven't" +- ❌ "has not" → ✅ "hasn't" +- Look for ANY pattern with: full forms of common contractions + +**NEVER use these awkward contractions:** +- ❌ "there'd", "it'll", "they'd", "would've" +- ❌ Noun + verb contractions like "Microsoft's developing" + +### 3. WORD CHOICE - MANDATORY REPLACEMENTS + +**SCAN FOR AND REPLACE verbose phrases (these are examples - find ALL similar patterns):** +- ❌ "make use of" → ✅ "use" +- ❌ "be able to" → ✅ "can" +- ❌ "in order to" → ✅ "to" +- ❌ "utilize" → ✅ "use" +- ❌ "eliminate" → ✅ "remove" +- ❌ "inform" → ✅ "tell" +- ❌ "establish connectivity" → ✅ "connect" +- ❌ "implement functionality" → ✅ "implement features" or "add functionality" +- ❌ "demonstrate how to" → ✅ "show how to" +- Look for ANY unnecessarily complex or verbose phrasing + +**SCAN FOR AND REMOVE unnecessary words (these are examples - find ALL similar patterns):** +- ❌ "in addition" → ✅ "also" +- ❌ "as a means to" → ✅ "to" +- ❌ "for the purpose of" → ✅ "to" +- ❌ "with regard to" → ✅ "about" or "for" +- ❌ Remove filler words: "quite", "very", "easily", "simply" (unless essential) +- Look for ANY unnecessary prepositional phrases or filler words + +**SCAN FOR AND ENSURE consistent terminology (apply this principle throughout):** +- Pick one term for each concept and use it throughout +- ❌ "Because" and "Since" mixed → ✅ "Because" consistently +- Choose "method" OR "function" consistently within a section +- Look for ANY inconsistent terminology for the same concept + +### 4. SENTENCE STRUCTURE - MANDATORY IMPROVEMENTS + +**ALWAYS break up long sentences:** +- Target maximum 20-25 words per sentence +- Split any sentence with multiple clauses +- ❌ "When you configure the settings, which are located in the main menu, you can customize the behavior that controls how the application responds to user input." +- ✅ "Configure the settings in the main menu. These settings customize how the application responds to user input." + +**ALWAYS lead with key information:** +- Put the most important information first +- Front-load keywords for scanning +- ❌ "In the event that you need to configure the application, you should..." → ✅ "To configure the application..." +- ❌ "Before you can use the feature, you must..." → ✅ "Configure X before using the feature." + +**ALWAYS make next steps obvious:** +- Use clear transitions +- Number steps when there's a sequence +- Start action items with verbs + +### 5. FORMATTING - MANDATORY FIXES + +**ALWAYS use sentence case for headings:** +- ❌ "How To Configure The Settings" → ✅ "How to configure the settings" +- ❌ "Using The API" → ✅ "Using the API" +- ❌ "Getting Started With The Framework" → ✅ "Getting started with the framework" + +**ALWAYS fix punctuation:** +- Remove colons from headings: ❌ "Next steps:" → ✅ "Next steps" +- Periods in lists: Use periods for complete sentences over 3 words +- ❌ "Prerequisites." → ✅ "Prerequisites" (for short list items) + +**ALWAYS use proper formatting:** +- **Bold** for UI elements: "Select **File** > **Open**" +- `Code style` for: file names, folders, API names, code elements +- Remove `https://learn.microsoft.com/en-us` from internal links + +## MANDATORY WORD/PHRASE REPLACEMENTS + +**SCAN THE ENTIRE DOCUMENT for these patterns and replace ALL instances (not just exact matches):** + +| ❌ FIND AND REPLACE | ✅ ALWAYS Use Instead | Pattern to Look For | +|-------------|---------------|---------------------| +| "we", "our" (referring to Microsoft) | "the", "this", or direct statements | Any first-person plural | +| "may" (for possibility) | "might" | "may" when expressing possibility | +| "may" (for permission) | "can" | "may" when expressing permission | +| "etc.", "and so on" | "for example" or complete the list | Any open-ended list endings | +| "in order to" | "to" | Any purpose clauses | +| "be able to" | "can" | Any ability expressions | +| "make use of" | "use" | Any verbose action phrases | +| "There are several ways" | "Use these methods" | Any "There are..." constructions | +| "It's possible to" | "You can" or start with action | Any possibility statements | +| "You should" | Direct imperative or "Consider" | Any weak instruction language | +| "You can" (in instructions) | Direct imperative | Instructions that could be commands | +| "allows you to" | "lets you" | Any formal permission language | +| "provides the ability to" | "lets you" | Any verbose capability descriptions | + +**PATTERN RECOGNITION INSTRUCTIONS:** +- These examples represent PATTERNS, not exhaustive lists +- Look for similar constructions and apply the same principles +- When in doubt, choose the simpler, more direct alternative +- Focus on the underlying pattern (passive vs active, verbose vs concise, formal vs conversational) + +## LIST AND STRUCTURE RULES - MANDATORY + +### Lists +- ALWAYS use Oxford comma: "Android, iOS, and Windows" +- ALWAYS number ordered lists as "1." for all items (not 1., 2., 3.) +- ALWAYS use periods for complete sentences in lists (if more than 3 words) +- ALWAYS replace "etc." with "for example" or complete the list + +### Spacing and Punctuation +- ALWAYS use one space after periods, colons, question marks +- ALWAYS use no spaces around dashes: "Use pipelines—logical groups—to consolidate" +- ALWAYS add blank lines around markdown elements (don't add extra if they exist) + +## FINAL VALIDATION - MANDATORY CHECKS + +After editing, you MUST verify: +- [ ] ALL passive voice converted to active voice +- [ ] ALL "you can/should" converted to imperative mood +- [ ] ALL future tense converted to present tense for descriptions +- [ ] ALL contractions added where appropriate +- [ ] ALL verbose phrases simplified +- [ ] ALL weak constructions eliminated +- [ ] Content maintains technical accuracy +- [ ] Tone is conversational and helpful +- [ ] Sentences are concise and scannable +- [ ] Formatting follows conventions +- [ ] No consecutive headings without content +- [ ] Code blocks are unchanged (except comments if needed) diff --git a/.github/projects/clipboard/style-copilot-section-instructions.md b/.github/projects/clipboard/style-copilot-section-instructions.md new file mode 100644 index 0000000000..229b6a7a47 --- /dev/null +++ b/.github/projects/clipboard/style-copilot-section-instructions.md @@ -0,0 +1,193 @@ +# Add a Copilot highlight in the docs + +Copilot is a powerful AI tool that speeds up and simplifies complex development tasks. By adding Copilot information to articles in various product and service areas, we can help customers take advantage of this new and powerful tool. +This article provides instructions for identifying suitable articles, the types of scenarios we should target, and guidelines for crafting Copilot usage tips. + +## What is a Copilot highlight? + +A Copilot highlight is a section you add to an article that shows how to use Copilot to speed up or simplify the task that the article focuses on. It showcases a Copilot usage scenario and isn't a marketing pitch. + +A Copilot highlight targeting a specific usage scenario includes: + +- A descriptive section heading, such as "Use GitHub Copilot to serialize to JSON" +- A brief introduction explaining how Copilot can be applied to your scenario +- An example Copilot prompt formatted as a *Copilot-prompt* code block using the `copilot-prompt` value from the [Dev lang taxonomy](metadata-taxonomies/devlang.md). +- An optional Copilot output example +- Mandatory warning text for Copilot usage + +For examples, see [Examples of published Copilot highlights](#examples-of-published-copilot-highlights). + +## Identify potential articles + +You can add a Copilot highlight to any article type, including conceptual and reference articles, but we believe procedural articles are a good place to start. Use this set of criteria to identify articles with the highest potential impact: + +- **High traffic articles**: Prioritizing docs by page views help Copilot scenarios added here reach the most users. +- **Articles of topic type how-to, get-started, quickstart, or tutorial**: These content types lend themselves well to practical, actionable Copilot scenarios. +- **Articles with code snippets**: Scenarios involving Visual Studio/Visual Studio Code/Azure are good cases to show GitHub Copilot examples. +- **Articles that contain a scenario where Copilot can save developers time and effort on real world tasks**: See the [Identify helpful scenarios](#identify-helpful-scenarios) section that follows. + +## Identify helpful scenarios + +Page views and article types can help you find good candidates for a Copilot highlight, but the most important element is whether Copilot can provide meaningful value in the article. Look for articles where Copilot can save time and effort for real-world tasks. + +Relevant Copilot usage scenarios are use cases that align with typical user workflows or areas where Copilot's suggestions would be useful. Through these examples, we have an opportunity to educate the user to take advantage of Copilot's capabilities in their regular workflow and enhance their productivity. + +Some practical scenarios to show Copilot use: + +- Generate customized code: Tell the reader to take the code provided in the how-to or quickstart and show them how to construct a prompt that modifies it for their specific scenario. + For example: + - Modify code to use a specific operating system or webserver or database + - Generate language specific (for example, C#, C++, Python) or framework specific (for example, .NET, React) code + +- Help with complex or detailed syntax. + For example: + - Translate a specific date and time to cron syntax for scheduling pipelines + - Generate a specific regular expression + +- Help with repetitive, mechanical tasks. These actions require planning, but implementing the idea is something that Copilot can speed up. + For example: + - Generate a class and its members + - Take configuration information and generate a configuration file in a specific format + - Refactor code to use a different API + - Refactor code to target a different endpoint + - Generate a YAML pipeline or GitHub Action that publishes the solution + +- Help with troubleshooting. + For example: + - Use Copilot to debug an error + + +| **Recommended** | **Not recommended** | +| --- | --- | +| Use Copilot to generate serialization code for your specific objects.

*Why*: A prompt for this scenario shows how to generate custom code tailored to the user's specific task, unlike a static code example. | Ask Copilot about what specific code is doing.

*Why*: While interesting, a prompt for this scenario isn't specific to the article. It's generic guidance that belongs in a general "how to use copilot" article. | +| Use Copilot to migrate your specific `Newtonsoft.Json` code to `System.Text.Json`.

*Why*: A prompt for this scenario shows how to migrate user's custom code to use `System.Text.Json`, unlike a generic `System.Text.Json` code example. | Ask Copilot for instructions on how to do *XYZ*.

*Why*: A prompt for this scenario isn't specific to the article. It's generic guidance that belongs in a general "how to use copilot" article. | + +## Determine which Copilot to use + +Microsoft offers various ways to access Copilot: via the web, through Visual Studio, through Visual Studio Code, through the Azure portal, and more. And there are also plugins that can enhance these different flavors of Copilot. + +- Don't refer to a specific type of Copilot unless the functionality you're describing is limited to that specific Copilot. For example, if a prompt works for all Copilot instances, don't qualify it. If the prompt or context only works for GitHub Copilot for Visual Studio, say so. +- List any special installation requirements for Copilot (such as requiring a specific plugin) in the first few sentences. + +## Determine where to put the Copilot highlight + +- Add Copilot highlights to an existing article. Avoid creating a separate article just for the highlight. +- Place the highlight with the task/scenario being used in the Copilot example. If it's generic in context of the article, it can be an H2 at the end of the article. If it fits within a workflow, it can be an H3 or H4 within a section. +- Consider calling attention to the highlight if it appears later in the article by adding a link to it as a *Tip* in the article intro. + +## Copilot highlight structure + +A Copilot highlight has a heading, instructions, a prompt, an optional output example, and a boilerplate warning about using AI-generated content: + +- **Section title** + - Typical format: + + ````markdown + ## Use AI to + ```` + + For example: 'Use AI to serialize a .NET object'. + - Don't refer to Copilot in the section title, use the more generic "AI" +- **Instructions** + - Provide a generalized prompt formula. If the formula contains placeholders, provide an example prompt. + - Mention that the prompt uses Copilot, or a specific version of Copilot, but avoid mentioning Copilot more than once if possible. +- **Prompt** + - Use the `copilot-prompt` devlang + - Example: + + ````markdown + ```copilot-prompt + Take this code: + + And adapt it to use and and + ``` + ```` + +- **Output example** + - Don't show example output unless the prompt is complicated and contains placeholders. (The user can run the prompt themselves to see the output.) +- **Warning about AI-generated content** + Include the following warning as plain text (not a note) after you show your prompt. + + ````markdown + *Copilot is powered by AI, so surprises and mistakes are possible. For more information, see [Copilot general use FAQs](https://aka.ms/copilot-general-use-faqs).* + ```` + +## Writing guidelines + +- Be concise and brief. Hopefully, we add many Copilot highlights to our docs. It's important that these sections are focused on a specific task and don't include redundant information. + Avoid general guidelines and instructions about using Copilot, like explaining how prompts work. Other docs provide that information, which you can link to if you think the user needs them. +- Incorporate Copilot usage in the context of the article, rather than a generic example. +- Don't add gifs or screenshots to showcase the example scenario in action. +- Be sensitive about branding. Mention Copilot or the specific type of Copilot once in the introduction, but to keep the text friendly and avoid it coming across as marketing, don't use the Copilot name repeatedly. +- Avoid marketing language. Copilot is an innovative new technology. Instead of talking about how cool and exciting it is, show its value by demonstrating its usefulness. Basically, avoid marketing language. For more information, see the [guidelines on marketing language](contribute-get-started-channel-guidance.md#unauthorized-content). + +## Metadata requirements for highlights + +Add the following metadata to your article with the Copilot highlight: + +| Attribute | Value | Why? | +| --- | --- | --- | +| `ms.custom` | copilot-scenario-highlight | Helps identify docs updated with a copilot highlight | + +## Templates + +Here are some generic templates for adding a Copilot section to an existing article: + +### Highlight template - Adapt code for your scenario + +````markdown +## Use AI to customize the code for + +You can use AI tools, such as Copilot , to customize the code in this article for your specific scenario . + +```copilot-prompt +Take this code: + +And adapt it to use and and +``` + +Copilot is powered by AI, so surprises and mistakes are possible. For more information see Copilot FAQs. +```` + +### Highlight template - Accomplish a + +````markdown +## Use AI to accomplish + +You can use AI tools, such as Copilot , to . +To generate code that , customize this prompt for your specific case . + +```copilot-prompt +Example prompt that might contain placeholders that the user replaces with their information. +For example, generate a connection string that connects to a SQL server database with
that uses managed identity for authentication. +``` + +Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot FAQs. +```` + +## Examples of published Copilot highlights + +| Article | Copilot section | +| --- | --- | +| [How to convert a string to a number](/dotnet/csharp/programming-guide/types/how-to-convert-a-string-to-a-number) | [Use GitHub Copilot to convert a string to a number](/dotnet/csharp/programming-guide/types/how-to-convert-a-string-to-a-number#use-github-copilot-to-convert-a-string-to-a-number) | +| [Split strings into substrings](/dotnet/csharp/how-to/parse-strings-using-split) | [Use GitHub Copilot to split a string](/dotnet/csharp/how-to/parse-strings-using-split#use-github-copilot-to-split-a-string) | +| [How to serialize JSON in C#](/dotnet/standard/serialization/system-text-json/how-to) | [Use GitHub Copilot to serialize to JSON](/dotnet/standard/serialization/system-text-json/how-to#use-github-copilot-to-serialize-to-json) | +| [Migrate from Newtonsoft.Json to System.Text.Json](/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft) | [Use GitHub Copilot to migrate](/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft#use-github-copilot-to-migrate) | +| [How to deserialize JSON in C#](/dotnet/standard/serialization/system-text-json/deserialization) | [Use GitHub Copilot to deserialize JSON](/dotnet/standard/serialization/system-text-json/deserialization#use-github-copilot-to-deserialize-json) | +| [How to customize property names and values with System.Text.Json](/dotnet/standard/serialization/system-text-json/customize-properties) | [Use GitHub Copilot to customize property names and order](/dotnet/standard/serialization/system-text-json/customize-properties#use-github-copilot-to-customize-property-names-and-order) | + +## Questions + +Use the [Copilot in the Docs chat channel](https://aka.ms/copilotindocsquestion) in Microsoft Teams for questions or feedback, and to share the highlights you add to your docs. + +## Resources + +- [How to write better prompts for GitHub Copilot](https://github.blog/developer-skills/github/how-to-write-better-prompts-for-github-copilot/) +- [Get better results with Copilot prompting](https://support.microsoft.com/en-us/topic/get-better-results-with-copilot-prompting-77251d6c-e162-479d-b398-9e46cf73da55) +- [Prompt engineering for GitHub Copilot](https://docs.github.com/en/copilot/using-github-copilot/prompt-engineering-for-github-copilot) +- [Learn about Copilot prompts](https://support.microsoft.com/en-us/topic/learn-about-copilot-prompts-f6c3b467-f07c-4db1-ae54-ffac96184dd5) +- [Cooking up a great prompt: Getting the most from Copilot](https://support.microsoft.com/en-us/topic/cooking-up-a-great-prompt-getting-the-most-from-copilot-7b614306-d5aa-4b62-8509-e46674a29165) +- [Craft effective prompts for Microsoft 365 Copilot](/training/paths/craft-effective-prompts-copilot-microsoft-365/) +- [GitHub Copilot Chat in Visual Studio](/visualstudio/ide/visual-studio-github-copilot-chat) +- [GitHub Copilot in Visual Studio Code](https://code.visualstudio.com/docs/copilot/overview) +- [Copilot Chat Cookbook - GitHub Docs](https://docs.github.com/en/copilot/example-prompts-for-github-copilot-chat) \ No newline at end of file From 7440762f1a30eedf14ca078ab32ec28340578a42 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 09:26:20 -0700 Subject: [PATCH 31/51] Phase 2.3: Brief edit pass --- .../advanced/how-to-retrieve-data-from-the-clipboard.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md index 79be214a9f..c5f212bcaf 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md @@ -11,8 +11,9 @@ helpviewer_keywords: - "pasting Clipboard data" - "Clipboard [Windows Forms], retrieving data" ms.assetid: 99612537-2c8a-449f-aab5-2b3b28d656e7 +ai-usage: ai-assisted --- -# How to: Retrieve Data from the Clipboard +# How to retrieve data from the Clipboard The class provides methods that you can use to interact with the Windows operating system Clipboard feature. Many applications use the Clipboard as a temporary repository for data. For example, word processors use the Clipboard during cut-and-paste operations. The Clipboard is also useful for transferring information from one application to another. @@ -20,7 +21,7 @@ Some applications store data on the Clipboard in multiple formats to increase th To determine whether the Clipboard contains data in a particular format, use one of the `Contains`*Format* methods or the method. To retrieve data from the Clipboard, use one of the `Get`*Format* methods or the method. These methods are new in .NET Framework 2.0. -To access data from the Clipboard by using versions earlier than .NET Framework 2.0, use the method and call the methods of the returned . To determine whether a particular format is available in the returned object, for example, call the method. +To access data from the Clipboard using versions earlier than .NET Framework 2.0, use the method and call the methods of the returned . To determine whether a particular format is available in the returned object, for example, call the method. > [!NOTE] > All Windows-based applications share the system Clipboard. Therefore, the contents are subject to change when you switch to another application. From 9b7c0bbf2193d7080b11cb0ef28fd47f096dac36 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 10:22:48 -0700 Subject: [PATCH 32/51] Phase 2.3: Migrate snippets --- ...how-to-retrieve-data-from-the-clipboard.md | 20 +++++++++--------- .../framework/csharp/Program.cs | 16 ++++++++++++++ .../csharp/RetrieveClipboardData.csproj | 9 ++++++++ .../framework/csharp}/form1.cs | 20 +++++++++--------- .../framework/vb/Program.vb | 11 ++++++++++ .../framework/vb/RetrieveClipboardData.vbproj | 9 ++++++++ .../framework}/vb/form1.vb | 21 ++++++++++--------- 7 files changed, 76 insertions(+), 30 deletions(-) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/Program.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/RetrieveClipboardData.csproj rename dotnet-desktop-guide/{samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS => winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp}/form1.cs (94%) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/Program.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/RetrieveClipboardData.vbproj rename dotnet-desktop-guide/{samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard => winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework}/vb/form1.vb (94%) diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md index c5f212bcaf..7e0a65d748 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md @@ -32,8 +32,8 @@ To access data from the Clipboard using versions earlier than .NET Framework 2.0 1. Use the , , , or method. Optionally, use the corresponding `Contains`*Format* methods first to determine whether data is available in a particular format. These methods are available only in .NET Framework 2.0. - [!code-csharp[System.Windows.Forms.Clipboard#2](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#2)] - [!code-vb[System.Windows.Forms.Clipboard#2](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#2)] + :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-common-format"::: + :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-common-format"::: ### To retrieve data from the Clipboard in a custom format @@ -41,19 +41,19 @@ To access data from the Clipboard using versions earlier than .NET Framework 2.0 You can also use predefined format names with the method. For more information, see . - [!code-csharp[System.Windows.Forms.Clipboard#3](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#3)] - [!code-vb[System.Windows.Forms.Clipboard#3](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#3)] - [!code-csharp[System.Windows.Forms.Clipboard#100](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#100)] - [!code-vb[System.Windows.Forms.Clipboard#100](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#100)] + :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-custom-format"::: + :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-custom-format"::: + :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: + :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: ### To retrieve data from the Clipboard in multiple formats 1. Use the method. You must use this method to retrieve data from the Clipboard on versions earlier than .NET Framework 2.0. - [!code-csharp[System.Windows.Forms.Clipboard#4](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#4)] - [!code-vb[System.Windows.Forms.Clipboard#4](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#4)] - [!code-csharp[System.Windows.Forms.Clipboard#100](~/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs#100)] - [!code-vb[System.Windows.Forms.Clipboard#100](~/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb#100)] + :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-multiple-formats"::: + :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-multiple-formats"::: + :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: + :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: ## See also diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/Program.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/Program.cs new file mode 100644 index 0000000000..906bbabb41 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/Program.cs @@ -0,0 +1,16 @@ +using System; +using System.Windows.Forms; + +namespace RetrieveClipboardData +{ + static class Program + { + [STAThread] + static void Main() + { + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/RetrieveClipboardData.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/RetrieveClipboardData.csproj new file mode 100644 index 0000000000..d161c73f49 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/RetrieveClipboardData.csproj @@ -0,0 +1,9 @@ + + + + WinExe + net48 + true + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs similarity index 94% rename from dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs index 3690bf36f5..d15532589a 100644 --- a/dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/CS/form1.cs +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs @@ -1,9 +1,9 @@ -using System; +using System; using System.Windows.Forms; public class Form1 : Form { - // + // [Serializable] public class Customer { @@ -18,7 +18,7 @@ public string Name set { nameValue = value; } } } - // + // public Form1() { @@ -27,7 +27,7 @@ public Form1() // } - // + // // Demonstrates SetData, ContainsData, and GetData // using a custom format name and a business object. public Customer TestCustomFormat @@ -42,9 +42,9 @@ public Customer TestCustomFormat return null; } } - // + // - // + // // Demonstrates how to use a DataObject to add // data to the Clipboard in multiple formats. public void TestClipboardMultipleFormats() @@ -81,7 +81,7 @@ public void TestClipboardMultipleFormats() } } } - // + // // // Demonstrates SetData, ContainsData, and GetData. @@ -97,7 +97,7 @@ public Object SwapClipboardFormattedData(String format, Object data) } // - // + // // // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. public System.IO.Stream SwapClipboardAudio( @@ -157,5 +157,5 @@ public String SwapClipboardHtmlText(String replacementHtmlText) return returnHtmlText; } // - // -} + // +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/Program.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/Program.vb new file mode 100644 index 0000000000..d1d61fe1e2 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/Program.vb @@ -0,0 +1,11 @@ +Imports System +Imports System.Windows.Forms + +Module Program + + Sub Main() + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New Form1()) + End Sub +End Module \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/RetrieveClipboardData.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/RetrieveClipboardData.vbproj new file mode 100644 index 0000000000..d161c73f49 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/RetrieveClipboardData.vbproj @@ -0,0 +1,9 @@ + + + + WinExe + net48 + true + + + \ No newline at end of file diff --git a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb similarity index 94% rename from dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb index d65f67f1f6..143cff66bc 100644 --- a/dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/vb/form1.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb @@ -1,9 +1,9 @@ -Imports System.Windows.Forms +Imports System.Windows.Forms Public Class Form1 Inherits Form - ' + ' Public Class Customer Private nameValue As String = String.Empty @@ -22,7 +22,7 @@ Public Class Form1 End Property End Class - ' + ' Public Sub New() ' @@ -30,7 +30,7 @@ Public Class Form1 ' End Sub - ' + ' ' Demonstrates SetData, ContainsData, and GetData ' using a custom format name and a business object. Public ReadOnly Property TestCustomFormat() As Customer @@ -44,9 +44,9 @@ Public Class Form1 Return Nothing End Get End Property - ' + ' - ' + ' ' Demonstrates how to use a DataObject to add ' data to the Clipboard in multiple formats. Public Sub TestClipboardMultipleFormats() @@ -88,7 +88,7 @@ Public Class Form1 End If End Sub - ' + ' ' ' Demonstrates SetData, ContainsData, and GetData. @@ -107,7 +107,7 @@ Public Class Form1 End Function ' - ' + ' ' ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. Public Function SwapClipboardAudio( _ @@ -160,6 +160,7 @@ Public Class Form1 End If Return returnImage + End Function ' @@ -179,6 +180,6 @@ Public Class Form1 End Function ' - ' + ' -End Class +End Class \ No newline at end of file From 6ee3a2cea62169578421c472ef38918b2ffcd39a Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" Date: Thu, 2 Oct 2025 14:51:46 -0700 Subject: [PATCH 33/51] More copilot updates --- ...tions.md => EditPass.Full.instructions.md} | 0 .../EditPass.LinkText.Instructions.md | 4 + .../Snippets.Migrate.instructions.md | 5 +- .github/prompts/RefreshLinks.prompt.md | 86 +++++++++++++++++++ 4 files changed, 94 insertions(+), 1 deletion(-) rename .github/instructions/{EditPass.instructions.md => EditPass.Full.instructions.md} (100%) create mode 100644 .github/instructions/EditPass.LinkText.Instructions.md create mode 100644 .github/prompts/RefreshLinks.prompt.md diff --git a/.github/instructions/EditPass.instructions.md b/.github/instructions/EditPass.Full.instructions.md similarity index 100% rename from .github/instructions/EditPass.instructions.md rename to .github/instructions/EditPass.Full.instructions.md diff --git a/.github/instructions/EditPass.LinkText.Instructions.md b/.github/instructions/EditPass.LinkText.Instructions.md new file mode 100644 index 0000000000..2ce915ccef --- /dev/null +++ b/.github/instructions/EditPass.LinkText.Instructions.md @@ -0,0 +1,4 @@ +--- +description: Refresh the text of all links in the current file +--- + diff --git a/.github/instructions/Snippets.Migrate.instructions.md b/.github/instructions/Snippets.Migrate.instructions.md index d90a18308f..80f50d2f2e 100644 --- a/.github/instructions/Snippets.Migrate.instructions.md +++ b/.github/instructions/Snippets.Migrate.instructions.md @@ -121,7 +121,10 @@ description: Migrate code from the old ~/samples/snippets/ location to the relat - **Clean**: Remove unused legacy files (if no other articles reference them) ### 7. Delete -- **Identify**: Check if the old snippet file is used by any other articles +- **Identify**: + - Check if the old snippet file is used by any other articles + - Some articles may use a relative path to the `samples` folder, so simply search for `samples/snippets/...` + - Be confident that all legacy snippets use a `samples/snippets` folder structure - **Delete**: If old snippet is no longer used by any article, delete it. ## Common mistakes to avoid diff --git a/.github/prompts/RefreshLinks.prompt.md b/.github/prompts/RefreshLinks.prompt.md new file mode 100644 index 0000000000..4e96defe28 --- /dev/null +++ b/.github/prompts/RefreshLinks.prompt.md @@ -0,0 +1,86 @@ +--- +model: GPT-4o (copilot) +mode: agent +description: "Updates link text to match target content headings" +--- + +# Refresh Links Prompt + +You are tasked with checking and updating all links in the current file to ensure their link text accurately reflects the target content's H1 heading or title. + +## Link Types and Processing Rules + +### 1. Relative Links (e.g., `./folder/file.md`, `../folder/file.md`) +- **Target**: Files within this repository, relative to the current file's location +- **Action**: Read the target file and extract the H1 heading (should be within the first 30 lines) +- **Update**: Replace the link text with the extracted H1 heading + +### 2. Root-Relative Links (e.g., `/dotnet-desktop-guide/wpf/overview`) +- **Target**: Published pages on https://learn.microsoft.com/ +- **Action**: Fetch the page from `https://learn.microsoft.com{link-path}` and extract the H1 heading +- **Update**: Replace the link text with the extracted H1 heading + +### 3. Repository Root Links (e.g., `~/dotnet-desktop-guide/winforms/overview.md`) +- **Target**: Files within this repository, relative to the repository root +- **Action**: Convert `~/` to the repository root path, read the target file, and extract the H1 heading +- **Update**: Replace the link text with the extracted H1 heading + +### 4. Full URLs (e.g., `https://example.com/page`) +- **Target**: External web pages +- **Action**: Fetch the page and extract the H1 heading or page title +- **Update**: Replace the link text with the extracted heading/title + +### 5. XREF links (e.g., `[link text](xref:api-doc-id)`) +- **Target**: API documentation links +- **Action**: Do not change the link text, ignore this type of item. + +## Processing Instructions + +1. **Scan the file**: Identify all markdown links in the format `[link text](url)` + +2. **For each link**: + - Determine the link type based on the URL pattern + - Follow the appropriate processing rule above + - Extract the H1 heading or title from the target + - Compare with current link text + - Update if different + +3. **H1 Extraction Rules**: + - Look for markdown H1 headers (`# Heading Text`) + - For repository files, check within the first 30 lines + - For web pages, extract the `

` tag content or `` tag as fallback + - Clean up the extracted text (remove extra whitespace, HTML entities) + +4. **Preserve Link Functionality**: + - Keep the original URL intact + - Only update the display text portion + - Maintain any additional link attributes if present + +5. **Error Handling**: + - If a target cannot be reached or read, leave the link unchanged + - If no H1 is found, try alternative heading levels (H2, H3) or page title + - Log any issues encountered during processing + +## Example Transformations + +```markdown +Before: [Old Link Text](../wpf/overview.md) +After: [WPF Overview](../wpf/overview.md) + +Before: [Click here](/dotnet-desktop-guide/winforms/getting-started) +After: [Getting Started with Windows Forms](/dotnet-desktop-guide/winforms/getting-started) + +Before: [Link](~/dotnet-desktop-guide/wpf/controls/button.md) +After: [Button Control](~/dotnet-desktop-guide/wpf/controls/button.md) + +Before: [External](https://example.com/some-page) +After: [Example Page](https://example.com/some-page) +``` + +## Output + +Provide a summary of: +- Total links processed +- Number of links updated +- Any errors or warnings encountered +- List of updated links with before/after text From f15d8d2a3dd24db7f46bf617eb2ab88637eaeb28 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 14:52:03 -0700 Subject: [PATCH 34/51] Phase 2.3: Final commit before build --- .../how-to-add-data-to-the-clipboard.md | 4 +- ...how-to-retrieve-data-from-the-clipboard.md | 127 ++++++++++-- .../framework/csharp/form1.cs | 12 -- .../framework/vb/form1.vb | 12 -- .../net/csharp/MainForm.cs | 159 ++++++++++++++++ .../net/csharp/Program.cs | 18 ++ .../net/csharp/RetrieveClipboardData.csproj | 11 ++ .../net/vb/MainForm.vb | 180 ++++++++++++++++++ .../net/vb/Program.vb | 14 ++ .../net/vb/RetrieveClipboardData.vbproj | 9 + 10 files changed, 502 insertions(+), 44 deletions(-) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/Program.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/RetrieveClipboardData.csproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/Program.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/RetrieveClipboardData.vbproj diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md index 0fc20dcb64..8e0eaee9d8 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-add-data-to-the-clipboard.md @@ -131,5 +131,5 @@ The `Customer` class used in the previous snippet: ## See also - [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) -- [How to: Retrieve Data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) -- [Windows Forms clipboard and DataObject changes in .NET 10](../../migration/clipboard-dataobject-net10.md) +- [How to retrieve data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) +- [Windows Forms clipboard and DataObject changes in .NET 10](../migration/clipboard-dataobject-net10.md) diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md index 7e0a65d748..f24b36e81f 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md @@ -12,16 +12,33 @@ helpviewer_keywords: - "Clipboard [Windows Forms], retrieving data" ms.assetid: 99612537-2c8a-449f-aab5-2b3b28d656e7 ai-usage: ai-assisted +zone_pivot_groups: dotnet-version --- # How to retrieve data from the Clipboard The <xref:System.Windows.Forms.Clipboard> class provides methods that you can use to interact with the Windows operating system Clipboard feature. Many applications use the Clipboard as a temporary repository for data. For example, word processors use the Clipboard during cut-and-paste operations. The Clipboard is also useful for transferring information from one application to another. -Some applications store data on the Clipboard in multiple formats to increase the number of other applications that can potentially use the data. A Clipboard format is a string that identifies the format. An application that uses the identified format can retrieve the associated data on the Clipboard. The <xref:System.Windows.Forms.DataFormats> class provides predefined format names for your use. You can also use your own format names or use an object's type as its format. For information about adding data to the Clipboard, see [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md). +Some applications store data on the Clipboard in multiple formats to increase the number of other applications that can potentially use the data. A Clipboard format is a string that identifies the format. An application that uses the identified format can retrieve the associated data on the Clipboard. The <xref:System.Windows.Forms.DataFormats> class provides predefined format names for your use. You can also use your own format names or use an object's type as its format. For information about adding data to the Clipboard, see [How to add data to the Clipboard](how-to-add-data-to-the-clipboard.md). -To determine whether the Clipboard contains data in a particular format, use one of the `Contains`*Format* methods or the <xref:System.Windows.Forms.Clipboard.GetData%2A> method. To retrieve data from the Clipboard, use one of the `Get`*Format* methods or the <xref:System.Windows.Forms.Clipboard.GetData%2A> method. These methods are new in .NET Framework 2.0. +::: zone pivot="dotnet" -To access data from the Clipboard using versions earlier than .NET Framework 2.0, use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A?displayProperty=nameWithType> method and call the methods of the returned <xref:System.Windows.Forms.IDataObject>. To determine whether a particular format is available in the returned object, for example, call the <xref:System.Windows.Forms.IDataObject.GetDataPresent%2A> method. +To determine whether the Clipboard contains data in a particular format, use one of the `Contains`*Format* methods. To retrieve data from the Clipboard, use one of the `Get`*Format* methods or the <xref:System.Windows.Forms.Clipboard.TryGetData%2A> method for custom formats. + +> [!NOTE] +> In .NET Framework, you use the <xref:System.Windows.Forms.Clipboard.GetData%2A> method instead of `TryGetData`, and the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method is commonly used for multiple format scenarios. + +::: zone-end + +::: zone pivot="dotnetframework" + +To determine whether the Clipboard contains data in a particular format, use one of the `Contains`*Format* methods. To retrieve data from the Clipboard, use one of the `Get`*Format* methods or the <xref:System.Windows.Forms.Clipboard.GetData%2A> method for custom formats. + +You can also use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A?displayProperty=nameWithType> method and call the methods of the returned <xref:System.Windows.Forms.IDataObject>. To determine whether a particular format is available in the returned object, for example, call the <xref:System.Windows.Forms.IDataObject.GetDataPresent%2A> method. + +> [!NOTE] +> Starting with .NET 10, the `GetData` method is obsoleted in favor of `TryGetData`, and object serialization through `SetData` is no longer supported for security reasons. + +::: zone-end > [!NOTE] > All Windows-based applications share the system Clipboard. Therefore, the contents are subject to change when you switch to another application. @@ -30,32 +47,106 @@ To access data from the Clipboard using versions earlier than .NET Framework 2.0 ### To retrieve data from the Clipboard in a single, common format -1. Use the <xref:System.Windows.Forms.Clipboard.GetAudioStream%2A>, <xref:System.Windows.Forms.Clipboard.GetFileDropList%2A>, <xref:System.Windows.Forms.Clipboard.GetImage%2A>, or <xref:System.Windows.Forms.Clipboard.GetText%2A> method. Optionally, use the corresponding `Contains`*Format* methods first to determine whether data is available in a particular format. These methods are available only in .NET Framework 2.0. +::: zone pivot="dotnet" - :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-common-format"::: - :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-common-format"::: +1. Use the <xref:System.Windows.Forms.Clipboard.GetAudioStream%2A>, <xref:System.Windows.Forms.Clipboard.GetFileDropList%2A>, <xref:System.Windows.Forms.Clipboard.GetImage%2A>, or <xref:System.Windows.Forms.Clipboard.GetText%2A> method. Optionally, use the corresponding `Contains`*Format* methods first to determine whether data is available in a particular format. + + For custom data formats, use the `TryGetData` method instead of the obsoleted `GetData` method. + +> [!NOTE] +> In .NET Framework, these same `Get`*Format* methods are available, but you use `GetData` instead of `TryGetData` for custom formats. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-common-format"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-common-format"::: + +::: zone-end + +::: zone pivot="dotnetframework" + +1. Use the <xref:System.Windows.Forms.Clipboard.GetAudioStream%2A>, <xref:System.Windows.Forms.Clipboard.GetFileDropList%2A>, <xref:System.Windows.Forms.Clipboard.GetImage%2A>, or <xref:System.Windows.Forms.Clipboard.GetText%2A> method. Optionally, use the corresponding `Contains`*Format* methods first to determine whether data is available in a particular format. + +> [!NOTE] +> In .NET (non-Framework), the `GetData` method is obsoleted in favor of `TryGetData` for custom data formats, and object serialization is no longer supported. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-common-format"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-common-format"::: + +::: zone-end ### To retrieve data from the Clipboard in a custom format -1. Use the <xref:System.Windows.Forms.Clipboard.GetData%2A> method with a custom format name. This method is available only in .NET Framework 2.0. +::: zone pivot="dotnet" + +1. Use the <xref:System.Windows.Forms.Clipboard.TryGetData%2A> method with a custom format name. This method replaces the obsoleted `GetData` method in modern .NET versions. - You can also use predefined format names with the <xref:System.Windows.Forms.Clipboard.SetData%2A> method. For more information, see <xref:System.Windows.Forms.DataFormats>. + You can also use predefined format names with this method. For more information, see <xref:System.Windows.Forms.DataFormats>. - :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-custom-format"::: - :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-custom-format"::: - :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: - :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: +> [!IMPORTANT] +> In .NET 10 and later, `SetData` for object serialization is no longer supported due to security concerns. The examples below show how to retrieve data that may have been set by other applications or earlier .NET versions. + +> [!NOTE] +> In .NET Framework, you use the <xref:System.Windows.Forms.Clipboard.GetData%2A> method instead of `TryGetData`, and object serialization through `SetData` is fully supported. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-custom-format"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-custom-format"::: + +The `Customer` class used in the previous snippet: + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="helper-methods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="helper-methods"::: + +::: zone-end + +::: zone pivot="dotnetframework" + +1. Use the <xref:System.Windows.Forms.Clipboard.GetData%2A> method with a custom format name. + + You can also use predefined format names with the <xref:System.Windows.Forms.Clipboard.SetData%2A> method. For more information, see <xref:System.Windows.Forms.DataFormats>. + +> [!NOTE] +> In .NET (non-Framework), the `GetData` method is obsoleted in favor of `TryGetData`, and object serialization through `SetData` is no longer supported for security reasons. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-custom-format"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-custom-format"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: + +::: zone-end ### To retrieve data from the Clipboard in multiple formats -1. Use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method. You must use this method to retrieve data from the Clipboard on versions earlier than .NET Framework 2.0. +::: zone pivot="dotnet" + +1. Use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method to get an <xref:System.Windows.Forms.IDataObject>, then use <xref:System.Windows.Forms.Clipboard.TryGetData%2A> to retrieve data in specific formats. + + This approach is recommended for modern .NET applications as it uses the newer, safer APIs. + +> [!NOTE] +> In .NET Framework, you typically use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method and work directly with the returned <xref:System.Windows.Forms.IDataObject>, using its methods like <xref:System.Windows.Forms.IDataObject.GetData%2A> instead of the newer `TryGetData` approach. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-multiple-formats"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-multiple-formats"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="helper-methods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="helper-methods"::: + +::: zone-end + +::: zone pivot="dotnetframework" + +1. Use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method. + +> [!NOTE] +> In .NET (non-Framework), you typically combine `GetDataObject` with the newer `TryGetData` method rather than working directly with the <xref:System.Windows.Forms.IDataObject> methods. + +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-multiple-formats"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-multiple-formats"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: - :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-multiple-formats"::: - :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-multiple-formats"::: - :::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: - :::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: +::: zone-end ## See also - [Drag-and-Drop Operations and Clipboard Support](drag-and-drop-operations-and-clipboard-support.md) -- [How to: Add Data to the Clipboard](how-to-add-data-to-the-clipboard.md) +- [How to add data to the Clipboard](how-to-add-data-to-the-clipboard.md) +- [Windows Forms clipboard and DataObject changes in .NET 10](../migration/clipboard-dataobject-net10.md) diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs index d15532589a..390227a6fd 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs @@ -22,9 +22,7 @@ public string Name public Form1() { - //<snippet1> Clipboard.Clear(); - //</snippet1> } //<retrieve-custom-format> @@ -83,7 +81,6 @@ public void TestClipboardMultipleFormats() } //</retrieve-multiple-formats> - //<snippet10> // Demonstrates SetData, ContainsData, and GetData. public Object SwapClipboardFormattedData(String format, Object data) { @@ -95,10 +92,8 @@ public Object SwapClipboardFormattedData(String format, Object data) } return returnObject; } - //</snippet10> //<retrieve-common-format> - //<snippet20> // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. public System.IO.Stream SwapClipboardAudio( System.IO.Stream replacementAudioStream) @@ -111,9 +106,7 @@ public System.IO.Stream SwapClipboardAudio( } return returnAudioStream; } - //</snippet20> - //<snippet30> // Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList public System.Collections.Specialized.StringCollection SwapClipboardFileDropList( @@ -127,9 +120,7 @@ public System.Collections.Specialized.StringCollection } return returnList; } - //</snippet30> - //<snippet40> // Demonstrates SetImage, ContainsImage, and GetImage. public System.Drawing.Image SwapClipboardImage( System.Drawing.Image replacementImage) @@ -142,9 +133,7 @@ public System.Drawing.Image SwapClipboardImage( } return returnImage; } - //</snippet40> - //<snippet50> // Demonstrates SetText, ContainsText, and GetText. public String SwapClipboardHtmlText(String replacementHtmlText) { @@ -156,6 +145,5 @@ public String SwapClipboardHtmlText(String replacementHtmlText) } return returnHtmlText; } - //</snippet50> //</retrieve-common-format> } \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb index 143cff66bc..803cb802e2 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb @@ -25,9 +25,7 @@ Public Class Form1 '</helper-methods> Public Sub New() - '<snippet1> Clipboard.Clear() - '</snippet1> End Sub '<retrieve-custom-format> @@ -90,7 +88,6 @@ Public Class Form1 End Sub '</retrieve-multiple-formats> - '<snippet10> ' Demonstrates SetData, ContainsData, and GetData. Public Function SwapClipboardFormattedData( _ ByVal format As String, ByVal data As Object) As Object @@ -105,10 +102,8 @@ Public Class Form1 Return returnObject End Function - '</snippet10> '<retrieve-common-format> - '<snippet20> ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. Public Function SwapClipboardAudio( _ ByVal replacementAudioStream As System.IO.Stream) _ @@ -124,9 +119,7 @@ Public Class Form1 Return returnAudioStream End Function - '</snippet20> - '<snippet30> ' Demonstrates SetFileDropList, ContainsFileDroList, and GetFileDropList Public Function SwapClipboardFileDropList(ByVal replacementList _ As System.Collections.Specialized.StringCollection) _ @@ -144,9 +137,7 @@ Public Class Form1 Return returnList End Function - '</snippet30> - '<snippet40> ' Demonstrates SetImage, ContainsImage, and GetImage. Public Function SwapClipboardImage( _ ByVal replacementImage As System.Drawing.Image) _ @@ -162,9 +153,7 @@ Public Class Form1 Return returnImage End Function - '</snippet40> - '<snippet50> ' Demonstrates SetText, ContainsText, and GetText. Public Function SwapClipboardHtmlText( _ ByVal replacementHtmlText As String) As String @@ -179,7 +168,6 @@ Public Class Form1 Return returnHtmlText End Function - '</snippet50> '</retrieve-common-format> End Class \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs new file mode 100644 index 0000000000..cdf5dfa1f1 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs @@ -0,0 +1,159 @@ +using System.Collections.Specialized; +using System.Drawing; +using System.Windows.Forms; + +namespace RetrieveClipboardData; + +public class MainForm : Form +{ + //<helper-methods> + [Serializable] + public class Customer + { + private string nameValue = string.Empty; + public Customer(string name) + { + nameValue = name; + } + public string Name + { + get { return nameValue; } + set { nameValue = value; } + } + } + //</helper-methods> + + public MainForm() + { + Clipboard.Clear(); + } + + //<retrieve-custom-format> + // Demonstrates TryGetData using a custom format name and a business object. + // Note: In .NET 10, SetData for objects is no longer supported, + // so this example shows how to retrieve data that might have been + // set by other applications or earlier .NET versions. + public Customer? TestCustomFormat + { + get + { + // For demonstration, we'll use string data instead of objects + // since SetData for objects is no longer supported in .NET 10 + if (Clipboard.TryGetData("CustomerFormat", out object? data)) + { + return data as Customer; + } + return null; + } + } + //</retrieve-custom-format> + + //<retrieve-multiple-formats> + // Demonstrates how to retrieve data from the Clipboard in multiple formats + // using TryGetData instead of the obsoleted GetData method. + public void TestClipboardMultipleFormats() + { + IDataObject? dataObject = Clipboard.GetDataObject(); + + if (dataObject != null) + { + // Check for custom format + if (dataObject.GetDataPresent("CustomFormat")) + { + if (Clipboard.TryGetData("CustomFormat", out object? customData)) + { + if (customData is ListViewItem item) + { + MessageBox.Show(item.Text); + } + else if (customData is string stringData) + { + MessageBox.Show(stringData); + } + } + } + + // Check for Customer type - note that object serialization + // through SetData is no longer supported in .NET 10 + if (dataObject.GetDataPresent(typeof(Customer))) + { + if (Clipboard.TryGetData(typeof(Customer).FullName!, out object? customerData)) + { + if (customerData is Customer customer) + { + MessageBox.Show(customer.Name); + } + } + } + + // For modern .NET 10 applications, prefer using standard formats + if (Clipboard.ContainsText()) + { + string text = Clipboard.GetText(); + MessageBox.Show($"Text data: {text}"); + } + } + } + //</retrieve-multiple-formats> + + //<retrieve-common-format> + // Demonstrates TryGetData methods for common formats. + // These methods are preferred over the older Get* methods. + public Stream? SwapClipboardAudio(Stream replacementAudioStream) + { + Stream? returnAudioStream = null; + if (Clipboard.ContainsAudio()) + { + returnAudioStream = Clipboard.GetAudioStream(); + Clipboard.SetAudio(replacementAudioStream); + } + return returnAudioStream; + } + + // Demonstrates TryGetData for file drop lists + public StringCollection? SwapClipboardFileDropList(StringCollection replacementList) + { + StringCollection? returnList = null; + if (Clipboard.ContainsFileDropList()) + { + returnList = Clipboard.GetFileDropList(); + Clipboard.SetFileDropList(replacementList); + } + return returnList; + } + + // Demonstrates TryGetData for images + public Image? SwapClipboardImage(Image replacementImage) + { + Image? returnImage = null; + if (Clipboard.ContainsImage()) + { + returnImage = Clipboard.GetImage(); + Clipboard.SetImage(replacementImage); + } + return returnImage; + } + + // Demonstrates TryGetData for text in HTML format + public string? SwapClipboardHtmlText(string replacementHtmlText) + { + string? returnHtmlText = null; + if (Clipboard.ContainsText(TextDataFormat.Html)) + { + returnHtmlText = Clipboard.GetText(TextDataFormat.Html); + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html); + } + return returnHtmlText; + } + + // Example of using TryGetData for custom string-based data + public string? GetCustomStringData(string format) + { + if (Clipboard.TryGetData(format, out object? data)) + { + return data as string; + } + return null; + } + //</retrieve-common-format> +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/Program.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/Program.cs new file mode 100644 index 0000000000..c7a30edb1b --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/Program.cs @@ -0,0 +1,18 @@ +using System.Windows.Forms; + +namespace RetrieveClipboardData; + +internal static class Program +{ + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new MainForm()); + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/RetrieveClipboardData.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/RetrieveClipboardData.csproj new file mode 100644 index 0000000000..00df3eb651 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/RetrieveClipboardData.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <UseWindowsForms>true</UseWindowsForms> + <ImplicitUsings>enable</ImplicitUsings> + <Nullable>enable</Nullable> + </PropertyGroup> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb new file mode 100644 index 0000000000..e43c00b4d4 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb @@ -0,0 +1,180 @@ +Imports System.Collections.Specialized +Imports System.Drawing +Imports System.Windows.Forms + +Namespace RetrieveClipboardData + + Public Class MainForm + Inherits Form + + '<helper-methods> + <Serializable()> + Public Class Customer + + Private nameValue As String = String.Empty + + Public Sub New(ByVal name As String) + nameValue = name + End Sub + + Public Property Name() As String + Get + Return nameValue + End Get + Set(ByVal value As String) + nameValue = value + End Set + End Property + + End Class + '</helper-methods> + + Public Sub New() + Clipboard.Clear() + End Sub + + '<retrieve-custom-format> + ' Demonstrates TryGetData using a custom format name and a business object. + ' Note: In .NET 10, SetData for objects is no longer supported, + ' so this example shows how to retrieve data that might have been + ' set by other applications or earlier .NET versions. + Public ReadOnly Property TestCustomFormat() As Customer + Get + Dim data As Object = Nothing + ' For demonstration, we'll use string data instead of objects + ' since SetData for objects is no longer supported in .NET 10 + If Clipboard.TryGetData("CustomerFormat", data) Then + Return TryCast(data, Customer) + End If + Return Nothing + End Get + End Property + '</retrieve-custom-format> + + '<retrieve-multiple-formats> + ' Demonstrates how to retrieve data from the Clipboard in multiple formats + ' using TryGetData instead of the obsoleted GetData method. + Public Sub TestClipboardMultipleFormats() + + Dim dataObject As IDataObject = Clipboard.GetDataObject() + + If dataObject IsNot Nothing Then + + ' Check for custom format + If dataObject.GetDataPresent("CustomFormat") Then + + Dim customData As Object = Nothing + If Clipboard.TryGetData("CustomFormat", customData) Then + + Dim item As ListViewItem = TryCast(customData, ListViewItem) + If item IsNot Nothing Then + MessageBox.Show(item.Text) + ElseIf TypeOf customData Is String Then + MessageBox.Show(CStr(customData)) + End If + + End If + + End If + + ' Check for Customer type - note that object serialization + ' through SetData is no longer supported in .NET 10 + If dataObject.GetDataPresent(GetType(Customer)) Then + + Dim customerData As Object = Nothing + If Clipboard.TryGetData(GetType(Customer).FullName, customerData) Then + + Dim customer As Customer = TryCast(customerData, Customer) + If customer IsNot Nothing Then + MessageBox.Show(customer.Name) + End If + + End If + + End If + + ' For modern .NET 10 applications, prefer using standard formats + If Clipboard.ContainsText() Then + Dim text As String = Clipboard.GetText() + MessageBox.Show($"Text data: {text}") + End If + + End If + + End Sub + '</retrieve-multiple-formats> + + '<retrieve-common-format> + ' Demonstrates TryGetData methods for common formats. + ' These methods are preferred over the older Get* methods. + Public Function SwapClipboardAudio(ByVal replacementAudioStream As System.IO.Stream) As System.IO.Stream + + Dim returnAudioStream As System.IO.Stream = Nothing + + If Clipboard.ContainsAudio() Then + returnAudioStream = Clipboard.GetAudioStream() + Clipboard.SetAudio(replacementAudioStream) + End If + + Return returnAudioStream + + End Function + + ' Demonstrates TryGetData for file drop lists + Public Function SwapClipboardFileDropList(ByVal replacementList As StringCollection) As StringCollection + + Dim returnList As StringCollection = Nothing + + If Clipboard.ContainsFileDropList() Then + returnList = Clipboard.GetFileDropList() + Clipboard.SetFileDropList(replacementList) + End If + + Return returnList + + End Function + + ' Demonstrates TryGetData for images + Public Function SwapClipboardImage(ByVal replacementImage As Image) As Image + + Dim returnImage As Image = Nothing + + If Clipboard.ContainsImage() Then + returnImage = Clipboard.GetImage() + Clipboard.SetImage(replacementImage) + End If + + Return returnImage + + End Function + + ' Demonstrates TryGetData for text in HTML format + Public Function SwapClipboardHtmlText(ByVal replacementHtmlText As String) As String + + Dim returnHtmlText As String = Nothing + + If Clipboard.ContainsText(TextDataFormat.Html) Then + returnHtmlText = Clipboard.GetText(TextDataFormat.Html) + Clipboard.SetText(replacementHtmlText, TextDataFormat.Html) + End If + + Return returnHtmlText + + End Function + + ' Example of using TryGetData for custom string-based data + Public Function GetCustomStringData(ByVal format As String) As String + + Dim data As Object = Nothing + If Clipboard.TryGetData(format, data) Then + Return TryCast(data, String) + End If + + Return Nothing + + End Function + '</retrieve-common-format> + + End Class + +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/Program.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/Program.vb new file mode 100644 index 0000000000..796fc42ff7 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/Program.vb @@ -0,0 +1,14 @@ +Imports System.Windows.Forms +Imports System + +Friend Module Program + + <STAThread()> + Friend Sub Main(args As String()) + Application.SetHighDpiMode(HighDpiMode.SystemAware) + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New RetrieveClipboardData.MainForm()) + End Sub + +End Module diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/RetrieveClipboardData.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/RetrieveClipboardData.vbproj new file mode 100644 index 0000000000..49b98949ec --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/RetrieveClipboardData.vbproj @@ -0,0 +1,9 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <UseWindowsForms>true</UseWindowsForms> + </PropertyGroup> + +</Project> \ No newline at end of file From 976713e36aa07a07801acb8d5a7eecb79501f220 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 15:31:15 -0700 Subject: [PATCH 35/51] Fix snippet ids --- ...how-to-retrieve-data-from-the-clipboard.md | 40 +++++++++---------- .../framework/csharp/form1.cs | 16 ++++---- .../framework/vb/form1.vb | 16 ++++---- .../net/csharp/MainForm.cs | 16 ++++---- .../net/vb/MainForm.vb | 16 ++++---- 5 files changed, 52 insertions(+), 52 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md index f24b36e81f..42f1976ea6 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-retrieve-data-from-the-clipboard.md @@ -56,8 +56,8 @@ You can also use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A?displ > [!NOTE] > In .NET Framework, these same `Get`*Format* methods are available, but you use `GetData` instead of `TryGetData` for custom formats. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-common-format"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-common-format"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="RetrieveCommonFormat"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="RetrieveCommonFormat"::: ::: zone-end @@ -68,8 +68,8 @@ You can also use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A?displ > [!NOTE] > In .NET (non-Framework), the `GetData` method is obsoleted in favor of `TryGetData` for custom data formats, and object serialization is no longer supported. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-common-format"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-common-format"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="RetrieveCommonFormat"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="RetrieveCommonFormat"::: ::: zone-end @@ -87,13 +87,13 @@ You can also use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A?displ > [!NOTE] > In .NET Framework, you use the <xref:System.Windows.Forms.Clipboard.GetData%2A> method instead of `TryGetData`, and object serialization through `SetData` is fully supported. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-custom-format"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-custom-format"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="RetrieveCustomFormat"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="RetrieveCustomFormat"::: The `Customer` class used in the previous snippet: -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="helper-methods"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="helper-methods"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="HelperMethods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="HelperMethods"::: ::: zone-end @@ -106,10 +106,10 @@ The `Customer` class used in the previous snippet: > [!NOTE] > In .NET (non-Framework), the `GetData` method is obsoleted in favor of `TryGetData`, and object serialization through `SetData` is no longer supported for security reasons. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-custom-format"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-custom-format"::: -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="RetrieveCustomFormat"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="RetrieveCustomFormat"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="HelperMethods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="HelperMethods"::: ::: zone-end @@ -124,10 +124,10 @@ The `Customer` class used in the previous snippet: > [!NOTE] > In .NET Framework, you typically use the <xref:System.Windows.Forms.Clipboard.GetDataObject%2A> method and work directly with the returned <xref:System.Windows.Forms.IDataObject>, using its methods like <xref:System.Windows.Forms.IDataObject.GetData%2A> instead of the newer `TryGetData` approach. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="retrieve-multiple-formats"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="retrieve-multiple-formats"::: -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="helper-methods"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="helper-methods"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="RetrieveMultipleFormats"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="RetrieveMultipleFormats"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs" id="HelperMethods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb" id="HelperMethods"::: ::: zone-end @@ -138,10 +138,10 @@ The `Customer` class used in the previous snippet: > [!NOTE] > In .NET (non-Framework), you typically combine `GetDataObject` with the newer `TryGetData` method rather than working directly with the <xref:System.Windows.Forms.IDataObject> methods. -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="retrieve-multiple-formats"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="retrieve-multiple-formats"::: -:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="helper-methods"::: -:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="helper-methods"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="RetrieveMultipleFormats"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="RetrieveMultipleFormats"::: +:::code language="csharp" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs" id="HelperMethods"::: +:::code language="vb" source="./snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb" id="HelperMethods"::: ::: zone-end diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs index 390227a6fd..7245adb62f 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/csharp/form1.cs @@ -3,7 +3,7 @@ public class Form1 : Form { - //<helper-methods> + //<HelperMethods> [Serializable] public class Customer { @@ -18,14 +18,14 @@ public string Name set { nameValue = value; } } } - //</helper-methods> + //</HelperMethods> public Form1() { Clipboard.Clear(); } - //<retrieve-custom-format> + //<RetrieveCustomFormat> // Demonstrates SetData, ContainsData, and GetData // using a custom format name and a business object. public Customer TestCustomFormat @@ -40,9 +40,9 @@ public Customer TestCustomFormat return null; } } - //</retrieve-custom-format> + //</RetrieveCustomFormat> - //<retrieve-multiple-formats> + //<RetrieveMultipleFormats> // Demonstrates how to use a DataObject to add // data to the Clipboard in multiple formats. public void TestClipboardMultipleFormats() @@ -79,7 +79,7 @@ public void TestClipboardMultipleFormats() } } } - //</retrieve-multiple-formats> + //</RetrieveMultipleFormats> // Demonstrates SetData, ContainsData, and GetData. public Object SwapClipboardFormattedData(String format, Object data) @@ -93,7 +93,7 @@ public Object SwapClipboardFormattedData(String format, Object data) return returnObject; } - //<retrieve-common-format> + //<RetrieveCommonFormat> // Demonstrates SetAudio, ContainsAudio, and GetAudioStream. public System.IO.Stream SwapClipboardAudio( System.IO.Stream replacementAudioStream) @@ -145,5 +145,5 @@ public String SwapClipboardHtmlText(String replacementHtmlText) } return returnHtmlText; } - //</retrieve-common-format> + //</RetrieveCommonFormat> } \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb index 803cb802e2..7f0583c13d 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/framework/vb/form1.vb @@ -3,7 +3,7 @@ Imports System.Windows.Forms Public Class Form1 Inherits Form - '<helper-methods> + '<HelperMethods> <Serializable()> Public Class Customer Private nameValue As String = String.Empty @@ -22,13 +22,13 @@ Public Class Form1 End Property End Class - '</helper-methods> + '</HelperMethods> Public Sub New() Clipboard.Clear() End Sub - '<retrieve-custom-format> + '<RetrieveCustomFormat> ' Demonstrates SetData, ContainsData, and GetData ' using a custom format name and a business object. Public ReadOnly Property TestCustomFormat() As Customer @@ -42,9 +42,9 @@ Public Class Form1 Return Nothing End Get End Property - '</retrieve-custom-format> + '</RetrieveCustomFormat> - '<retrieve-multiple-formats> + '<RetrieveMultipleFormats> ' Demonstrates how to use a DataObject to add ' data to the Clipboard in multiple formats. Public Sub TestClipboardMultipleFormats() @@ -86,7 +86,7 @@ Public Class Form1 End If End Sub - '</retrieve-multiple-formats> + '</RetrieveMultipleFormats> ' Demonstrates SetData, ContainsData, and GetData. Public Function SwapClipboardFormattedData( _ @@ -103,7 +103,7 @@ Public Class Form1 End Function - '<retrieve-common-format> + '<RetrieveCommonFormat> ' Demonstrates SetAudio, ContainsAudio, and GetAudioStream. Public Function SwapClipboardAudio( _ ByVal replacementAudioStream As System.IO.Stream) _ @@ -168,6 +168,6 @@ Public Class Form1 Return returnHtmlText End Function - '</retrieve-common-format> + '</RetrieveCommonFormat> End Class \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs index cdf5dfa1f1..93fde16f00 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/csharp/MainForm.cs @@ -6,7 +6,7 @@ namespace RetrieveClipboardData; public class MainForm : Form { - //<helper-methods> + //<HelperMethods> [Serializable] public class Customer { @@ -21,14 +21,14 @@ public string Name set { nameValue = value; } } } - //</helper-methods> + //</HelperMethods> public MainForm() { Clipboard.Clear(); } - //<retrieve-custom-format> + //<RetrieveCustomFormat> // Demonstrates TryGetData using a custom format name and a business object. // Note: In .NET 10, SetData for objects is no longer supported, // so this example shows how to retrieve data that might have been @@ -46,9 +46,9 @@ public Customer? TestCustomFormat return null; } } - //</retrieve-custom-format> + //</RetrieveCustomFormat> - //<retrieve-multiple-formats> + //<RetrieveMultipleFormats> // Demonstrates how to retrieve data from the Clipboard in multiple formats // using TryGetData instead of the obsoleted GetData method. public void TestClipboardMultipleFormats() @@ -94,9 +94,9 @@ public void TestClipboardMultipleFormats() } } } - //</retrieve-multiple-formats> + //</RetrieveMultipleFormats> - //<retrieve-common-format> + //<RetrieveCommonFormat> // Demonstrates TryGetData methods for common formats. // These methods are preferred over the older Get* methods. public Stream? SwapClipboardAudio(Stream replacementAudioStream) @@ -155,5 +155,5 @@ public void TestClipboardMultipleFormats() } return null; } - //</retrieve-common-format> + //</RetrieveCommonFormat> } \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb index e43c00b4d4..32ba9e19a3 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-retrieve-data-from-the-clipboard/net/vb/MainForm.vb @@ -7,7 +7,7 @@ Namespace RetrieveClipboardData Public Class MainForm Inherits Form - '<helper-methods> + '<HelperMethods> <Serializable()> Public Class Customer @@ -27,13 +27,13 @@ Namespace RetrieveClipboardData End Property End Class - '</helper-methods> + '</HelperMethods> Public Sub New() Clipboard.Clear() End Sub - '<retrieve-custom-format> + '<RetrieveCustomFormat> ' Demonstrates TryGetData using a custom format name and a business object. ' Note: In .NET 10, SetData for objects is no longer supported, ' so this example shows how to retrieve data that might have been @@ -49,9 +49,9 @@ Namespace RetrieveClipboardData Return Nothing End Get End Property - '</retrieve-custom-format> + '</RetrieveCustomFormat> - '<retrieve-multiple-formats> + '<RetrieveMultipleFormats> ' Demonstrates how to retrieve data from the Clipboard in multiple formats ' using TryGetData instead of the obsoleted GetData method. Public Sub TestClipboardMultipleFormats() @@ -102,9 +102,9 @@ Namespace RetrieveClipboardData End If End Sub - '</retrieve-multiple-formats> + '</RetrieveMultipleFormats> - '<retrieve-common-format> + '<RetrieveCommonFormat> ' Demonstrates TryGetData methods for common formats. ' These methods are preferred over the older Get* methods. Public Function SwapClipboardAudio(ByVal replacementAudioStream As System.IO.Stream) As System.IO.Stream @@ -173,7 +173,7 @@ Namespace RetrieveClipboardData Return Nothing End Function - '</retrieve-common-format> + '</RetrieveCommonFormat> End Class From 9829a2c81443e56c32a5cd8e1a35b159aaafff66 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 17:16:00 -0700 Subject: [PATCH 36/51] More instruction updates --- .../EditPass.LinkText.Instructions.md | 4 - ...ns.md => Editing.FullPass.instructions.md} | 0 .../Plans.ClipboardWork.instructions.md | 73 ++++------- .../Snippets.Migrate.instructions.md | 6 +- .../Snippets.Push.instructions.md | 121 ++++++++++++++++++ .../Snippets.Upgrade.instructions.md | 8 +- 6 files changed, 155 insertions(+), 57 deletions(-) delete mode 100644 .github/instructions/EditPass.LinkText.Instructions.md rename .github/instructions/{EditPass.Full.instructions.md => Editing.FullPass.instructions.md} (100%) create mode 100644 .github/instructions/Snippets.Push.instructions.md diff --git a/.github/instructions/EditPass.LinkText.Instructions.md b/.github/instructions/EditPass.LinkText.Instructions.md deleted file mode 100644 index 2ce915ccef..0000000000 --- a/.github/instructions/EditPass.LinkText.Instructions.md +++ /dev/null @@ -1,4 +0,0 @@ ---- -description: Refresh the text of all links in the current file ---- - diff --git a/.github/instructions/EditPass.Full.instructions.md b/.github/instructions/Editing.FullPass.instructions.md similarity index 100% rename from .github/instructions/EditPass.Full.instructions.md rename to .github/instructions/Editing.FullPass.instructions.md diff --git a/.github/instructions/Plans.ClipboardWork.instructions.md b/.github/instructions/Plans.ClipboardWork.instructions.md index 1349fafcb4..c091ab37e9 100644 --- a/.github/instructions/Plans.ClipboardWork.instructions.md +++ b/.github/instructions/Plans.ClipboardWork.instructions.md @@ -8,9 +8,9 @@ description: The plan for updating the Clipboard content If you're creating article files, use the [templates](/.github/projects/article-templates/) folder to find a suitable article template. IMPORTANT! Add the following files as context: +- [Migration guide for Clipboard in .NET 10](/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md) - [Engineer's overview on the changes in .NET 10 for Clipboard](/.github/projects/clipboard/clipboard-dataobject-net10-changes.md) - [BinaryFormatter migration guide](https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-migration-guide/) -- [Summary of existing articles](/.github/projects/clipboard/temp-clipboard-articles.md) ## Executive Summary @@ -23,12 +23,6 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar 1. **`drag-and-drop-operations-and-clipboard-support.md`** - Main overview article 2. **`how-to-add-data-to-the-clipboard.md`** - Adding data guide 3. **`how-to-retrieve-data-from-the-clipboard.md`** - Retrieving data guide -4. **`additional-security-considerations-in-windows-forms.md`** - Security section needs updates - -### Existing Code Snippets: - -- **`dotnet-desktop-guide/samples/snippets/csharp/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`** -- **`dotnet-desktop-guide/samples/snippets/visualbasic/VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`** ## Detailed Update Plan @@ -48,9 +42,9 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - **Estimated Length**: 2,000-2,500 words - **Status**: Completed -### Phase 2: Update Existing Core Articles +### Phase 2: Update Existing Core Articles ✅ -#### 2.1 Update Main Overview (`drag-and-drop-operations-and-clipboard-support.md`) +#### 2.1 Update Main Overview (`drag-and-drop-operations-and-clipboard-support.md`) ✅ - **Changes Needed**: - Add .NET 10 compatibility section @@ -58,8 +52,9 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - Add links to new migration guide - Update "In This Section" with new articles - **Priority**: High +- **Status**: Completed -#### 2.2 Comprehensive Rewrite (`how-to-add-data-to-the-clipboard.md`) +#### 2.2 Comprehensive Rewrite (`how-to-add-data-to-the-clipboard.md`) ✅ - **Major Changes**: - Add new section on `SetDataAsJson<T>()` method @@ -72,8 +67,9 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - "Working with Recommended Built-in Types" - "Migrating from Legacy SetData Methods" - **Priority**: High +- **Status**: Completed -#### 2.3 Comprehensive Rewrite (`how-to-retrieve-data-from-the-clipboard.md`) +#### 2.3 Comprehensive Rewrite (`how-to-retrieve-data-from-the-clipboard.md`) ✅ - **Major Changes**: - Replace `GetData()` examples with `TryGetData<T>()` methods @@ -85,20 +81,13 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - "Handling Legacy Binary Data" - "Working with Custom JSON Types" - **Priority**: High - -#### 2.4 Update Security Article (`additional-security-considerations-in-windows-forms.md`) - -- **Changes Needed**: - - Update clipboard security section for .NET 10 - - Add information about BinaryFormatter security implications - - Document new runtime configuration switches - - Add guidance on type resolvers for legacy support -- **Priority**: Medium +- **Status**: Completed ### Phase 3: Create New Specialized Articles #### 3.1 New Article: `how-to-use-typed-clipboard-apis.md` +- **Template**: How-to article - **Content Focus**: - Detailed guide on `TryGetData<T>()` methods - Examples of all overloads @@ -115,8 +104,9 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - Cross-process/cross-framework compatibility - **Priority**: Medium -#### 3.3 New Article: `enabling-binaryformatter-clipboard-support.md` +#### 3.3 New Article: `how-to-enable-binaryformatter-clipboard-support.md` +- **Template**: How-to article - **Content Focus**: - Complete guide for legacy application migration - Runtime configuration steps @@ -124,34 +114,15 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - Type resolver implementation examples - **Priority**: Medium (for legacy support) -### Phase 4: Update Code Snippets and Examples - -#### 4.1 Create New Snippet Collections - -- **Location**: `dotnet-desktop-guide/samples/snippets/winforms/clipboard-net10/` -- **Contents**: - - `basic-json-serialization/` - SetDataAsJson examples - - `typed-retrieval/` - TryGetData examples - - `legacy-migration/` - Before/after migration examples - - `custom-resolver/` - Type resolver implementations -- **Languages**: C# and VB.NET for each example - -#### 4.2 Update Existing Snippets - -- **`VS_Snippets_Winforms/System.Windows.Forms.Clipboard/`**: - - Add new .NET 10 examples alongside existing ones - - Mark legacy examples with version compatibility notes - - Add migration guidance in comments - -### Phase 5: Navigation and Discoverability Updates +### Phase 4: Navigation and Discoverability Updates -#### 5.1 Update Table of Contents (`toc.yml`) +#### 4.1 Update Table of Contents (`toc.yml`) - Add new articles to the drag-and-drop section - Reorganize clipboard articles for better flow - Add migration guide as featured content -#### 5.2 Update Cross-References +#### 4.2 Update Cross-References - Add xref links between related articles - Update "See also" sections across all clipboard articles @@ -159,17 +130,17 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar ## Implementation Timeline -### Week 1-2: Foundation +### Week 1-2: Foundation ✅ -- [ ] Create comprehensive migration overview article -- [ ] Update main overview article with .NET 10 references -- [ ] Set up new code snippet structure +- [x] Create comprehensive migration overview article +- [x] Update main overview article with .NET 10 references +- [x] Set up new code snippet structure -### Week 3-4: Core Rewrites +### Week 3-4: Core Rewrites ✅ -- [ ] Rewrite "How to: Add Data" article -- [ ] Rewrite "How to: Retrieve Data" article -- [ ] Create new typed APIs guide +- [x] Rewrite "How to: Add Data" article +- [x] Rewrite "How to: Retrieve Data" article +- [x] Create new typed APIs guide ### Week 5-6: Specialized Content diff --git a/.github/instructions/Snippets.Migrate.instructions.md b/.github/instructions/Snippets.Migrate.instructions.md index 80f50d2f2e..df74ecefe1 100644 --- a/.github/instructions/Snippets.Migrate.instructions.md +++ b/.github/instructions/Snippets.Migrate.instructions.md @@ -54,6 +54,9 @@ description: Migrate code from the old ~/samples/snippets/ location to the relat - ✅ MUST target appropriate .NET version (see targeting rules below) - ✅ MUST provide BOTH C# and Visual Basic versions - ✅ MUST use appropriate syntax for the target framework +- ✅ MUST use meaningful, descriptive snippet identifiers in CamelCase format + - **Examples** of good snippet identifiers: `BasicClipboardData`, `CustomDataFormat`, `ClipboardImageHandling` + - **Avoid** simplistic identifiers like `1`, `2`, `code1`, or `snippet1` **Current article references look like this:** ```markdown @@ -113,7 +116,8 @@ description: Migrate code from the old ~/samples/snippets/ location to the relat ### 5. Update article references - **Replace**: Change from legacy `[!code-...]` format to modern `:::code...:::` format - **Before**: `[!code-csharp[description](~/samples/snippets/path/file.cs#snippet1)]` -- **After**: `:::code language="csharp" source="./snippets/doc-name/net/csharp/file.cs" id="snippet1":::` +- **After**: `:::code language="csharp" source="./snippets/doc-name/net/csharp/file.cs" id="BasicClipboardData":::` +- **Note**: Use meaningful CamelCase identifiers instead of simple numbers ### 6. Validate - **Build**: Ensure all code compiles successfully diff --git a/.github/instructions/Snippets.Push.instructions.md b/.github/instructions/Snippets.Push.instructions.md new file mode 100644 index 0000000000..209b70dc8a --- /dev/null +++ b/.github/instructions/Snippets.Push.instructions.md @@ -0,0 +1,121 @@ +--- +description: Push inline code block snippets out of articles into standalone files with proper project structure. +--- + +# Push inline code snippets to files + +**IMPORTANT**: Unless otherwise asked to, **only** edit the article file in context. At the end of your operations you may ask for permission to edit other articles that might benefit from the same snippet extraction. + +## Quick Reference + +**WHEN TO PUSH:** Code >6 lines, complete/compilable examples, or when specifically requested +**FOLDER PATTERN:** `./snippets/{doc-file}/[net-or-framework]/{csharp|vb}/` +**PROJECT CREATION:** Always use `dotnet new {winforms|wpf|console|classlib}` commands +**LANGUAGES:** Create both C# and VB versions +**SNIPPET IDs:** Use CamelCase region markers like `<ButtonClick>` +**ARTICLE REFS:** Replace with `:::code language="csharp" source="./path" id="SnippetId":::` + +## When to push snippets out of articles + +**PUSH SNIPPETS WHEN:** +- Code blocks are longer than 6 lines or the rest of the article is using them +- Code demonstrates complete, compilable examples +- Code should not be reused across multiple articles +- Code represents a complete application or significant functionality +- User specifically requests snippet extraction + +**KEEP INLINE WHEN:** +- Code blocks are 6 lines or shorter +- Code shows configuration snippets (XAML, JSON, XML) +- Code demonstrates simple one-liner examples +- Code is pseudo-code or conceptual examples + +## Target folder structure + +**IMPORTANT**: Follow the same structure as the migration guidelines: + +### New snippet location (standard) +- Path pattern: `./snippets/{doc-file}/[net-or-framework]/{code-language}/` +- Example: `./snippets/create-windows-forms-app/net/csharp/` + +**Path components explained:** +- `{doc-file}`: The markdown article filename WITHOUT the `.md` extension + - Example: For article `create-windows-forms-app.md` → use `create-windows-forms-app` +- `[net-or-framework]`: Choose based on target framework: + - `net`: For .NET (.NET 6 and newer) + - `framework`: For .NET Framework (4.8 and older) + - **Rule**: Only include this subfolder when the article demonstrates BOTH .NET and .NET Framework approaches +- `{code-language}`: + - `csharp`: For C# code + - `vb`: For Visual Basic code + +## Framework targeting and project types + +**Determine target framework:** +- Check article frontmatter `ms.service` value: + - `dotnet-framework` → .NET Framework 4.8 + - `dotnet-desktop` → Current .NET (e.g., .NET 10) +- Examine code patterns and article content + +**Create appropriate project with `dotnet new`:** + +| Project Type | Indicators | .NET Command | .NET Framework Command | +|--------------|------------|--------------|------------------------| +| **Windows Forms** | `System.Windows.Forms`, `Form`, `/winforms/` path | `dotnet new winforms` | `dotnet new winforms --framework net48` | +| **WPF** | `System.Windows`, `Window`, XAML, `/wpf/` path | `dotnet new wpf` | `dotnet new wpf --framework net48` | +| **Console** | `Console.WriteLine`, simple examples, no UI | `dotnet new console` | `dotnet new console --framework net48` | +| **Class Library** | Reusable components, no entry point | `dotnet new classlib` | `dotnet new classlib --framework net48` | + +## Push process + +### 1. Analyze and prepare +- Locate code blocks >6 lines or complete examples +- Determine project type from code patterns and article location +- Check framework targeting from frontmatter +- Create folder structure: `./snippets/{doc-file}/[net-or-framework]/{csharp|vb}/` + +### 2. Create projects and extract code +- Run appropriate `dotnet new` command in each language folder +- Copy and complete code to make it compilable +- Add missing using statements, namespaces, class declarations +- Modernize code patterns if targeting current .NET +- Test compilation with `dotnet build` + +### 3. Add snippet references and update article +- Add CamelCase region markers: `// <ButtonClick>` and `// </ButtonClick>` +- Use same identifiers across C# and VB versions +- Replace inline code with snippet references: + ```markdown + :::code language="csharp" source="./snippets/doc-name/net/csharp/File.cs" id="ButtonClick"::: + :::code language="vb" source="./snippets/doc-name/net/vb/File.vb" id="ButtonClick"::: + ``` +- DO NOT use language tabs, simply put them side-by-side +- Verify all paths and references are correct + +### 4. Make sure frontmatter specifies a language when required + +If both CSharp and VB examples are provided make sure the following frontmatter is at the top of the article: + +```yml +dev_langs: + - "csharp" + - "vb" +``` + +## Common mistakes to avoid + +- ❌ Extracting short snippets (≤6 lines) without request +- ❌ Skipping `dotnet new` commands or creating incomplete projects +- ❌ Missing C# or VB versions +- ❌ Using language tabs +- ❌ Wrong project type (winforms vs wpf vs console) +- ❌ Incorrect framework targeting (net vs framework) +- ❌ Missing or inconsistent snippet region identifiers +- ❌ Code that doesn't compile + +## Quality checklist + +- ✅ Correct folder structure and project type +- ✅ Both C# and VB versions compile successfully +- ✅ Snippet regions use CamelCase identifiers +- ✅ Article uses correct `:::code...:::` syntax with valid paths \ No newline at end of file diff --git a/.github/instructions/Snippets.Upgrade.instructions.md b/.github/instructions/Snippets.Upgrade.instructions.md index fac19c8e22..caf0f3228d 100644 --- a/.github/instructions/Snippets.Upgrade.instructions.md +++ b/.github/instructions/Snippets.Upgrade.instructions.md @@ -30,8 +30,14 @@ All snippets must follow this folder structure relative to the referencing artic - **USE** PascalCase for class names and file names (e.g., `MainForm.cs`, `DataProcessor.cs`) - **ORGANIZE** files logically within the language folder -### 2. Snippet naming +### 2. Snippet Identifiers and Naming +- **USE** meaningful, descriptive snippet identifiers in CamelCase format - **REPLACE** simplistic identifiers (like single numbers) with descriptive snippet names +- **EXAMPLES** of good snippet identifiers: + - `BasicClipboardData` instead of `1` + - `CustomDataFormat` instead of `2` + - `ClipboardImageHandling` instead of `code1` +- **ENSURE** snippet identifiers clearly describe the code's purpose or functionality ### 3. .NET Version and Syntax Modernization - **TARGET** the latest stable .NET version for `/net/` folders From d920b4b4fc4d0d2aac6f90ee742fa832bf33ea75 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 17:16:34 -0700 Subject: [PATCH 37/51] Phase 1: Convert code to snippets --- .../migration/clipboard-dataobject-net10.md | 362 ++---------------- .../net/csharp/BinaryFormatterSupport.cs | 67 ++++ .../net/csharp/CustomTypesExamples.cs | 74 ++++ .../net/csharp/Form1.Designer.cs | 38 ++ .../net/csharp/Form1.cs | 9 + .../net/csharp/ITypedDataObjectExamples.cs | 74 ++++ .../net/csharp/ModernApproach.cs | 40 ++ .../net/csharp/ObsoletePatterns.cs | 48 +++ .../net/csharp/PrimitiveTypesExamples.cs | 66 ++++ .../net/csharp/Program.cs | 16 + .../net/csharp/SetDataAsJsonExamples.cs | 50 +++ .../net/csharp/SystemDrawingTypesExamples.cs | 31 ++ .../net/csharp/TypeResolver.cs | 67 ++++ .../net/csharp/TypeSafeRetrieval.cs | 94 +++++ .../net/csharp/csharp.csproj | 11 + .../net/vb/BinaryFormatterSupport.vb | 58 +++ .../net/vb/CustomTypesExamples.vb | 77 ++++ .../net/vb/Form1.Designer.vb | 31 ++ .../net/vb/Form1.vb | 3 + .../net/vb/ITypedDataObjectExamples.vb | 68 ++++ .../net/vb/ModernApproach.vb | 32 ++ .../net/vb/ObsoletePatterns.vb | 41 ++ .../net/vb/PrimitiveTypesExamples.vb | 60 +++ .../net/vb/Program.vb | 11 + .../net/vb/SetDataAsJsonExamples.vb | 44 +++ .../net/vb/SystemDrawingTypesExamples.vb | 28 ++ .../net/vb/TypeResolver.vb | 62 +++ .../net/vb/TypeSafeRetrieval.vb | 110 ++++++ .../net/vb/vb.vbproj | 17 + 29 files changed, 1364 insertions(+), 325 deletions(-) create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Program.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SystemDrawingTypesExamples.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/csharp.csproj create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.Designer.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Program.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SystemDrawingTypesExamples.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/vb.vbproj diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 1762b11b81..32024e7361 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -6,6 +6,9 @@ ms.author: adegeo ms.service: dotnet-desktop ms.topic: concept-article ms.date: 09/26/2025 +dev_langs: + - "csharp" + - "vb" ms.custom: - copilot-scenario-highlight ai-usage: ai-assisted @@ -47,21 +50,8 @@ In .NET 8 and earlier, you could place any serializable custom object on the cli The following code no longer works: -```csharp -[Serializable] -public class Person -{ - public string Name { get; set; } - public int Age { get; set; } -} - -// This worked in .NET 8 and earlier but silently fails starting with .NET 9 -Person person = new Person { Name = "John", Age = 30 }; -Clipboard.SetData("MyApp.Person", person); // No data is stored - -// Later attempts to retrieve the data return null -object data = Clipboard.GetData("MyApp.Person"); -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs" id="ObsoleteCustomType"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb" id="ObsoleteCustomType"::: #### What you might see @@ -79,32 +69,13 @@ The legacy `GetData()` method is obsolete in .NET 10. Even if it sometimes retur **Obsolete code to avoid:** -```csharp -// Don't use - GetData() is obsolete in .NET 10 -object data = Clipboard.GetData("MyApp.Person"); // Obsolete method - -// Always returns null on a custom object type -if (data != null) -{ - Person person = (Person)data; // Unsafe casting - ProcessPerson(person); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs" id="ObsoleteGetData"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb" id="ObsoleteGetData"::: **Modern approach using TryGetData\<T>():** -```csharp -// Use this - type-safe approach with TryGetData<T>() -if (Clipboard.TryGetData("MyApp.Person", out Person person)) -{ - ProcessPerson(person); // person is guaranteed to be the correct type -} -else -{ - // Handle the case where data isn't available or is the wrong type - ShowError("Unable to retrieve person data from clipboard"); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs" id="ModernTryGetData"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb" id="ModernTryGetData"::: #### Benefits of TryGetData\<T>() @@ -137,59 +108,13 @@ The `TryGetData<T>()` family replaces the obsolete `GetData()` method. It provid #### Basic type-safe retrieval -```csharp -// Retrieve text data using a standard format -if (Clipboard.TryGetData(DataFormats.Text, out string textData)) -{ - ProcessTextData(textData); -} - -// Retrieve an integer using a custom format -if (Clipboard.TryGetData("NumberData", out int numberData)) -{ - ProcessNumber(numberData); -} - -// Retrieve Unicode text using a standard format -if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText)) -{ - ProcessUnicodeText(unicodeText); -} - -// Retrieve raw text data with OLE conversion control -if (Clipboard.TryGetData(DataFormats.Text, autoConvert: false, out string rawText)) -{ - ProcessRawText(rawText); -} - -// Retrieve file drops using a standard format -if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) -{ - ProcessFiles(files); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs" id="BasicTypeSafeRetrieval"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb" id="BasicTypeSafeRetrieval"::: #### Custom JSON types -```csharp -// Retrieve a custom type stored with SetDataAsJson<T>() -if (Clipboard.TryGetData("Person", out Person person)) -{ - ProcessPerson(person); -} - -// Retrieve application-specific data formats -if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings)) -{ - ApplySettings(settings); -} - -// Retrieve complex custom objects -if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) -{ - LoadDocument(doc); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs" id="CustomJsonTypes"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb" id="CustomJsonTypes"::: #### Use a type resolver for legacy binary data (requires BinaryFormatter; not recommended) @@ -198,33 +123,8 @@ if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) Type resolvers let you handle legacy binary data by mapping type names to actual types during deserialization. -```csharp -// Create a type resolver that maps old type names to current types -Func<TypeName, Type> resolver = typeName => -{ - // Only allow specific, known, safe types - return typeName.FullName switch - { - "MyApp.Person" => typeof(Person), - "MyApp.Settings" => typeof(AppSettings), - "System.String" => typeof(string), - "System.Int32" => typeof(int), - _ => throw new InvalidOperationException($"Type not allowed: {typeName.FullName}") - }; -}; - -// Use the resolver with legacy binary data -if (Clipboard.TryGetData("LegacyFormat", resolver, out Person person)) -{ - ProcessPerson(person); -} - -// Use a resolver with conversion control -if (Clipboard.TryGetData("OldCustomData", resolver, autoConvert: true, out MyType data)) -{ - ProcessCustomData(data); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs" id="TypeResolverExample"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb" id="TypeResolverExample"::: **Important security considerations for type resolvers:** @@ -240,31 +140,13 @@ These methods provide automatic JSON serialization using `System.Text.Json` with #### Automatic format inference -```csharp -var person = new Person { Name = "Alice", Age = 25 }; - -// The format is automatically inferred from the type name -Clipboard.SetDataAsJson(person) // Uses "Person" as the format - -// Retrieve the data later -if (Clipboard.TryGetData("Person", out Person retrievedPerson)) -{ - Console.WriteLine($"Retrieved: {retrievedPerson.Name}"); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs" id="AutomaticFormatInference"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb" id="AutomaticFormatInference"::: #### Specify a custom format -```csharp -var settings = new AppSettings { Theme = "Dark", AutoSave = true }; - -// Use a custom format for better organization -Clipboard.SetDataAsJson("MyApp.Settings", settings) - -// Store the same data in multiple formats -Clipboard.SetDataAsJson("Config.V1", settings) -Clipboard.SetDataAsJson("AppConfig", settings) -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs" id="CustomFormat"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb" id="CustomFormat"::: ### ITypedDataObject interface @@ -272,50 +154,13 @@ The <xref:System.Windows.Forms.ITypedDataObject> interface enables type-safe dra #### Implement ITypedDataObject in a custom DataObject -```csharp -public class TypedDataObject : DataObject, ITypedDataObject -{ - public bool TryGetData<T>(string format, out T data) - { - // Use new type-safe logic - return base.TryGetData(format, out data); - } - - // This overload requires BinaryFormatter support (not recommended) - public bool TryGetData<T>(string format, Func<TypeName, Type> resolver, out T data) - { - return base.TryGetData(format, resolver, out data); - } -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs" id="ITypedDataObjectImplementation"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb" id="ITypedDataObjectImplementation"::: #### Use ITypedDataObject in drag-and-drop scenarios -```csharp -private void OnDragDrop(object sender, DragEventArgs e) -{ - if (e.Data is ITypedDataObject typedData) - { - // Retrieve files from drag data using a standard format - if (typedData.TryGetData(DataFormats.FileDrop, out string[] files)) - { - ProcessDroppedFiles(files); - } - - // Retrieve text using a standard format - if (typedData.TryGetData(DataFormats.Text, out string text)) - { - ProcessDroppedText(text); - } - - // Retrieve custom items using an application-specific format - if (typedData.TryGetData("CustomItem", out MyItem item)) - { - ProcessCustomItem(item); - } - } -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs" id="DragDropUsage"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb" id="DragDropUsage"::: ## Types that don't require JSON serialization @@ -352,27 +197,8 @@ The following primitive types work seamlessly with clipboard and `DataObject` op The following examples show how these primitive types work directly with `SetData()` and `TryGetData<T>()` methods: -```csharp -// Numeric types -Clipboard.SetData("MyInt", 42); -Clipboard.SetData("MyDouble", 3.14159); -Clipboard.SetData("MyDecimal", 123.45m); - -// Text and character types -Clipboard.SetData("MyString", "Hello World"); -Clipboard.SetData("MyChar", 'A'); - -// Boolean and date/time types -Clipboard.SetData("MyBool", true); -Clipboard.SetData("MyDateTime", DateTime.Now); -Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)); - -// Later retrieval with type safety -if (Clipboard.TryGetData("MyInt", out int value)) -{ - ProcessInteger(value); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs" id="PrimitiveTypesExample"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb" id="PrimitiveTypesExample"::: ### Collections of primitive types @@ -384,24 +210,8 @@ Arrays and generic lists of supported primitive types work without extra configu The following examples show how arrays and lists can be set on the clipboard: -```csharp -// Arrays of primitive types -int[] numbers = { 1, 2, 3, 4, 5 }; -Clipboard.SetData("NumberArray", numbers); - -double[] coordinates = { 1.0, 2.5, 3.7 }; -Clipboard.SetData("Coordinates", coordinates); - -// Generic lists -List<int> intList = new List<int> { 10, 20, 30 }; -Clipboard.SetData("IntList", intList); - -// Retrieval maintains type safety -if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers)) -{ - ProcessNumbers(retrievedNumbers); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs" id="CollectionsExample"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb" id="CollectionsExample"::: ### System.Drawing types @@ -413,24 +223,8 @@ Common graphics types from the `System.Drawing` namespace work seamlessly with c The following examples show how these graphics types can be used with clipboard operations: -```csharp -// Geometric types -Point location = new Point(100, 200); -Rectangle bounds = new Rectangle(0, 0, 500, 300); -Size dimensions = new Size(800, 600); - -Clipboard.SetData("Location", location); -Clipboard.SetData("Bounds", bounds); -Clipboard.SetData("Size", dimensions); - -// Color information -Color backgroundColor = Color.FromArgb(255, 128, 64, 192); -Clipboard.SetData("BackColor", backgroundColor); - -// Bitmap data (use with caution for large images) -Bitmap smallIcon = new Bitmap(16, 16); -Clipboard.SetData("Icon", smallIcon); -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/SystemDrawingTypesExamples.cs" id="SystemDrawingTypes"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/SystemDrawingTypesExamples.vb" id="SystemDrawingTypes"::: ## Work with custom types @@ -440,26 +234,8 @@ When you use <xref:System.Windows.Forms.Clipboard.SetDataAsJson``1(System.String Most straightforward custom types don't require special configuration: -```csharp -// Records work without any attributes. -public record PersonInfo(string Name, int Age, string Email); - -// Simple classes serialize all public properties automatically. -public class DocumentMetadata -{ - public string Title { get; set; } - public DateTime Created { get; set; } - public string Author { get; set; } -} - -// Structs with public properties work seamlessly. -public struct Point3D -{ - public double X { get; set; } - public double Y { get; set; } - public double Z { get; set; } -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs" id="SimpleCustomTypes"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb" id="SimpleCustomTypes"::: ### Use JSON attributes for advanced control @@ -467,48 +243,13 @@ Use `System.Text.Json` attributes only when you need to customize serialization The following example shows how you can use JSON attributes to control serialization: -```csharp -public class ClipboardFriendlyType -{ - // Include a field that normally isn't serialized - [JsonInclude] - private int _privateData; - - // Public properties are always serialized - public string Name { get; set; } - - // Exclude sensitive or non-essential data - [JsonIgnore] - public string InternalId { get; set; } - - // Handle property name differences for compatibility - [JsonPropertyName("display_text")] - public string DisplayText { get; set; } - - // Control null value handling - [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] - public string OptionalField { get; set; } -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs" id="JsonAttributesExample"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb" id="JsonAttributesExample"::: ### Example: Clipboard operations with custom types -```csharp -var data = new ClipboardFriendlyType -{ - Name = "Sample", - DisplayText = "Sample Display Text", - InternalId = "internal-123" // This property isn't serialized due to [JsonIgnore] -}; - -Clipboard.SetDataAsJson("MyAppData", data); - -if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved)) -{ - Console.WriteLine($"Retrieved: {retrieved.Name}"); - // retrieved.InternalId is null because of [JsonIgnore] -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs" id="CustomTypesClipboardOperations"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb" id="CustomTypesClipboardOperations"::: ## Enable BinaryFormatter support (not recommended) @@ -583,37 +324,8 @@ Even with `BinaryFormatter` enabled, you must implement type resolvers to restri The following example shows a secure type resolver implementation: -```csharp -// Create a security-focused type resolver -private static Type SecureTypeResolver(TypeName typeName) -{ - // Explicit allow-list of permitted types—add only what you need - var allowedTypes = new Dictionary<string, Type> - { - ["MyApp.Person"] = typeof(Person), - ["MyApp.Settings"] = typeof(AppSettings), - ["System.String"] = typeof(string), - ["System.Int32"] = typeof(int), - // Add only the specific types your application requires - }; - - // Only allow explicitly listed types - exact string match required - if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType)) - { - return allowedType; - } - - // Reject any type not in the allow-list with clear error message - throw new InvalidOperationException( - $"Type '{typeName.FullName}' is not permitted for clipboard deserialization"); -} - -// Use the resolver with clipboard operations -if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data)) -{ - ProcessLegacyData(data); -} -``` +:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs" id="SecureTypeResolver"::: +:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb" id="SecureTypeResolver"::: ## Use AI to migrate clipboard code diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs new file mode 100644 index 0000000000..8f6b91b37b --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class BinaryFormatterSupport + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public class AppSettings + { + public string Theme { get; set; } + public bool AutoSave { get; set; } + } + + public class MyCustomType + { + public string Data { get; set; } + } + + // <SecureTypeResolver> + // Create a security-focused type resolver + private static Type SecureTypeResolver(TypeName typeName) + { + // Explicit allow-list of permitted types—add only what you need + var allowedTypes = new Dictionary<string, Type> + { + ["MyApp.Person"] = typeof(Person), + ["MyApp.Settings"] = typeof(AppSettings), + ["System.String"] = typeof(string), + ["System.Int32"] = typeof(int), + // Add only the specific types your application requires + }; + + // Only allow explicitly listed types - exact string match required + if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType)) + { + return allowedType; + } + + // Reject any type not in the allow-list with clear error message + throw new InvalidOperationException( + $"Type '{typeName.FullName}' is not permitted for clipboard deserialization"); + } + + // Use the resolver with clipboard operations + public static void UseSecureTypeResolver() + { + if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data)) + { + ProcessLegacyData(data); + } + } + // </SecureTypeResolver> + + private static void ProcessLegacyData(MyCustomType data) + { + Console.WriteLine($"Processing legacy data: {data.Data}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs new file mode 100644 index 0000000000..91921aac8c --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/CustomTypesExamples.cs @@ -0,0 +1,74 @@ +using System; +using System.Text.Json.Serialization; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class CustomTypesExamples + { + // <SimpleCustomTypes> + // Records work without any attributes. + public record PersonInfo(string Name, int Age, string Email); + + // Simple classes serialize all public properties automatically. + public class DocumentMetadata + { + public string Title { get; set; } + public DateTime Created { get; set; } + public string Author { get; set; } + } + + // Structs with public properties work seamlessly. + public struct Point3D + { + public double X { get; set; } + public double Y { get; set; } + public double Z { get; set; } + } + // </SimpleCustomTypes> + + // <JsonAttributesExample> + public class ClipboardFriendlyType + { + // Include a field that normally isn't serialized + [JsonInclude] + private int _privateData; + + // Public properties are always serialized + public string Name { get; set; } + + // Exclude sensitive or non-essential data + [JsonIgnore] + public string InternalId { get; set; } + + // Handle property name differences for compatibility + [JsonPropertyName("display_text")] + public string DisplayText { get; set; } + + // Control null value handling + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public string OptionalField { get; set; } + } + // </JsonAttributesExample> + + // <CustomTypesClipboardOperations> + public static void CustomTypesClipboardOperationsExample() + { + var data = new ClipboardFriendlyType + { + Name = "Sample", + DisplayText = "Sample Display Text", + InternalId = "internal-123" // This property isn't serialized due to [JsonIgnore] + }; + + Clipboard.SetDataAsJson("MyAppData", data); + + if (Clipboard.TryGetData("MyAppData", out ClipboardFriendlyType retrieved)) + { + Console.WriteLine($"Retrieved: {retrieved.Name}"); + // retrieved.InternalId is null because of [JsonIgnore] + } + } + // </CustomTypesClipboardOperations> + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.Designer.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.Designer.cs new file mode 100644 index 0000000000..c23c093ee9 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.Designer.cs @@ -0,0 +1,38 @@ +namespace csharp; + +partial class Form1 +{ + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 450); + Text = "Form1"; + } + + #endregion +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.cs new file mode 100644 index 0000000000..a1158949f6 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.cs @@ -0,0 +1,9 @@ +namespace csharp; + +public partial class Form1 : Form +{ + public Form1() + { + InitializeComponent(); + } +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs new file mode 100644 index 0000000000..3cb97f8aa3 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs @@ -0,0 +1,74 @@ +using System; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + // <ITypedDataObjectImplementation> + public class TypedDataObject : DataObject, ITypedDataObject + { + public new bool TryGetData<T>(string format, out T data) + { + // Use new type-safe logic + return base.TryGetData(format, out data); + } + + // This overload requires BinaryFormatter support (not recommended) + public new bool TryGetData<T>(string format, Func<TypeName, Type> resolver, out T data) + { + data = default(T)!; + return false; // Simplified implementation for example + } + } + // </ITypedDataObjectImplementation> + + public class DragDropExamples + { + public class MyItem + { + public string Name { get; set; } + public string Value { get; set; } + } + + // <DragDropUsage> + private void OnDragDrop(object sender, DragEventArgs e) + { + if (e.Data is ITypedDataObject typedData) + { + // Retrieve files from drag data using a standard format + if (typedData.TryGetData(DataFormats.FileDrop, out string[] files)) + { + ProcessDroppedFiles(files); + } + + // Retrieve text using a standard format + if (typedData.TryGetData(DataFormats.Text, out string text)) + { + ProcessDroppedText(text); + } + + // Retrieve custom items using an application-specific format + if (typedData.TryGetData("CustomItem", out MyItem item)) + { + ProcessCustomItem(item); + } + } + } + // </DragDropUsage> + + private void ProcessDroppedFiles(string[] files) + { + Console.WriteLine($"Dropped files: {string.Join(", ", files)}"); + } + + private void ProcessDroppedText(string text) + { + Console.WriteLine($"Dropped text: {text}"); + } + + private void ProcessCustomItem(MyItem item) + { + Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs new file mode 100644 index 0000000000..b9bb9e017b --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs @@ -0,0 +1,40 @@ +using System; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class ModernApproach + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + // <ModernTryGetData> + public static void ModernTryGetDataExample() + { + // Use this - type-safe approach with TryGetData<T>() + if (Clipboard.TryGetData("MyApp.Person", out Person person)) + { + ProcessPerson(person); // person is guaranteed to be the correct type + } + else + { + // Handle the case where data isn't available or is the wrong type + ShowError("Unable to retrieve person data from clipboard"); + } + } + // </ModernTryGetData> + + private static void ProcessPerson(Person person) + { + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); + } + + private static void ShowError(string message) + { + MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs new file mode 100644 index 0000000000..8945ff2011 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs @@ -0,0 +1,48 @@ +using System; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + // Examples of obsolete patterns that no longer work in .NET 10 + public class ObsoletePatterns + { + // <ObsoleteCustomType> + [Serializable] + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public static void BrokenCustomTypeExample() + { + // This worked in .NET 8 and earlier but silently fails starting with .NET 9 + Person person = new Person { Name = "John", Age = 30 }; + Clipboard.SetData("MyApp.Person", person); // No data is stored + + // Later attempts to retrieve the data return null + object data = Clipboard.GetData("MyApp.Person"); + } + // </ObsoleteCustomType> + + // <ObsoleteGetData> + public static void ObsoleteGetDataExample() + { + // Don't use - GetData() is obsolete in .NET 10 + object data = Clipboard.GetData("MyApp.Person"); // Obsolete method + + // Always returns null on a custom object type + if (data != null) + { + Person person = (Person)data; // Unsafe casting + ProcessPerson(person); + } + } + // </ObsoleteGetData> + + private static void ProcessPerson(Person person) + { + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs new file mode 100644 index 0000000000..9cfa7d19a6 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs @@ -0,0 +1,66 @@ +using System; +using System.Collections.Generic; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class PrimitiveTypesExamples + { + // <PrimitiveTypesExample> + public static void PrimitiveTypesExample() + { + // Numeric types + Clipboard.SetData("MyInt", 42); + Clipboard.SetData("MyDouble", 3.14159); + Clipboard.SetData("MyDecimal", 123.45m); + + // Text and character types + Clipboard.SetData("MyString", "Hello World"); + Clipboard.SetData("MyChar", 'A'); + + // Boolean and date/time types + Clipboard.SetData("MyBool", true); + Clipboard.SetData("MyDateTime", DateTime.Now); + Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)); + + // Later retrieval with type safety + if (Clipboard.TryGetData("MyInt", out int value)) + { + ProcessInteger(value); + } + } + // </PrimitiveTypesExample> + + // <CollectionsExample> + public static void CollectionsExample() + { + // Arrays of primitive types + int[] numbers = { 1, 2, 3, 4, 5 }; + Clipboard.SetData("NumberArray", numbers); + + double[] coordinates = { 1.0, 2.5, 3.7 }; + Clipboard.SetData("Coordinates", coordinates); + + // Generic lists + List<int> intList = new List<int> { 10, 20, 30 }; + Clipboard.SetData("IntList", intList); + + // Retrieval maintains type safety + if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers)) + { + ProcessNumbers(retrievedNumbers); + } + } + // </CollectionsExample> + + private static void ProcessInteger(int value) + { + Console.WriteLine($"Integer value: {value}"); + } + + private static void ProcessNumbers(int[] numbers) + { + Console.WriteLine($"Numbers: {string.Join(", ", numbers)}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Program.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Program.cs new file mode 100644 index 0000000000..4db135f19c --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Program.cs @@ -0,0 +1,16 @@ +namespace csharp; + +static class Program +{ + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Form1()); + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs new file mode 100644 index 0000000000..fcceb52777 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SetDataAsJsonExamples.cs @@ -0,0 +1,50 @@ +using System; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class SetDataAsJsonExamples + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public class AppSettings + { + public string Theme { get; set; } + public bool AutoSave { get; set; } + } + + // <AutomaticFormatInference> + public static void AutomaticFormatInferenceExample() + { + var person = new Person { Name = "Alice", Age = 25 }; + + // The format is automatically inferred from the type name + Clipboard.SetDataAsJson("Person", person); // Uses "Person" as the format + + // Retrieve the data later + if (Clipboard.TryGetData("Person", out Person retrievedPerson)) + { + Console.WriteLine($"Retrieved: {retrievedPerson.Name}"); + } + } + // </AutomaticFormatInference> + + // <CustomFormat> + public static void CustomFormatExample() + { + var settings = new AppSettings { Theme = "Dark", AutoSave = true }; + + // Use a custom format for better organization + Clipboard.SetDataAsJson("MyApp.Settings", settings); + + // Store the same data in multiple formats + Clipboard.SetDataAsJson("Config.V1", settings); + Clipboard.SetDataAsJson("AppConfig", settings); + } + // </CustomFormat> + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SystemDrawingTypesExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SystemDrawingTypesExamples.cs new file mode 100644 index 0000000000..7a04bf0cb5 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/SystemDrawingTypesExamples.cs @@ -0,0 +1,31 @@ +using System; +using System.Drawing; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class SystemDrawingTypesExamples + { + // <SystemDrawingTypes> + public static void SystemDrawingTypesExample() + { + // Geometric types + Point location = new Point(100, 200); + Rectangle bounds = new Rectangle(0, 0, 500, 300); + Size dimensions = new Size(800, 600); + + Clipboard.SetData("Location", location); + Clipboard.SetData("Bounds", bounds); + Clipboard.SetData("Size", dimensions); + + // Color information + Color backgroundColor = Color.FromArgb(255, 128, 64, 192); + Clipboard.SetData("BackColor", backgroundColor); + + // Bitmap data (use with caution for large images) + Bitmap smallIcon = new Bitmap(16, 16); + Clipboard.SetData("Icon", smallIcon); + } + // </SystemDrawingTypes> + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs new file mode 100644 index 0000000000..71567797f1 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs @@ -0,0 +1,67 @@ +using System; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class TypeResolver + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public class AppSettings + { + public string Theme { get; set; } + public bool AutoSave { get; set; } + } + + public class MyType + { + public string Data { get; set; } + } + + // <TypeResolverExample> + public static void TypeResolverExample() + { + // Create a type resolver that maps old type names to current types + Func<TypeName, Type> resolver = typeName => + { + // Only allow specific, known, safe types + return typeName.FullName switch + { + "MyApp.Person" => typeof(Person), + "MyApp.Settings" => typeof(AppSettings), + "System.String" => typeof(string), + "System.Int32" => typeof(int), + _ => throw new InvalidOperationException($"Type not allowed: {typeName.FullName}") + }; + }; + + // Use the resolver with legacy binary data + if (Clipboard.TryGetData("LegacyFormat", resolver, out Person person)) + { + ProcessPerson(person); + } + + // Use a resolver with conversion control + if (Clipboard.TryGetData("OldCustomData", resolver, out MyType data)) + { + ProcessCustomData(data); + } + } + // </TypeResolverExample> + + private static void ProcessPerson(Person person) + { + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); + } + + private static void ProcessCustomData(MyType data) + { + Console.WriteLine($"Processing custom data: {data.Data}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs new file mode 100644 index 0000000000..3cf6709a03 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs @@ -0,0 +1,94 @@ +using System; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class TypeSafeRetrieval + { + // <BasicTypeSafeRetrieval> + public static void BasicTypeSafeRetrievalExamples() + { + // Retrieve text data using a standard format + if (Clipboard.TryGetData(DataFormats.Text, out string textData)) + { + ProcessTextData(textData); + } + + // Retrieve an integer using a custom format + if (Clipboard.TryGetData("NumberData", out int numberData)) + { + ProcessNumber(numberData); + } + + // Retrieve Unicode text using a standard format + if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText)) + { + ProcessUnicodeText(unicodeText); + } + + // Retrieve raw text data with OLE conversion control + if (Clipboard.TryGetData(DataFormats.Text, out string rawText)) + { + ProcessRawText(rawText); + } + + // Retrieve file drops using a standard format + if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) + { + ProcessFiles(files); + } + } + // </BasicTypeSafeRetrieval> + + // <CustomJsonTypes> + public static void CustomJsonTypesExamples() + { + // Retrieve a custom type stored with SetDataAsJson<T>() + if (Clipboard.TryGetData("Person", out Person person)) + { + ProcessPerson(person); + } + + // Retrieve application-specific data formats + if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings)) + { + ApplySettings(settings); + } + + // Retrieve complex custom objects + if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) + { + LoadDocument(doc); + } + } + // </CustomJsonTypes> + + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public class AppSettings + { + public string Theme { get; set; } + public bool AutoSave { get; set; } + } + + public class DocumentInfo + { + public string Title { get; set; } + public string Author { get; set; } + public DateTime Created { get; set; } + } + + private static void ProcessTextData(string text) => Console.WriteLine($"Text: {text}"); + private static void ProcessNumber(int number) => Console.WriteLine($"Number: {number}"); + private static void ProcessUnicodeText(string text) => Console.WriteLine($"Unicode: {text}"); + private static void ProcessRawText(string text) => Console.WriteLine($"Raw: {text}"); + private static void ProcessFiles(string[] files) => Console.WriteLine($"Files: {string.Join(", ", files)}"); + private static void ProcessPerson(Person person) => Console.WriteLine($"Person: {person.Name}"); + private static void ApplySettings(AppSettings settings) => Console.WriteLine($"Settings: {settings.Theme}"); + private static void LoadDocument(DocumentInfo doc) => Console.WriteLine($"Document: {doc.Title}"); + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/csharp.csproj b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/csharp.csproj new file mode 100644 index 0000000000..5151c0a87e --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/csharp.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <Nullable>enable</Nullable> + <UseWindowsForms>true</UseWindowsForms> + <ImplicitUsings>enable</ImplicitUsings> + </PropertyGroup> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb new file mode 100644 index 0000000000..012547f249 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb @@ -0,0 +1,58 @@ +Imports System +Imports System.Collections.Generic +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class BinaryFormatterSupport + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Class AppSettings + Public Property Theme As String + Public Property AutoSave As Boolean + End Class + + Public Class MyCustomType + Public Property Data As String + End Class + + ' <SecureTypeResolver> + ' Create a security-focused type resolver + Private Shared Function SecureTypeResolver(typeName As TypeName) As Type + ' Explicit allow-list of permitted types—add only what you need + Dim allowedTypes As New Dictionary(Of String, Type) From { + {"MyApp.Person", GetType(Person)}, + {"MyApp.Settings", GetType(AppSettings)}, + {"System.String", GetType(String)}, + {"System.Int32", GetType(Integer)} + } + ' Add only the specific types your application requires + + ' Only allow explicitly listed types - exact string match required + Dim allowedType As Type = Nothing + If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then + Return allowedType + End If + + ' Reject any type not in the allow-list with clear error message + Throw New InvalidOperationException( + $"Type '{typeName.FullName}' is not permitted for clipboard deserialization") + End Function + + ' Use the resolver with clipboard operations + Public Shared Sub UseSecureTypeResolver() + Dim data As MyCustomType = Nothing + If Clipboard.TryGetData("LegacyData", AddressOf SecureTypeResolver, data) Then + ProcessLegacyData(data) + End If + End Sub + ' </SecureTypeResolver> + + Private Shared Sub ProcessLegacyData(data As MyCustomType) + Console.WriteLine($"Processing legacy data: {data.Data}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb new file mode 100644 index 0000000000..7b886ae49b --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb @@ -0,0 +1,77 @@ +Imports System +Imports System.Text.Json.Serialization +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class CustomTypesExamples + ' <SimpleCustomTypes> + ' Records work without any attributes. + Public Structure PersonInfo + Public Sub New(name As String, age As Integer, email As String) + Me.Name = name + Me.Age = age + Me.Email = email + End Sub + + Public Property Name As String + Public Property Age As Integer + Public Property Email As String + End Structure + + ' Simple classes serialize all public properties automatically. + Public Class DocumentMetadata + Public Property Title As String + Public Property Created As DateTime + Public Property Author As String + End Class + + ' Structs with public properties work seamlessly. + Public Structure Point3D + Public Property X As Double + Public Property Y As Double + Public Property Z As Double + End Structure + ' </SimpleCustomTypes> + + ' <JsonAttributesExample> + Public Class ClipboardFriendlyType + ' Include a field that normally isn't serialized + <JsonInclude> + Private _privateData As Integer + + ' Public properties are always serialized + Public Property Name As String + + ' Exclude sensitive or non-essential data + <JsonIgnore> + Public Property InternalId As String + + ' Handle property name differences for compatibility + <JsonPropertyName("display_text")> + Public Property DisplayText As String + + ' Control null value handling + <JsonIgnore(Condition:=JsonIgnoreCondition.WhenWritingNull)> + Public Property OptionalField As String + End Class + ' </JsonAttributesExample> + + ' <CustomTypesClipboardOperations> + Public Shared Sub CustomTypesClipboardOperationsExample() + Dim data As New ClipboardFriendlyType With { + .Name = "Sample", + .DisplayText = "Sample Display Text", + .InternalId = "internal-123" ' This property isn't serialized due to <JsonIgnore> + } + + Clipboard.SetDataAsJson("MyAppData", data) + + Dim retrieved As ClipboardFriendlyType = Nothing + If Clipboard.TryGetData("MyAppData", retrieved) Then + Console.WriteLine($"Retrieved: {retrieved.Name}") + ' retrieved.InternalId is null because of <JsonIgnore> + End If + End Sub + ' </CustomTypesClipboardOperations> + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.Designer.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.Designer.vb new file mode 100644 index 0000000000..0a21f031de --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.Designer.vb @@ -0,0 +1,31 @@ +<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> +Partial Class Form1 + Inherits System.Windows.Forms.Form + + 'Form overrides dispose to clean up the component list. + <System.Diagnostics.DebuggerNonUserCode()> + Protected Overrides Sub Dispose(disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + <System.Diagnostics.DebuggerStepThrough()> + Private Sub InitializeComponent() + components = New System.ComponentModel.Container() + AutoScaleMode = AutoScaleMode.Font + ClientSize = New Size(800, 450) + Text = "Form1" + End Sub + +End Class diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.vb new file mode 100644 index 0000000000..17d659563f --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Form1.vb @@ -0,0 +1,3 @@ +Public Class Form1 + +End Class diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb new file mode 100644 index 0000000000..97b4f98f23 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb @@ -0,0 +1,68 @@ +Imports System +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + ' <ITypedDataObjectImplementation> + Public Class TypedDataObject + Inherits DataObject + Implements ITypedDataObject + + Public Overloads Function TryGetData(Of T)(format As String, ByRef data As T) As Boolean Implements ITypedDataObject.TryGetData + ' Use new type-safe logic + Return MyBase.TryGetData(format, data) + End Function + + ' This overload requires BinaryFormatter support (not recommended) + Public Overloads Function TryGetData(Of T)(format As String, resolver As Func(Of TypeName, Type), ByRef data As T) As Boolean + data = Nothing + Return False ' Simplified implementation for example + End Function + End Class + ' </ITypedDataObjectImplementation> + + Public Class DragDropExamples + Public Class MyItem + Public Property Name As String + Public Property Value As String + End Class + + ' <DragDropUsage> + Private Sub OnDragDrop(sender As Object, e As DragEventArgs) + If TypeOf e.Data Is ITypedDataObject Then + Dim typedData As ITypedDataObject = CType(e.Data, ITypedDataObject) + + ' Retrieve files from drag data using a standard format + Dim files As String() = Nothing + If typedData.TryGetData(DataFormats.FileDrop, files) Then + ProcessDroppedFiles(files) + End If + + ' Retrieve text using a standard format + Dim text As String = Nothing + If typedData.TryGetData(DataFormats.Text, text) Then + ProcessDroppedText(text) + End If + + ' Retrieve custom items using an application-specific format + Dim item As MyItem = Nothing + If typedData.TryGetData("CustomItem", item) Then + ProcessCustomItem(item) + End If + End If + End Sub + ' </DragDropUsage> + + Private Sub ProcessDroppedFiles(files As String()) + Console.WriteLine($"Dropped files: {String.Join(", ", files)}") + End Sub + + Private Sub ProcessDroppedText(text As String) + Console.WriteLine($"Dropped text: {text}") + End Sub + + Private Sub ProcessCustomItem(item As MyItem) + Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb new file mode 100644 index 0000000000..d490f6a309 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb @@ -0,0 +1,32 @@ +Imports System +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class ModernApproach + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + ' <ModernTryGetData> + Public Shared Sub ModernTryGetDataExample() + ' Use this - type-safe approach with TryGetData(Of T)() + Dim person As Person = Nothing + If Clipboard.TryGetData("MyApp.Person", person) Then + ProcessPerson(person) ' person is guaranteed to be the correct type + Else + ' Handle the case where data isn't available or is the wrong type + ShowError("Unable to retrieve person data from clipboard") + End If + End Sub + ' </ModernTryGetData> + + Private Shared Sub ProcessPerson(person As Person) + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") + End Sub + + Private Shared Sub ShowError(message As String) + MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb new file mode 100644 index 0000000000..40406818d9 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb @@ -0,0 +1,41 @@ +Imports System +Imports System.Windows.Forms + +Namespace ClipboardExamples + ' Examples of obsolete patterns that no longer work in .NET 10 + Public Class ObsoletePatterns + ' <ObsoleteCustomType> + <Serializable> + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Shared Sub BrokenCustomTypeExample() + ' This worked in .NET 8 and earlier but silently fails starting with .NET 9 + Dim person As New Person With {.Name = "John", .Age = 30} + Clipboard.SetData("MyApp.Person", person) ' No data is stored + + ' Later attempts to retrieve the data return null + Dim data As Object = Clipboard.GetData("MyApp.Person") + End Sub + ' </ObsoleteCustomType> + + ' <ObsoleteGetData> + Public Shared Sub ObsoleteGetDataExample() + ' Don't use - GetData() is obsolete in .NET 10 + Dim data As Object = Clipboard.GetData("MyApp.Person") ' Obsolete method + + ' Always returns null on a custom object type + If data IsNot Nothing Then + Dim person As Person = CType(data, Person) ' Unsafe casting + ProcessPerson(person) + End If + End Sub + ' </ObsoleteGetData> + + Private Shared Sub ProcessPerson(person As Person) + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb new file mode 100644 index 0000000000..25fefa5c73 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb @@ -0,0 +1,60 @@ +Imports System +Imports System.Collections.Generic +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class PrimitiveTypesExamples + ' <PrimitiveTypesExample> + Public Shared Sub PrimitiveTypesExample() + ' Numeric types + Clipboard.SetData("MyInt", 42) + Clipboard.SetData("MyDouble", 3.14159) + Clipboard.SetData("MyDecimal", 123.45D) + + ' Text and character types + Clipboard.SetData("MyString", "Hello World") + Clipboard.SetData("MyChar", "A"c) + + ' Boolean and date/time types + Clipboard.SetData("MyBool", True) + Clipboard.SetData("MyDateTime", DateTime.Now) + Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)) + + ' Later retrieval with type safety + Dim value As Integer + If Clipboard.TryGetData("MyInt", value) Then + ProcessInteger(value) + End If + End Sub + ' </PrimitiveTypesExample> + + ' <CollectionsExample> + Public Shared Sub CollectionsExample() + ' Arrays of primitive types + Dim numbers As Integer() = {1, 2, 3, 4, 5} + Clipboard.SetData("NumberArray", numbers) + + Dim coordinates As Double() = {1.0, 2.5, 3.7} + Clipboard.SetData("Coordinates", coordinates) + + ' Generic lists + Dim intList As New List(Of Integer) From {10, 20, 30} + Clipboard.SetData("IntList", intList) + + ' Retrieval maintains type safety + Dim retrievedNumbers As Integer() = Nothing + If Clipboard.TryGetData("NumberArray", retrievedNumbers) Then + ProcessNumbers(retrievedNumbers) + End If + End Sub + ' </CollectionsExample> + + Private Shared Sub ProcessInteger(value As Integer) + Console.WriteLine($"Integer value: {value}") + End Sub + + Private Shared Sub ProcessNumbers(numbers As Integer()) + Console.WriteLine($"Numbers: {String.Join(", ", numbers)}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Program.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Program.vb new file mode 100644 index 0000000000..236767207e --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/Program.vb @@ -0,0 +1,11 @@ +Friend Module Program + + <STAThread()> + Friend Sub Main(args As String()) + Application.SetHighDpiMode(HighDpiMode.SystemAware) + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New Form1) + End Sub + +End Module diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb new file mode 100644 index 0000000000..1f9f076d62 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SetDataAsJsonExamples.vb @@ -0,0 +1,44 @@ +Imports System +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class SetDataAsJsonExamples + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Class AppSettings + Public Property Theme As String + Public Property AutoSave As Boolean + End Class + + ' <AutomaticFormatInference> + Public Shared Sub AutomaticFormatInferenceExample() + Dim person As New Person With {.Name = "Alice", .Age = 25} + + ' The format is automatically inferred from the type name + Clipboard.SetDataAsJson("Person", person) ' Uses "Person" as the format + + ' Retrieve the data later + Dim retrievedPerson As Person = Nothing + If Clipboard.TryGetData("Person", retrievedPerson) Then + Console.WriteLine($"Retrieved: {retrievedPerson.Name}") + End If + End Sub + ' </AutomaticFormatInference> + + ' <CustomFormat> + Public Shared Sub CustomFormatExample() + Dim settings As New AppSettings With {.Theme = "Dark", .AutoSave = True} + + ' Use a custom format for better organization + Clipboard.SetDataAsJson("MyApp.Settings", settings) + + ' Store the same data in multiple formats + Clipboard.SetDataAsJson("Config.V1", settings) + Clipboard.SetDataAsJson("AppConfig", settings) + End Sub + ' </CustomFormat> + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SystemDrawingTypesExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SystemDrawingTypesExamples.vb new file mode 100644 index 0000000000..8d1c3c1de2 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/SystemDrawingTypesExamples.vb @@ -0,0 +1,28 @@ +Imports System +Imports System.Drawing +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class SystemDrawingTypesExamples + ' <SystemDrawingTypes> + Public Shared Sub SystemDrawingTypesExample() + ' Geometric types + Dim location As New Point(100, 200) + Dim bounds As New Rectangle(0, 0, 500, 300) + Dim dimensions As New Size(800, 600) + + Clipboard.SetData("Location", location) + Clipboard.SetData("Bounds", bounds) + Clipboard.SetData("Size", dimensions) + + ' Color information + Dim backgroundColor As Color = Color.FromArgb(255, 128, 64, 192) + Clipboard.SetData("BackColor", backgroundColor) + + ' Bitmap data (use with caution for large images) + Dim smallIcon As New Bitmap(16, 16) + Clipboard.SetData("Icon", smallIcon) + End Sub + ' </SystemDrawingTypes> + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb new file mode 100644 index 0000000000..490eb24a19 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb @@ -0,0 +1,62 @@ +Imports System +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class TypeResolver + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Class AppSettings + Public Property Theme As String + Public Property AutoSave As Boolean + End Class + + Public Class MyType + Public Property Data As String + End Class + + ' <TypeResolverExample> + Public Shared Sub TypeResolverExample() + ' Create a type resolver that maps old type names to current types + Dim resolver As Func(Of TypeName, Type) = Function(typeName) + ' Only allow specific, known, safe types + Select Case typeName.FullName + Case "MyApp.Person" + Return GetType(Person) + Case "MyApp.Settings" + Return GetType(AppSettings) + Case "System.String" + Return GetType(String) + Case "System.Int32" + Return GetType(Integer) + Case Else + Throw New InvalidOperationException($"Type not allowed: {typeName.FullName}") + End Select + End Function + + ' Use the resolver with legacy binary data + Dim person As Person = Nothing + If Clipboard.TryGetData("LegacyFormat", resolver, person) Then + ProcessPerson(person) + End If + + ' Use a resolver with conversion control + Dim data As MyType = Nothing + If Clipboard.TryGetData("OldCustomData", resolver, data) Then + ProcessCustomData(data) + End If + End Sub + ' </TypeResolverExample> + + Private Shared Sub ProcessPerson(person As Person) + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") + End Sub + + Private Shared Sub ProcessCustomData(data As MyType) + Console.WriteLine($"Processing custom data: {data.Data}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb new file mode 100644 index 0000000000..20c32f7c37 --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb @@ -0,0 +1,110 @@ +Imports System +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class TypeSafeRetrieval + ' <BasicTypeSafeRetrieval> + Public Shared Sub BasicTypeSafeRetrievalExamples() + ' Retrieve text data using a standard format + Dim textData As String = Nothing + If Clipboard.TryGetData(DataFormats.Text, textData) Then + ProcessTextData(textData) + End If + + ' Retrieve an integer using a custom format + Dim numberData As Integer + If Clipboard.TryGetData("NumberData", numberData) Then + ProcessNumber(numberData) + End If + + ' Retrieve Unicode text using a standard format + Dim unicodeText As String = Nothing + If Clipboard.TryGetData(DataFormats.UnicodeText, unicodeText) Then + ProcessUnicodeText(unicodeText) + End If + + ' Retrieve raw text data with OLE conversion control + Dim rawText As String = Nothing + If Clipboard.TryGetData(DataFormats.Text, rawText) Then + ProcessRawText(rawText) + End If + + ' Retrieve file drops using a standard format + Dim files As String() = Nothing + If Clipboard.TryGetData(DataFormats.FileDrop, files) Then + ProcessFiles(files) + End If + End Sub + ' </BasicTypeSafeRetrieval> + + ' <CustomJsonTypes> + Public Shared Sub CustomJsonTypesExamples() + ' Retrieve a custom type stored with SetDataAsJson(Of T)() + Dim person As Person = Nothing + If Clipboard.TryGetData("Person", person) Then + ProcessPerson(person) + End If + + ' Retrieve application-specific data formats + Dim settings As AppSettings = Nothing + If Clipboard.TryGetData("MyApp.Settings", settings) Then + ApplySettings(settings) + End If + + ' Retrieve complex custom objects + Dim doc As DocumentInfo = Nothing + If Clipboard.TryGetData("DocumentData", doc) Then + LoadDocument(doc) + End If + End Sub + ' </CustomJsonTypes> + + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Class AppSettings + Public Property Theme As String + Public Property AutoSave As Boolean + End Class + + Public Class DocumentInfo + Public Property Title As String + Public Property Author As String + Public Property Created As DateTime + End Class + + Private Shared Sub ProcessTextData(text As String) + Console.WriteLine($"Text: {text}") + End Sub + + Private Shared Sub ProcessNumber(number As Integer) + Console.WriteLine($"Number: {number}") + End Sub + + Private Shared Sub ProcessUnicodeText(text As String) + Console.WriteLine($"Unicode: {text}") + End Sub + + Private Shared Sub ProcessRawText(text As String) + Console.WriteLine($"Raw: {text}") + End Sub + + Private Shared Sub ProcessFiles(files As String()) + Console.WriteLine($"Files: {String.Join(", ", files)}") + End Sub + + Private Shared Sub ProcessPerson(person As Person) + Console.WriteLine($"Person: {person.Name}") + End Sub + + Private Shared Sub ApplySettings(settings As AppSettings) + Console.WriteLine($"Settings: {settings.Theme}") + End Sub + + Private Shared Sub LoadDocument(doc As DocumentInfo) + Console.WriteLine($"Document: {doc.Title}") + End Sub + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/vb.vbproj b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/vb.vbproj new file mode 100644 index 0000000000..9870ed665a --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/vb.vbproj @@ -0,0 +1,17 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <RootNamespace>vb</RootNamespace> + <StartupObject>Sub Main</StartupObject> + <UseWindowsForms>true</UseWindowsForms> + </PropertyGroup> + + <ItemGroup> + <Import Include="System.Data" /> + <Import Include="System.Drawing" /> + <Import Include="System.Windows.Forms" /> + </ItemGroup> + +</Project> \ No newline at end of file From 076b6d7e0e145698fc2bd23d5949ac4282cf8bb0 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:17:03 -0700 Subject: [PATCH 38/51] Update instructions --- .../Plans.ClipboardWork.instructions.md | 5 +- .../Editing.FullPass.prompt.md} | 11 ++- .github/prompts/ValidateTemplate.prompt.md | 97 +++++++++++++++++++ .gitignore | 1 - 4 files changed, 110 insertions(+), 4 deletions(-) rename .github/{instructions/Editing.FullPass.instructions.md => prompts/Editing.FullPass.prompt.md} (94%) create mode 100644 .github/prompts/ValidateTemplate.prompt.md diff --git a/.github/instructions/Plans.ClipboardWork.instructions.md b/.github/instructions/Plans.ClipboardWork.instructions.md index c091ab37e9..1e65c45404 100644 --- a/.github/instructions/Plans.ClipboardWork.instructions.md +++ b/.github/instructions/Plans.ClipboardWork.instructions.md @@ -104,15 +104,16 @@ The .NET 10 release introduces significant changes to the Windows Forms clipboar - Cross-process/cross-framework compatibility - **Priority**: Medium -#### 3.3 New Article: `how-to-enable-binaryformatter-clipboard-support.md` +#### 3.3 New Article: `how-to-enable-binaryformatter-clipboard-support.md` ✅ -- **Template**: How-to article +- **Template**: How-to article (COMPLETED) - **Content Focus**: - Complete guide for legacy application migration - Runtime configuration steps - Security considerations and risks - Type resolver implementation examples - **Priority**: Medium (for legacy support) +- **Status**: Completed ### Phase 4: Navigation and Discoverability Updates diff --git a/.github/instructions/Editing.FullPass.instructions.md b/.github/prompts/Editing.FullPass.prompt.md similarity index 94% rename from .github/instructions/Editing.FullPass.instructions.md rename to .github/prompts/Editing.FullPass.prompt.md index f04a7ae5c1..312a0915f2 100644 --- a/.github/instructions/Editing.FullPass.instructions.md +++ b/.github/prompts/Editing.FullPass.prompt.md @@ -1,5 +1,7 @@ --- -description: Edit the content according to the Microsoft Style Guide +model: Claude Sonnet 4 (copilot) +mode: agent +description: "Performs comprehensive editing pass following Microsoft Style Guide" --- # Article Editing Instructions for LLMs @@ -68,6 +70,13 @@ When editing, focus on these areas in order of priority: - ❌ "You would see the result" → ✅ "You see the result" - Look for ANY pattern with: "will/would/shall + verb" in descriptions +**SCAN FOR AND CONVERT ALL present perfect tense with simple present tense (these are examples - find ALL similar patterns):** +- ❌ "The system has processed the data" → ✅ "The system processes the data" +- ❌ "You have configured the settings" → ✅ "Configure the settings" +- ❌ "The service has been running" → ✅ "The service runs" +- ❌ "Once you have completed the setup" → ✅ "Once you complete the setup" +- Look for ANY pattern with: "have/has + past participle", "have/has been + verb-ing" + **SCAN FOR AND ELIMINATE ALL weak constructions (these are examples - find ALL similar patterns):** - ❌ "There are three ways to..." → ✅ "Use these three methods..." - ❌ "It's possible to..." → ✅ "You can..." or start with the action diff --git a/.github/prompts/ValidateTemplate.prompt.md b/.github/prompts/ValidateTemplate.prompt.md new file mode 100644 index 0000000000..1a520f8a3c --- /dev/null +++ b/.github/prompts/ValidateTemplate.prompt.md @@ -0,0 +1,97 @@ +--- +model: GPT-4o (copilot) +mode: agent +description: "Validates article structure against appropriate templates" +--- + +# Template Validation Prompt + +You are tasked with validating that the current Markdown documentation file conforms to the appropriate article template from `/.github/projects/article-templates/`. + +- **IMPORTANT**: Template files contain XML comments (`<!-- ... -->`) that provide crucial instructions. You must read and apply these instructions during validation. + +## Validation Workflow + +### Step 1: Identify Article Type +Analyze the current article to determine its type: +- Examine `ms.topic` frontmatter value +- Review content structure and purpose +- Consider file naming conventions +- Assess target audience and use case + +### Step 2: Select and Read Template +- Map the article type to the corresponding template file: + - `how-to` → `template-how-to-guide.md` + - `quickstart` → `template-quickstart.md` + - `tutorial` → `template-tutorial.md` + - `concept` → `template-concept.md` + - `overview` → `template-overview.md` + - `troubleshooting` → `general-troubleshoot.md` + - Other types as defined in the templates directory +- Read the complete template file from `/.github/projects/article-templates/` +- Extract all template requirements and guidelines + +### Step 3: Systematic Validation +Compare the current article against the template across all dimensions: + +#### Frontmatter Analysis +- Check all required frontmatter fields +- Validate field values and formats +- Verify template-specific frontmatter requirements + +#### Structure Validation +- Compare section presence and organization +- Verify heading hierarchy and naming +- Check for required content blocks + +#### Content Pattern Compliance +- Analyze all headers format per template specifications +- Validate introduction patterns +- Check for template-mandated content elements + +#### Consistency Verification +- Ensure title frontmatter aligns with H1 heading +- Verify internal consistency throughout the article +- Check template-specific formatting requirements + +### Step 4: Generate Corrections +For any violations found: +- Reference the specific template requirement +- Provide the exact corrected version +- Explain the rationale based on template guidance +- Preserve the article's core content and intent + +### Step 5: Next Steps and Related Content +- Validate if the article includes a **Next step** or **Related content** section at the end, as per the updated template style. +- If the article contains a **See also** section, ensure it is updated to **Related content** to align with the new guidelines. + +## Execution Instructions + +1. **Read the current article** completely +2. **Determine the article type** using the criteria above +3. **Load the appropriate template** from the templates directory +4. **Extract all template requirements** systematically +5. **Perform comprehensive comparison** across all elements +6. **Document violations** with specific template references +7. **Apply corrections** while maintaining content value + +## Output Requirements + +Provide a structured report including: +- **Article type identified** and reasoning +- **Template file used** for validation +- **Comprehensive violation list** with template citations +- **Specific corrections applied** with before/after examples +- **Summary of structural changes** made + +## Validation Scope + +This process should cover: +- All frontmatter requirements +- Complete structural conformance +- Heading and title formatting +- Required section presence +- Template-specific content patterns +- Internal consistency requirements + +Focus on template fidelity while preserving the article's informational value and purpose. \ No newline at end of file diff --git a/.gitignore b/.gitignore index 81aebf17e6..1a11e6a762 100644 --- a/.gitignore +++ b/.gitignore @@ -68,4 +68,3 @@ Release *.vbproj.user ipch *sdf -article-templates From 3fd65b9ac91040200d47acfe9802e1f4534e6042 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:17:40 -0700 Subject: [PATCH 39/51] Phase 3.3: Complete --- .../article-templates/template-whats-new.md | 84 +++++++++ ...nable-binaryformatter-clipboard-support.md | 164 ++++++++++++++++++ .../net/csharp/ClipboardUsage.cs | 42 +++++ .../net/csharp/SecureTypeResolver.cs | 48 +++++ .../net/csharp/TestConfiguration.cs | 77 ++++++++ ...e-binaryformatter-clipboard-support.csproj | 16 ++ .../net/csharp/runtimeconfig.json | 7 + .../net/vb/ClipboardUsage.vb | 36 ++++ .../net/vb/SecureTypeResolver.vb | 44 +++++ .../net/vb/TestConfiguration.vb | 66 +++++++ ...e-binaryformatter-clipboard-support.vbproj | 14 ++ .../net/vb/runtimeconfig.json | 7 + .../winforms/advanced/toc.yml | 2 + .../migration/clipboard-dataobject-net10.md | 48 +---- 14 files changed, 610 insertions(+), 45 deletions(-) create mode 100644 .github/projects/article-templates/template-whats-new.md create mode 100644 dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json diff --git a/.github/projects/article-templates/template-whats-new.md b/.github/projects/article-templates/template-whats-new.md new file mode 100644 index 0000000000..c4d14d9f05 --- /dev/null +++ b/.github/projects/article-templates/template-whats-new.md @@ -0,0 +1,84 @@ +--- +title: [Follow SEO guidance at +https://review.learn.microsoft.com/en-us/help/platform/seo-meta-title] +description: "[Article description]." +author: [your GitHub alias] +ms.author: [your Microsoft alias or a team alias] +ms.service: learn +ms.topic: whats-new #Don't change. +ms.date: [mm/dd/yyyy] + +#customer intent: As a <role>, I want <what> so that <why>. + +--- + +<!-- -------------------------------------- + +- Use this template with pattern instructions for: + +What's New + +- Before you sign off or merge: + +Remove all comments except the customer intent. + +- Feedback: + +https://aka.ms/patterns-feedback + +--> + +# What's new in [product or documentation set]? + +<!-- Required: Article headline - H1 + +Identify the product or service the article applies to. + +--> + +[Introduce and explain the purpose of the article.] + +<!-- Required: Introductory paragraphs (no heading) + +Write a brief introduction that can help users +determine whether the article is relevant for them +and to describe the concept of a "what's new" +article. + +--> + +## [Feature area, date, or release] + +<!-- Required: New feature sections - H2 + +Use one or more H2 sections to explain what's new +in the product, service, or documentation. Summarize +information about updates. Include links to resources +that provide more information and context. + + +If there are many new features, try to organize them into +a few H2 sections. Consider using a summary table as part +of the introduction or the first H2 section. + +--> + +## Related content + +- [Related article title](link.md) +- [Related article title](link.md) +- [Related article title](link.md) + +<!-- Optional: Related content - H2 + +Consider including a "Related content" H2 section that +lists links to 1 to 3 articles the user might find helpful. + +--> + +<!-- + +Remove all comments except the customer intent +before you sign off or merge to the main branch. + +--> diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md b/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md new file mode 100644 index 0000000000..6b7a14a005 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md @@ -0,0 +1,164 @@ +--- +title: "Enable BinaryFormatter clipboard support (not recommended)" +description: "Learn how to configure legacy BinaryFormatter support for Windows Forms clipboard operations in .NET 10, including security considerations and type resolver implementation." +author: adegeo +ms.author: adegeo +ms.service: dotnet-desktop +ms.topic: how-to +ms.date: 10/02/2025 +dev_langs: + - "csharp" + - "vb" +ai-usage: ai-assisted + +#customer intent: As a Windows Forms developer, I want to enable BinaryFormatter clipboard support for legacy applications so that I can maintain compatibility while migrating to new type-safe APIs. + +--- + +# Enable BinaryFormatter clipboard support (not recommended) + +> [!CAUTION] +> `BinaryFormatter` support isn't recommended. Use it only as a temporary migration bridge for legacy applications that can't immediately migrate to the new type-safe APIs. This approach carries significant security risks. + +This article shows how to configure limited `BinaryFormatter` support for Windows Forms clipboard operations in .NET 10. While `BinaryFormatter` was removed from the runtime in .NET 9 due to security vulnerabilities, restore limited functionality through explicit configuration for legacy applications that need time to migrate. + +For complete migration guidance to the new type-safe APIs, see [Windows Forms clipboard and DataObject changes in .NET 10](../migration/clipboard-dataobject-net10.md). + +> [!WARNING] +> Use this approach only as a temporary bridge while updating your application to use the new type-safe clipboard APIs introduced in .NET 10. + +## Prerequisites + +Before continuing, review these concepts: + +- How your application currently uses `BinaryFormatter` in clipboard operations. +- The security vulnerabilities that led to the removal of `BinaryFormatter`. +- Your migration timeline to the new type-safe clipboard APIs. + +For more information, see these articles: + +- [Deserialization risks in use of BinaryFormatter and related types](/dotnet/standard/serialization/binaryformatter-security-guide) +- [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide) + +## Security warnings and risks + +`BinaryFormatter` is inherently insecure and deprecated for these reasons: + +- **Arbitrary code execution vulnerabilities**: Attackers can execute malicious code during deserialization, exposing your application to remote attacks. +- **Denial of service attacks**: Malicious clipboard data can consume excessive memory or CPU resources, causing crashes or instability. +- **Information disclosure risks**: Attackers might extract sensitive data from memory. +- **No security boundaries**: The format is fundamentally unsafe, and configuration settings can't secure it. + +Enable this support only as a temporary bridge while you update your application to use the new type-safe APIs. + +## Install the compatibility package + +Add the unsupported `BinaryFormatter` compatibility package to your project. This package provides the necessary runtime support for `BinaryFormatter` operations: + +:::code language="xml" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj" id="PackageReference"::: + +> [!NOTE] +> This package is marked as unsupported and deprecated. Use it only for temporary compatibility during migration. + +## Enable unsafe serialization in your project + +Set the `EnableUnsafeBinaryFormatterSerialization` property to `true` in your project file. This property tells the compiler to allow `BinaryFormatter` usage: + +```xml +<PropertyGroup> + <TargetFramework>net10.0</TargetFramework> + <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> +</PropertyGroup> +``` + +Without this setting, your application generates compilation errors when it attempts to use `BinaryFormatter` APIs. + +## Configure the Windows Forms runtime switch + +Create or update your application's `runtimeconfig.json` file to enable the Windows Forms-specific clipboard switch. This configuration allows clipboard operations to fall back to `BinaryFormatter` when necessary: + +:::code language="json" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json"::: + +> [!IMPORTANT] +> Without this specific runtime switch, clipboard operations won't fall back to `BinaryFormatter` even if general serialization support is enabled. This switch is required specifically for Windows Forms clipboard functionality. + +## Implement security-focused type resolvers + +Even with `BinaryFormatter` enabled, implement type resolvers to restrict deserialization to explicitly approved types. Type resolvers provide your only defense against malicious payload attacks. + +### Create a secure type resolver + +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs" id="SecureTypeResolver"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb" id="SecureTypeResolver"::: + +### Use the type resolver with clipboard operations + +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs" id="ClipboardUsage"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb" id="ClipboardUsage"::: + +## Security guidelines for type resolvers + +Follow these essential security guidelines when implementing type resolvers: + +### Use explicit allowlists + +- **Reject by default**: Allow only explicitly listed types. +- **No wildcards**: Avoid pattern matching or namespace-based permissions. +- **Exact matching**: Require exact string matches for type names. + +### Validate all inputs + +- **Type name validation**: Ensure type names match expected formats. +- **Assembly restrictions**: Limit types to known, trusted assemblies. +- **Version checking**: Consider version-specific type restrictions. + +### Handle unknown types securely + +- **Throw exceptions**: Always throw for unauthorized types. +- **Log attempts**: Consider logging unauthorized access attempts. +- **Clear error messages**: Provide specific rejection reasons for debugging. + +### Regular maintenance + +- **Audit regularly**: Review and update the allowed type list. +- **Remove unused types**: Eliminate permissions for types no longer needed. +- **Document decisions**: Maintain clear documentation of why each type is permitted. + +## Test your configuration + +After configuring `BinaryFormatter` support, test your application to ensure it works correctly: + +1. **Verify clipboard operations**: Test both storing and retrieving data with your custom types. +1. **Test type resolver**: Confirm that unauthorized types are properly rejected. +1. **Monitor security**: Watch for any unexpected type resolution attempts. +1. **Performance testing**: Ensure the type resolver doesn't significantly impact performance. + +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs" id="TestConfiguration"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb" id="TestConfiguration"::: + +## Plan your migration strategy + +While `BinaryFormatter` support provides temporary compatibility, develop a migration plan to move to the new type-safe APIs: + +1. **Identify usage**: Catalog all clipboard operations using custom types. +1. **Prioritize migration**: Focus on the most security-sensitive operations first. +1. **Update incrementally**: Migrate one operation at a time to reduce risk. +1. **Test thoroughly**: Ensure new implementations provide equivalent functionality. +1. **Remove BinaryFormatter**: Disable support once migration is complete. + +## Clean up resources + +Once you've migrated to the new type-safe clipboard APIs, remove the `BinaryFormatter` configuration to improve security: + +1. Remove the `System.Runtime.Serialization.Formatters` package reference. +1. Remove the `EnableUnsafeBinaryFormatterSerialization` property from your project file. +1. Remove the `Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization` setting from your `runtimeconfig.json`. +1. Delete type resolver implementations that are no longer needed. + +## Related content + +- [Clipboard and DataObject changes in .NET 10](../migration/clipboard-dataobject-net10.md) +- [How to add data to the Clipboard](how-to-add-data-to-the-clipboard.md) +- [How to retrieve data from the Clipboard](how-to-retrieve-data-from-the-clipboard.md) +- [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide) +- [Deserialization risks in use of BinaryFormatter and related types](/dotnet/standard/serialization/binaryformatter-security-guide) diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs new file mode 100644 index 0000000000..91396ce1b4 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs @@ -0,0 +1,42 @@ +using System; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class ClipboardUsageExample + { + public class MyCustomType + { + public string Data { get; set; } + } + + // <ClipboardUsage> + // Use the resolver with clipboard operations + private static Type SecureTypeResolver(TypeName typeName) + { + // Implementation from SecureTypeResolver example + // ... (allow-list implementation here) + throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted"); + } + + public static void UseSecureTypeResolver() + { + // Retrieve legacy data using the secure type resolver + if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data)) + { + ProcessLegacyData(data); + } + else + { + Console.WriteLine("No compatible data found on clipboard"); + } + } + // </ClipboardUsage> + + private static void ProcessLegacyData(MyCustomType data) + { + Console.WriteLine($"Processing legacy data: {data.Data}"); + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs new file mode 100644 index 0000000000..63f75b4e42 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class SecureTypeResolverExample + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + public class AppSettings + { + public string Theme { get; set; } + public bool AutoSave { get; set; } + } + + // <SecureTypeResolver> + // Create a security-focused type resolver + private static Type SecureTypeResolver(TypeName typeName) + { + // Explicit allow-list of permitted types—add only what you need + var allowedTypes = new Dictionary<string, Type> + { + ["MyApp.Person"] = typeof(Person), + ["MyApp.AppSettings"] = typeof(AppSettings), + ["System.String"] = typeof(string), + ["System.Int32"] = typeof(int), + // Add only the specific types your application requires + }; + + // Only allow explicitly listed types - exact string match required + if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType)) + { + return allowedType; + } + + // Reject any type not in the allow-list with clear error message + throw new InvalidOperationException( + $"Type '{typeName.FullName}' is not permitted for clipboard deserialization"); + } + // </SecureTypeResolver> + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs new file mode 100644 index 0000000000..cbd0f00472 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Reflection.Metadata; +using System.Windows.Forms; + +namespace ClipboardExamples +{ + public class TestConfigurationExample + { + public class Person + { + public string Name { get; set; } + public int Age { get; set; } + } + + // <TestConfiguration> + public static void TestBinaryFormatterConfiguration() + { + // Test data to verify configuration + var testPerson = new Person { Name = "Test User", Age = 30 }; + + try + { + // Test storing data (this should work with proper configuration) + Clipboard.SetData("TestPerson", testPerson); + Console.WriteLine("Successfully stored test data on clipboard"); + + // Test retrieving with type resolver + if (Clipboard.TryGetData("TestPerson", SecureTypeResolver, out Person retrievedPerson)) + { + Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}"); + } + else + { + Console.WriteLine("Failed to retrieve test data"); + } + + // Test that unauthorized types are rejected + try + { + Clipboard.TryGetData("TestPerson", UnauthorizedTypeResolver, out Person _); + Console.WriteLine("ERROR: Unauthorized type was not rejected!"); + } + catch (InvalidOperationException ex) + { + Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}"); + } + } + catch (Exception ex) + { + Console.WriteLine($"Configuration test failed: {ex.Message}"); + } + } + + private static Type SecureTypeResolver(TypeName typeName) + { + var allowedTypes = new Dictionary<string, Type> + { + ["ClipboardExamples.Person"] = typeof(Person), + }; + + if (allowedTypes.TryGetValue(typeName.FullName, out Type allowedType)) + { + return allowedType; + } + + throw new InvalidOperationException($"Type '{typeName.FullName}' is not permitted"); + } + + private static Type UnauthorizedTypeResolver(TypeName typeName) + { + // Intentionally restrictive resolver to test rejection + throw new InvalidOperationException($"No types are permitted by this test resolver"); + } + // </TestConfiguration> + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj new file mode 100644 index 0000000000..ef5394a4a7 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj @@ -0,0 +1,16 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net10.0</TargetFramework> + <UseWindowsForms>true</UseWindowsForms> + <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> + </PropertyGroup> + + <!-- <PackageReference> --> + <ItemGroup> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.0" /> + </ItemGroup> + <!-- </PackageReference> --> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json new file mode 100644 index 0000000000..6a7c3d90bd --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json @@ -0,0 +1,7 @@ +{ + "runtimeOptions": { + "configProperties": { + "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb new file mode 100644 index 0000000000..32c3bb2b53 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb @@ -0,0 +1,36 @@ +Imports System +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class ClipboardUsageExample + + Public Class MyCustomType + Public Property Data As String + End Class + + ' <ClipboardUsage> + ' Use the resolver with clipboard operations + Private Shared Function SecureTypeResolver(typeName As TypeName) As Type + ' Implementation from SecureTypeResolver example + ' ... (allow-list implementation here) + Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted") + End Function + + Public Shared Sub UseSecureTypeResolver() + ' Retrieve legacy data using the secure type resolver + Dim data As MyCustomType = Nothing + If Clipboard.TryGetData("LegacyData", AddressOf SecureTypeResolver, data) Then + ProcessLegacyData(data) + Else + Console.WriteLine("No compatible data found on clipboard") + End If + End Sub + ' </ClipboardUsage> + + Private Shared Sub ProcessLegacyData(data As MyCustomType) + Console.WriteLine($"Processing legacy data: {data.Data}") + End Sub + + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb new file mode 100644 index 0000000000..6a0564b1b1 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb @@ -0,0 +1,44 @@ +Imports System +Imports System.Collections.Generic +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class SecureTypeResolverExample + + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + Public Class AppSettings + Public Property Theme As String + Public Property AutoSave As Boolean + End Class + + ' <SecureTypeResolver> + ' Create a security-focused type resolver + Private Shared Function SecureTypeResolver(typeName As TypeName) As Type + ' Explicit allow-list of permitted types—add only what you need + Dim allowedTypes As New Dictionary(Of String, Type) From { + {"MyApp.Person", GetType(Person)}, + {"MyApp.AppSettings", GetType(AppSettings)}, + {"System.String", GetType(String)}, + {"System.Int32", GetType(Integer)} + ' Add only the specific types your application requires + } + + ' Only allow explicitly listed types - exact string match required + Dim allowedType As Type = Nothing + If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then + Return allowedType + End If + + ' Reject any type not in the allow-list with clear error message + Throw New InvalidOperationException( + $"Type '{typeName.FullName}' is not permitted for clipboard deserialization") + End Function + ' </SecureTypeResolver> + + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb new file mode 100644 index 0000000000..24735137eb --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb @@ -0,0 +1,66 @@ +Imports System +Imports System.Collections.Generic +Imports System.Reflection.Metadata +Imports System.Windows.Forms + +Namespace ClipboardExamples + Public Class TestConfigurationExample + + Public Class Person + Public Property Name As String + Public Property Age As Integer + End Class + + ' <TestConfiguration> + Public Shared Sub TestBinaryFormatterConfiguration() + ' Test data to verify configuration + Dim testPerson As New Person With {.Name = "Test User", .Age = 30} + + Try + ' Test storing data (this should work with proper configuration) + Clipboard.SetData("TestPerson", testPerson) + Console.WriteLine("Successfully stored test data on clipboard") + + ' Test retrieving with type resolver + Dim retrievedPerson As Person = Nothing + If Clipboard.TryGetData("TestPerson", AddressOf SecureTypeResolver, retrievedPerson) Then + Console.WriteLine($"Successfully retrieved: {retrievedPerson.Name}, Age: {retrievedPerson.Age}") + Else + Console.WriteLine("Failed to retrieve test data") + End If + + ' Test that unauthorized types are rejected + Try + Dim testResult As Person = Nothing + Clipboard.TryGetData("TestPerson", AddressOf UnauthorizedTypeResolver, testResult) + Console.WriteLine("ERROR: Unauthorized type was not rejected!") + Catch ex As InvalidOperationException + Console.WriteLine($"SUCCESS: Unauthorized type properly rejected - {ex.Message}") + End Try + + Catch ex As Exception + Console.WriteLine($"Configuration test failed: {ex.Message}") + End Try + End Sub + + Private Shared Function SecureTypeResolver(typeName As TypeName) As Type + Dim allowedTypes As New Dictionary(Of String, Type) From { + {"ClipboardExamples.Person", GetType(Person)} + } + + Dim allowedType As Type = Nothing + If allowedTypes.TryGetValue(typeName.FullName, allowedType) Then + Return allowedType + End If + + Throw New InvalidOperationException($"Type '{typeName.FullName}' is not permitted") + End Function + + Private Shared Function UnauthorizedTypeResolver(typeName As TypeName) As Type + ' Intentionally restrictive resolver to test rejection + Throw New InvalidOperationException($"No types are permitted by this test resolver") + End Function + ' </TestConfiguration> + + End Class +End Namespace \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj new file mode 100644 index 0000000000..8c44faba2f --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj @@ -0,0 +1,14 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>Exe</OutputType> + <TargetFramework>net10.0</TargetFramework> + <UseWindowsForms>true</UseWindowsForms> + <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> + </PropertyGroup> + + <ItemGroup> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.0" /> + </ItemGroup> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json new file mode 100644 index 0000000000..6a7c3d90bd --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json @@ -0,0 +1,7 @@ +{ + "runtimeOptions": { + "configProperties": { + "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true + } + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/toc.yml b/dotnet-desktop-guide/winforms/advanced/toc.yml index 19d11c02fa..369f6bbbd1 100644 --- a/dotnet-desktop-guide/winforms/advanced/toc.yml +++ b/dotnet-desktop-guide/winforms/advanced/toc.yml @@ -330,6 +330,8 @@ items: href: how-to-add-data-to-the-clipboard.md - name: "How to: Retrieve Data from the Clipboard" href: how-to-retrieve-data-from-the-clipboard.md + - name: "How to: Enable BinaryFormatter clipboard support (not recommended)" + href: how-to-enable-binaryformatter-clipboard-support.md - name: Networking in Windows Forms Applications href: networking-in-windows-forms-applications.md - name: Globalizing Windows Forms diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 32024e7361..25a871361e 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -258,7 +258,7 @@ The following example shows how you can use JSON attributes to control serializa If you must continue using `BinaryFormatter` for clipboard operations in .NET 10, enable limited support through explicit configuration. This approach carries significant security risks and requires several steps. -For complete migration guidance, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). +For complete step-by-step instructions, see [How to: Enable BinaryFormatter clipboard support (not recommended)](../advanced/how-to-enable-binaryformatter-clipboard-support.md). For general migration guidance, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ### Security warnings and risks @@ -271,46 +271,7 @@ For complete migration guidance, see the [BinaryFormatter migration guide](/dotn Only enable this support as a temporary bridge while you update your application to use the new type-safe APIs. -### Complete configuration requirements - -Follow these steps to enable `BinaryFormatter` support for clipboard operations: - -1. Install the compatibility package. - - Add the unsupported `BinaryFormatter` compatibility package to your project: - - ```xml - <ItemGroup> - <PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.0" /> - </ItemGroup> - ``` - -1. Enable unsafe serialization in your project file. - - Set the `EnableUnsafeBinaryFormatterSerialization` property to `true` in your project file: - - ```xml - <PropertyGroup> - <TargetFramework>net10.0</TargetFramework> - <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> - </PropertyGroup> - ``` - -1. Configure the Windows Forms runtime switch. - - Create or update your application's `runtimeconfig.json` file to enable the Windows Forms-specific clipboard switch: - - ```json - { - "runtimeOptions": { - "configProperties": { - "Windows.ClipboardDragDrop.EnableUnsafeBinaryFormatterSerialization": true - } - } - } - ``` - - Without this switch, clipboard operations won't fall back to `BinaryFormatter` even if general serialization support is enabled. +For detailed security guidelines and configuration steps, see [Security warnings and risks](../advanced/how-to-enable-binaryformatter-clipboard-support.md#security-warnings-and-risks) in the how-to guide. ### Implement security-focused type resolvers @@ -322,10 +283,7 @@ Even with `BinaryFormatter` enabled, you must implement type resolvers to restri - **Throw exceptions for unknown types.** Clearly reject unauthorized types. - **Review regularly.** Audit and update the allowed list as needed. -The following example shows a secure type resolver implementation: - -:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs" id="SecureTypeResolver"::: -:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb" id="SecureTypeResolver"::: +For complete implementation examples and code samples, see [Implement security-focused type resolvers](../advanced/how-to-enable-binaryformatter-clipboard-support.md#implement-security-focused-type-resolvers) in the how-to guide. ## Use AI to migrate clipboard code From 5ec04deb73275d7c01a6cb13e1b7f5045cc147e2 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:37:17 -0700 Subject: [PATCH 40/51] Fix code and move around --- ...nable-binaryformatter-clipboard-support.md | 16 ++++---- .../{net => }/csharp/ClipboardUsage.cs | 0 .../csharp/Form1.Designer.cs | 38 +++++++++++++++++++ .../csharp/Form1.cs | 9 +++++ .../csharp/Program.cs | 16 ++++++++ .../csharp/ProjectCS.csproj | 11 ++++++ .../{net => }/csharp/SecureTypeResolver.cs | 0 .../{net => }/csharp/TestConfiguration.cs | 0 .../{net => }/csharp/runtimeconfig.json | 0 ...e-binaryformatter-clipboard-support.csproj | 16 -------- ...e-binaryformatter-clipboard-support.vbproj | 14 ------- .../{net => }/vb/ClipboardUsage.vb | 0 .../vb/Form1.Designer.vb | 31 +++++++++++++++ .../vb/Form1.vb | 3 ++ .../vb/Program.vb | 11 ++++++ .../vb/ProjectVB.vbproj | 17 +++++++++ .../{net => }/vb/SecureTypeResolver.vb | 3 +- .../{net => }/vb/TestConfiguration.vb | 0 .../{net => }/vb/runtimeconfig.json | 0 19 files changed, 145 insertions(+), 40 deletions(-) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/csharp/ClipboardUsage.cs (100%) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.Designer.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Program.cs create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/csharp/SecureTypeResolver.cs (100%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/csharp/TestConfiguration.cs (100%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/csharp/runtimeconfig.json (100%) delete mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj delete mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/vb/ClipboardUsage.vb (100%) create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.Designer.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Program.vb create mode 100644 dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/vb/SecureTypeResolver.vb (94%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/vb/TestConfiguration.vb (100%) rename dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/{net => }/vb/runtimeconfig.json (100%) diff --git a/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md b/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md index 6b7a14a005..9697d99344 100644 --- a/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md +++ b/dotnet-desktop-guide/winforms/advanced/how-to-enable-binaryformatter-clipboard-support.md @@ -55,7 +55,7 @@ Enable this support only as a temporary bridge while you update your application Add the unsupported `BinaryFormatter` compatibility package to your project. This package provides the necessary runtime support for `BinaryFormatter` operations: -:::code language="xml" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj" id="PackageReference"::: +:::code language="xml" source="./snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj" id="PackageReference"::: > [!NOTE] > This package is marked as unsupported and deprecated. Use it only for temporary compatibility during migration. @@ -77,7 +77,7 @@ Without this setting, your application generates compilation errors when it atte Create or update your application's `runtimeconfig.json` file to enable the Windows Forms-specific clipboard switch. This configuration allows clipboard operations to fall back to `BinaryFormatter` when necessary: -:::code language="json" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json"::: +:::code language="json" source="./snippets/how-to-enable-binaryformatter-clipboard-support/csharp/runtimeconfig.json"::: > [!IMPORTANT] > Without this specific runtime switch, clipboard operations won't fall back to `BinaryFormatter` even if general serialization support is enabled. This switch is required specifically for Windows Forms clipboard functionality. @@ -88,13 +88,13 @@ Even with `BinaryFormatter` enabled, implement type resolvers to restrict deseri ### Create a secure type resolver -:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs" id="SecureTypeResolver"::: -:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb" id="SecureTypeResolver"::: +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/csharp/SecureTypeResolver.cs" id="SecureTypeResolver"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/vb/SecureTypeResolver.vb" id="SecureTypeResolver"::: ### Use the type resolver with clipboard operations -:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs" id="ClipboardUsage"::: -:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb" id="ClipboardUsage"::: +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ClipboardUsage.cs" id="ClipboardUsage"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/vb/ClipboardUsage.vb" id="ClipboardUsage"::: ## Security guidelines for type resolvers @@ -133,8 +133,8 @@ After configuring `BinaryFormatter` support, test your application to ensure it 1. **Monitor security**: Watch for any unexpected type resolution attempts. 1. **Performance testing**: Ensure the type resolver doesn't significantly impact performance. -:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs" id="TestConfiguration"::: -:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb" id="TestConfiguration"::: +:::code language="csharp" source="./snippets/how-to-enable-binaryformatter-clipboard-support/csharp/TestConfiguration.cs" id="TestConfiguration"::: +:::code language="vb" source="./snippets/how-to-enable-binaryformatter-clipboard-support/vb/TestConfiguration.vb" id="TestConfiguration"::: ## Plan your migration strategy diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ClipboardUsage.cs similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/ClipboardUsage.cs rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ClipboardUsage.cs diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.Designer.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.Designer.cs new file mode 100644 index 0000000000..ca8ec69d19 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.Designer.cs @@ -0,0 +1,38 @@ +namespace ProjectCS; + +partial class Form1 +{ + /// <summary> + /// Required designer variable. + /// </summary> + private System.ComponentModel.IContainer components = null; + + /// <summary> + /// Clean up any resources being used. + /// </summary> + /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// <summary> + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// </summary> + private void InitializeComponent() + { + components = new System.ComponentModel.Container(); + AutoScaleMode = AutoScaleMode.Font; + ClientSize = new Size(800, 450); + Text = "Form1"; + } + + #endregion +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.cs new file mode 100644 index 0000000000..357af0c6a5 --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Form1.cs @@ -0,0 +1,9 @@ +namespace ProjectCS; + +public partial class Form1 : Form +{ + public Form1() + { + InitializeComponent(); + } +} diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Program.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Program.cs new file mode 100644 index 0000000000..3e3a06d61a --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/Program.cs @@ -0,0 +1,16 @@ +namespace ProjectCS; + +static class Program +{ + /// <summary> + /// The main entry point for the application. + /// </summary> + [STAThread] + static void Main() + { + // To customize application configuration such as set high DPI settings or default font, + // see https://aka.ms/applicationconfiguration. + ApplicationConfiguration.Initialize(); + Application.Run(new Form1()); + } +} \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj new file mode 100644 index 0000000000..5151c0a87e --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj @@ -0,0 +1,11 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <Nullable>enable</Nullable> + <UseWindowsForms>true</UseWindowsForms> + <ImplicitUsings>enable</ImplicitUsings> + </PropertyGroup> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/SecureTypeResolver.cs similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/SecureTypeResolver.cs rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/SecureTypeResolver.cs diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/TestConfiguration.cs similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/TestConfiguration.cs rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/TestConfiguration.cs diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/runtimeconfig.json similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/runtimeconfig.json rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/runtimeconfig.json diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj deleted file mode 100644 index ef5394a4a7..0000000000 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/csharp/how-to-enable-binaryformatter-clipboard-support.csproj +++ /dev/null @@ -1,16 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <OutputType>Exe</OutputType> - <TargetFramework>net10.0</TargetFramework> - <UseWindowsForms>true</UseWindowsForms> - <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> - </PropertyGroup> - - <!-- <PackageReference> --> - <ItemGroup> - <PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.0" /> - </ItemGroup> - <!-- </PackageReference> --> - -</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj deleted file mode 100644 index 8c44faba2f..0000000000 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/how-to-enable-binaryformatter-clipboard-support.vbproj +++ /dev/null @@ -1,14 +0,0 @@ -<Project Sdk="Microsoft.NET.Sdk"> - - <PropertyGroup> - <OutputType>Exe</OutputType> - <TargetFramework>net10.0</TargetFramework> - <UseWindowsForms>true</UseWindowsForms> - <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> - </PropertyGroup> - - <ItemGroup> - <PackageReference Include="System.Runtime.Serialization.Formatters" Version="9.0.0" /> - </ItemGroup> - -</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ClipboardUsage.vb similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/ClipboardUsage.vb rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ClipboardUsage.vb diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.Designer.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.Designer.vb new file mode 100644 index 0000000000..0a21f031de --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.Designer.vb @@ -0,0 +1,31 @@ +<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> +Partial Class Form1 + Inherits System.Windows.Forms.Form + + 'Form overrides dispose to clean up the component list. + <System.Diagnostics.DebuggerNonUserCode()> + Protected Overrides Sub Dispose(disposing As Boolean) + Try + If disposing AndAlso components IsNot Nothing Then + components.Dispose() + End If + Finally + MyBase.Dispose(disposing) + End Try + End Sub + + 'Required by the Windows Form Designer + Private components As System.ComponentModel.IContainer + + 'NOTE: The following procedure is required by the Windows Form Designer + 'It can be modified using the Windows Form Designer. + 'Do not modify it using the code editor. + <System.Diagnostics.DebuggerStepThrough()> + Private Sub InitializeComponent() + components = New System.ComponentModel.Container() + AutoScaleMode = AutoScaleMode.Font + ClientSize = New Size(800, 450) + Text = "Form1" + End Sub + +End Class diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.vb new file mode 100644 index 0000000000..17d659563f --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Form1.vb @@ -0,0 +1,3 @@ +Public Class Form1 + +End Class diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Program.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Program.vb new file mode 100644 index 0000000000..236767207e --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/Program.vb @@ -0,0 +1,11 @@ +Friend Module Program + + <STAThread()> + Friend Sub Main(args As String()) + Application.SetHighDpiMode(HighDpiMode.SystemAware) + Application.EnableVisualStyles() + Application.SetCompatibleTextRenderingDefault(False) + Application.Run(New Form1) + End Sub + +End Module diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj new file mode 100644 index 0000000000..fc40913a5c --- /dev/null +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj @@ -0,0 +1,17 @@ +<Project Sdk="Microsoft.NET.Sdk"> + + <PropertyGroup> + <OutputType>WinExe</OutputType> + <TargetFramework>net10.0-windows</TargetFramework> + <RootNamespace>ProjectVB</RootNamespace> + <StartupObject>Sub Main</StartupObject> + <UseWindowsForms>true</UseWindowsForms> + </PropertyGroup> + + <ItemGroup> + <Import Include="System.Data" /> + <Import Include="System.Drawing" /> + <Import Include="System.Windows.Forms" /> + </ItemGroup> + +</Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/SecureTypeResolver.vb similarity index 94% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/SecureTypeResolver.vb index 6a0564b1b1..a5fa631c12 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/SecureTypeResolver.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/SecureTypeResolver.vb @@ -25,8 +25,7 @@ Namespace ClipboardExamples {"MyApp.AppSettings", GetType(AppSettings)}, {"System.String", GetType(String)}, {"System.Int32", GetType(Integer)} - ' Add only the specific types your application requires - } + } ' Add only the specific types your application requires ' Only allow explicitly listed types - exact string match required Dim allowedType As Type = Nothing diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/TestConfiguration.vb similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/TestConfiguration.vb rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/TestConfiguration.vb diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/runtimeconfig.json similarity index 100% rename from dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/net/vb/runtimeconfig.json rename to dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/runtimeconfig.json From 50c698f14cef78f03c8a808b941f5da3c2bc3263 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:54:10 -0700 Subject: [PATCH 41/51] Fix the projects and ref --- .../csharp/ProjectCS.csproj | 7 +++++++ .../vb/ProjectVB.vbproj | 5 +++++ .../winforms/migration/clipboard-dataobject-net10.md | 10 +++++----- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj index 5151c0a87e..7e650096d4 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj @@ -6,6 +6,13 @@ <Nullable>enable</Nullable> <UseWindowsForms>true</UseWindowsForms> <ImplicitUsings>enable</ImplicitUsings> + <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> </PropertyGroup> + <!-- <PackageReference> --> + <ItemGroup> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0"/> + </ItemGroup> + <!-- </PackageReference> --> + </Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj index fc40913a5c..117dfb332f 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj @@ -6,6 +6,7 @@ <RootNamespace>ProjectVB</RootNamespace> <StartupObject>Sub Main</StartupObject> <UseWindowsForms>true</UseWindowsForms> + <EnableUnsafeBinaryFormatterSerialization>true</EnableUnsafeBinaryFormatterSerialization> </PropertyGroup> <ItemGroup> @@ -14,4 +15,8 @@ <Import Include="System.Windows.Forms" /> </ItemGroup> + <ItemGroup> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0"/> + </ItemGroup> + </Project> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 25a871361e..fc8f6d2a9b 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -37,7 +37,7 @@ Before you continue, review these concepts: For more information, see these articles: -- [BinaryFormatter security guide](/dotnet/standard/serialization/binaryformatter-security-guide). +- [Deserialization risks in use of BinaryFormatter and related types](/dotnet/standard/serialization/binaryformatter-security-guide). - [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ## Breaking changes from BinaryFormatter removal @@ -119,7 +119,7 @@ The `TryGetData<T>()` family replaces the obsolete `GetData()` method. It provid #### Use a type resolver for legacy binary data (requires BinaryFormatter; not recommended) > [!WARNING] -> Type resolvers only work when BinaryFormatter support is enabled, which isn't recommended due to security risks. For more information, see [Enable BinaryFormatter support (not recommended)](#enable-binaryformatter-support-not-recommended). +> Type resolvers only work when BinaryFormatter support is enabled, which isn't recommended due to security risks. For more information, see [Enable BinaryFormatter clipboard support (not recommended)](#enable-binaryformatter-clipboard-support-not-recommended). Type resolvers let you handle legacy binary data by mapping type names to actual types during deserialization. @@ -258,7 +258,7 @@ The following example shows how you can use JSON attributes to control serializa If you must continue using `BinaryFormatter` for clipboard operations in .NET 10, enable limited support through explicit configuration. This approach carries significant security risks and requires several steps. -For complete step-by-step instructions, see [How to: Enable BinaryFormatter clipboard support (not recommended)](../advanced/how-to-enable-binaryformatter-clipboard-support.md). For general migration guidance, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). +For complete step-by-step instructions, see [Enable BinaryFormatter clipboard support (not recommended)](../advanced/how-to-enable-binaryformatter-clipboard-support.md). For general migration guidance, see the [BinaryFormatter migration guide](/dotnet/standard/serialization/binaryformatter-migration-guide/). ### Security warnings and risks @@ -387,8 +387,8 @@ Check for: missing error handling, types that might not serialize properly to JS ## Related content -- [How to: Add Data to the Clipboard](../advanced/how-to-add-data-to-the-clipboard.md) -- [How to: Retrieve Data from the Clipboard](../advanced/how-to-retrieve-data-from-the-clipboard.md) +- [How to add data to the Clipboard](../advanced/how-to-add-data-to-the-clipboard.md) +- [How to retrieve data from the Clipboard](../advanced/how-to-retrieve-data-from-the-clipboard.md) - [Drag-and-Drop Operations and Clipboard Support](../advanced/drag-and-drop-operations-and-clipboard-support.md) - <xref:System.Windows.Forms.Clipboard.SetDataAsJson``1(System.String,``0)?displayProperty=fullName> - <xref:System.Windows.Forms.Clipboard.TryGetData*?displayProperty=fullName> From 0850297e7865cb77950a8b4c79de454c2d08e1c1 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:54:34 -0700 Subject: [PATCH 42/51] Remove temp project files --- .../Plans.ClipboardWork.instructions.md | 204 ------------------ .../clipboard-dataobject-net10-changes.md | 186 ---------------- .../style-copilot-section-instructions.md | 193 ----------------- .../clipboard/temp-clipboard-articles.md | 92 -------- 4 files changed, 675 deletions(-) delete mode 100644 .github/instructions/Plans.ClipboardWork.instructions.md delete mode 100644 .github/projects/clipboard/clipboard-dataobject-net10-changes.md delete mode 100644 .github/projects/clipboard/style-copilot-section-instructions.md delete mode 100644 .github/projects/clipboard/temp-clipboard-articles.md diff --git a/.github/instructions/Plans.ClipboardWork.instructions.md b/.github/instructions/Plans.ClipboardWork.instructions.md deleted file mode 100644 index 1e65c45404..0000000000 --- a/.github/instructions/Plans.ClipboardWork.instructions.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -description: The plan for updating the Clipboard content ---- - -# Plan to Update WinForms Clipboard Documentation for .NET 10 - -## LLM instructions -If you're creating article files, use the [templates](/.github/projects/article-templates/) folder to find a suitable article template. - -IMPORTANT! Add the following files as context: -- [Migration guide for Clipboard in .NET 10](/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md) -- [Engineer's overview on the changes in .NET 10 for Clipboard](/.github/projects/clipboard/clipboard-dataobject-net10-changes.md) -- [BinaryFormatter migration guide](https://learn.microsoft.com/en-us/dotnet/standard/serialization/binaryformatter-migration-guide/) - -## Executive Summary - -The .NET 10 release introduces significant changes to the Windows Forms clipboard and drag-and-drop functionality, primarily driven by the removal of `BinaryFormatter` from the runtime. This requires updating existing documentation and creating new articles to cover the new type-safe APIs, JSON serialization, and migration guidance. - -## Current Documentation Inventory - -### Existing Articles to Update: - -1. **`drag-and-drop-operations-and-clipboard-support.md`** - Main overview article -2. **`how-to-add-data-to-the-clipboard.md`** - Adding data guide -3. **`how-to-retrieve-data-from-the-clipboard.md`** - Retrieving data guide - -## Detailed Update Plan - -### Phase 1: Create New Comprehensive Overview Article ✅ - -**New Article: `clipboard-dataobject-net10.md`** (COMPLETED) - -- **Location**: dontnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md -- **Priority**: High (COMPLETED) -- **Content Focus**: - - Overview of .NET 10 changes and BinaryFormatter removal - - Comparison table: old vs new APIs - - Best practices for type-safe clipboard operations - - Migration guide from legacy methods - - Security improvements and implications -- **Target Audience**: Developers migrating existing applications -- **Estimated Length**: 2,000-2,500 words -- **Status**: Completed - -### Phase 2: Update Existing Core Articles ✅ - -#### 2.1 Update Main Overview (`drag-and-drop-operations-and-clipboard-support.md`) ✅ - -- **Changes Needed**: - - Add .NET 10 compatibility section - - Update introduction to mention new type-safe APIs - - Add links to new migration guide - - Update "In This Section" with new articles -- **Priority**: High -- **Status**: Completed - -#### 2.2 Comprehensive Rewrite (`how-to-add-data-to-the-clipboard.md`) ✅ - -- **Major Changes**: - - Add new section on `SetDataAsJson<T>()` method - - Update best practices to recommend new APIs first - - Add warning about BinaryFormatter deprecation - - Show examples of recommended built-in types - - Add migration examples from old to new methods -- **New Sections**: - - "Adding Custom Types with JSON Serialization" - - "Working with Recommended Built-in Types" - - "Migrating from Legacy SetData Methods" -- **Priority**: High -- **Status**: Completed - -#### 2.3 Comprehensive Rewrite (`how-to-retrieve-data-from-the-clipboard.md`) ✅ - -- **Major Changes**: - - Replace `GetData()` examples with `TryGetData<T>()` methods - - Add type-safe retrieval examples - - Cover resolver patterns for legacy data - - Add error handling best practices -- **New Sections**: - - "Type-Safe Data Retrieval with `TryGetData<T>`" - - "Handling Legacy Binary Data" - - "Working with Custom JSON Types" -- **Priority**: High -- **Status**: Completed - -### Phase 3: Create New Specialized Articles - -#### 3.1 New Article: `how-to-use-typed-clipboard-apis.md` - -- **Template**: How-to article -- **Content Focus**: - - Detailed guide on `TryGetData<T>()` methods - - Examples of all overloads - - Type resolver implementation patterns - - Error handling strategies -- **Priority**: High - -#### 3.2 New Article: `clipboard-json-serialization.md` - -- **Content Focus**: - - Using `SetDataAsJson<T>()` effectively - - System.Text.Json considerations - - Custom type design for clipboard - - Cross-process/cross-framework compatibility -- **Priority**: Medium - -#### 3.3 New Article: `how-to-enable-binaryformatter-clipboard-support.md` ✅ - -- **Template**: How-to article (COMPLETED) -- **Content Focus**: - - Complete guide for legacy application migration - - Runtime configuration steps - - Security considerations and risks - - Type resolver implementation examples -- **Priority**: Medium (for legacy support) -- **Status**: Completed - -### Phase 4: Navigation and Discoverability Updates - -#### 4.1 Update Table of Contents (`toc.yml`) - -- Add new articles to the drag-and-drop section -- Reorganize clipboard articles for better flow -- Add migration guide as featured content - -#### 4.2 Update Cross-References - -- Add xref links between related articles -- Update "See also" sections across all clipboard articles -- Link to BinaryFormatter migration guidance - -## Implementation Timeline - -### Week 1-2: Foundation ✅ - -- [x] Create comprehensive migration overview article -- [x] Update main overview article with .NET 10 references -- [x] Set up new code snippet structure - -### Week 3-4: Core Rewrites ✅ - -- [x] Rewrite "How to: Add Data" article -- [x] Rewrite "How to: Retrieve Data" article -- [x] Create new typed APIs guide - -### Week 5-6: Specialized Content - -- [ ] Create JSON serialization guide -- [ ] Create BinaryFormatter legacy support guide -- [ ] Update security considerations - -### Week 7: Polish and Integration - -- [ ] Update all code snippets -- [ ] Update navigation and cross-references -- [ ] Review and test all examples - -## Quality Assurance Checklist - -### Content Standards - -- [ ] All articles include `ai-usage: ai-generated` frontmatter -- [ ] Follow Microsoft Writing Style Guide -- [ ] Use Oxford commas in all lists -- [ ] Number ordered lists as "1." (not sequential) -- [ ] Use complete sentences in lists with proper punctuation -- [ ] Active voice and second person throughout - -### Technical Standards - -- [ ] All code examples compile and run -- [ ] Both C# and VB.NET examples where appropriate -- [ ] API references use proper xref format -- [ ] Version compatibility clearly documented -- [ ] Security warnings appropriately placed - -### Documentation Architecture - -- [ ] Logical information hierarchy -- [ ] Clear navigation between related topics -- [ ] Appropriate use of includes for shared content -- [ ] SEO-friendly titles and descriptions - -## Success Metrics - -1. **Coverage**: All major .NET 10 clipboard APIs documented -2. **Migration Support**: Clear upgrade path from legacy APIs -3. **Developer Experience**: Easy-to-find, actionable guidance -4. **Code Quality**: All examples follow best practices -5. **Discoverability**: Proper navigation and cross-linking - -## Risk Mitigation - -### Technical Risks - -- **API Changes**: Monitor .NET 10 development for any last-minute API changes -- **Backward Compatibility**: Ensure legacy guidance remains accurate - -### Content Risks - -- **Information Overload**: Balance comprehensive coverage with readability -- **Fragmentation**: Maintain consistent messaging across all articles - -This plan ensures comprehensive coverage of the .NET 10 clipboard changes while maintaining the existing documentation structure and providing clear migration guidance for developers. diff --git a/.github/projects/clipboard/clipboard-dataobject-net10-changes.md b/.github/projects/clipboard/clipboard-dataobject-net10-changes.md deleted file mode 100644 index d5ce5b770f..0000000000 --- a/.github/projects/clipboard/clipboard-dataobject-net10-changes.md +++ /dev/null @@ -1,186 +0,0 @@ -# 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`** in .NET 9 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) \ No newline at end of file diff --git a/.github/projects/clipboard/style-copilot-section-instructions.md b/.github/projects/clipboard/style-copilot-section-instructions.md deleted file mode 100644 index 229b6a7a47..0000000000 --- a/.github/projects/clipboard/style-copilot-section-instructions.md +++ /dev/null @@ -1,193 +0,0 @@ -# Add a Copilot highlight in the docs - -Copilot is a powerful AI tool that speeds up and simplifies complex development tasks. By adding Copilot information to articles in various product and service areas, we can help customers take advantage of this new and powerful tool. -This article provides instructions for identifying suitable articles, the types of scenarios we should target, and guidelines for crafting Copilot usage tips. - -## What is a Copilot highlight? - -A Copilot highlight is a section you add to an article that shows how to use Copilot to speed up or simplify the task that the article focuses on. It showcases a Copilot usage scenario and isn't a marketing pitch. - -A Copilot highlight targeting a specific usage scenario includes: - -- A descriptive section heading, such as "Use GitHub Copilot to serialize to JSON" -- A brief introduction explaining how Copilot can be applied to your scenario -- An example Copilot prompt formatted as a *Copilot-prompt* code block using the `copilot-prompt` value from the [Dev lang taxonomy](metadata-taxonomies/devlang.md). -- An optional Copilot output example -- Mandatory warning text for Copilot usage - -For examples, see [Examples of published Copilot highlights](#examples-of-published-copilot-highlights). - -## Identify potential articles - -You can add a Copilot highlight to any article type, including conceptual and reference articles, but we believe procedural articles are a good place to start. Use this set of criteria to identify articles with the highest potential impact: - -- **High traffic articles**: Prioritizing docs by page views help Copilot scenarios added here reach the most users. -- **Articles of topic type how-to, get-started, quickstart, or tutorial**: These content types lend themselves well to practical, actionable Copilot scenarios. -- **Articles with code snippets**: Scenarios involving Visual Studio/Visual Studio Code/Azure are good cases to show GitHub Copilot examples. -- **Articles that contain a scenario where Copilot can save developers time and effort on real world tasks**: See the [Identify helpful scenarios](#identify-helpful-scenarios) section that follows. - -## Identify helpful scenarios - -Page views and article types can help you find good candidates for a Copilot highlight, but the most important element is whether Copilot can provide meaningful value in the article. Look for articles where Copilot can save time and effort for real-world tasks. - -Relevant Copilot usage scenarios are use cases that align with typical user workflows or areas where Copilot's suggestions would be useful. Through these examples, we have an opportunity to educate the user to take advantage of Copilot's capabilities in their regular workflow and enhance their productivity. - -Some practical scenarios to show Copilot use: - -- Generate customized code: Tell the reader to take the code provided in the how-to or quickstart and show them how to construct a prompt that modifies it for their specific scenario. - For example: - - Modify code to use a specific operating system or webserver or database - - Generate language specific (for example, C#, C++, Python) or framework specific (for example, .NET, React) code - -- Help with complex or detailed syntax. - For example: - - Translate a specific date and time to cron syntax for scheduling pipelines - - Generate a specific regular expression - -- Help with repetitive, mechanical tasks. These actions require planning, but implementing the idea is something that Copilot can speed up. - For example: - - Generate a class and its members - - Take configuration information and generate a configuration file in a specific format - - Refactor code to use a different API - - Refactor code to target a different endpoint - - Generate a YAML pipeline or GitHub Action that publishes the solution - -- Help with troubleshooting. - For example: - - Use Copilot to debug an error - - -| **Recommended** | **Not recommended** | -| --- | --- | -| Use Copilot to generate serialization code for your specific objects.<br/><br/>*Why*: A prompt for this scenario shows how to generate custom code tailored to the user's specific task, unlike a static code example. | Ask Copilot about what specific code is doing.<br/><br/>*Why*: While interesting, a prompt for this scenario isn't specific to the article. It's generic guidance that belongs in a general "how to use copilot" article. | -| Use Copilot to migrate your specific `Newtonsoft.Json` code to `System.Text.Json`.<br/><br/>*Why*: A prompt for this scenario shows how to migrate user's custom code to use `System.Text.Json`, unlike a generic `System.Text.Json` code example. | Ask Copilot for instructions on how to do *XYZ*.<br/><br/>*Why*: A prompt for this scenario isn't specific to the article. It's generic guidance that belongs in a general "how to use copilot" article. | - -## Determine which Copilot to use - -Microsoft offers various ways to access Copilot: via the web, through Visual Studio, through Visual Studio Code, through the Azure portal, and more. And there are also plugins that can enhance these different flavors of Copilot. - -- Don't refer to a specific type of Copilot unless the functionality you're describing is limited to that specific Copilot. For example, if a prompt works for all Copilot instances, don't qualify it. If the prompt or context only works for GitHub Copilot for Visual Studio, say so. -- List any special installation requirements for Copilot (such as requiring a specific plugin) in the first few sentences. - -## Determine where to put the Copilot highlight - -- Add Copilot highlights to an existing article. Avoid creating a separate article just for the highlight. -- Place the highlight with the task/scenario being used in the Copilot example. If it's generic in context of the article, it can be an H2 at the end of the article. If it fits within a workflow, it can be an H3 or H4 within a section. -- Consider calling attention to the highlight if it appears later in the article by adding a link to it as a *Tip* in the article intro. - -## Copilot highlight structure - -A Copilot highlight has a heading, instructions, a prompt, an optional output example, and a boilerplate warning about using AI-generated content: - -- **Section title** - - Typical format: - - ````markdown - ## Use AI to <accomplish a specific scenario> - ```` - - For example: 'Use AI to serialize a .NET object'. - - Don't refer to Copilot in the section title, use the more generic "AI" -- **Instructions** - - Provide a generalized prompt formula. If the formula contains placeholders, provide an example prompt. - - Mention that the prompt uses Copilot, or a specific version of Copilot, but avoid mentioning Copilot more than once if possible. -- **Prompt** - - Use the `copilot-prompt` devlang - - Example: - - ````markdown - ```copilot-prompt - Take this code: - <code example from article> - And adapt it to use <detail 1> and <detail 2> and <detail 3> - ``` - ```` - -- **Output example** - - Don't show example output unless the prompt is complicated and contains placeholders. (The user can run the prompt themselves to see the output.) -- **Warning about AI-generated content** - Include the following warning as plain text (not a note) after you show your prompt. - - ````markdown - *Copilot is powered by AI, so surprises and mistakes are possible. For more information, see [Copilot general use FAQs](https://aka.ms/copilot-general-use-faqs).* - ```` - -## Writing guidelines - -- Be concise and brief. Hopefully, we add many Copilot highlights to our docs. It's important that these sections are focused on a specific task and don't include redundant information. - Avoid general guidelines and instructions about using Copilot, like explaining how prompts work. Other docs provide that information, which you can link to if you think the user needs them. -- Incorporate Copilot usage in the context of the article, rather than a generic example. -- Don't add gifs or screenshots to showcase the example scenario in action. -- Be sensitive about branding. Mention Copilot or the specific type of Copilot once in the introduction, but to keep the text friendly and avoid it coming across as marketing, don't use the Copilot name repeatedly. -- Avoid marketing language. Copilot is an innovative new technology. Instead of talking about how cool and exciting it is, show its value by demonstrating its usefulness. Basically, avoid marketing language. For more information, see the [guidelines on marketing language](contribute-get-started-channel-guidance.md#unauthorized-content). - -## Metadata requirements for highlights - -Add the following metadata to your article with the Copilot highlight: - -| Attribute | Value | Why? | -| --- | --- | --- | -| `ms.custom` | copilot-scenario-highlight | Helps identify docs updated with a copilot highlight | - -## Templates - -Here are some generic templates for adding a Copilot section to an existing article: - -### Highlight template - Adapt code for your scenario - -````markdown -## Use AI to customize the code for <scenario> - -You can use AI tools, such as Copilot <or specific version of Copilot>, to customize the code in this article for your specific scenario <include specific information>. - -```copilot-prompt -Take this code: -<code example from article> -And adapt it to use <detail 1> and <detail 2> and <detail 3> -``` - -Copilot is powered by AI, so surprises and mistakes are possible. For more information see Copilot FAQs. -```` - -### Highlight template - Accomplish a <task/scenario> - -````markdown -## Use AI to accomplish <Task/Scenario> - -You can use AI tools, such as Copilot <or specific version of Copilot>, to <accomplish task/scenario>. -To generate code that <accomplishes task>, customize this prompt for your specific case <include specific information>. - -```copilot-prompt -Example prompt that might contain placeholders that the user replaces with their information. -For example, generate a connection string that connects to a SQL server database with <address> that uses managed identity for authentication. -``` - -Copilot is powered by AI, so surprises and mistakes are possible. For more information, see Copilot FAQs. -```` - -## Examples of published Copilot highlights - -| Article | Copilot section | -| --- | --- | -| [How to convert a string to a number](/dotnet/csharp/programming-guide/types/how-to-convert-a-string-to-a-number) | [Use GitHub Copilot to convert a string to a number](/dotnet/csharp/programming-guide/types/how-to-convert-a-string-to-a-number#use-github-copilot-to-convert-a-string-to-a-number) | -| [Split strings into substrings](/dotnet/csharp/how-to/parse-strings-using-split) | [Use GitHub Copilot to split a string](/dotnet/csharp/how-to/parse-strings-using-split#use-github-copilot-to-split-a-string) | -| [How to serialize JSON in C#](/dotnet/standard/serialization/system-text-json/how-to) | [Use GitHub Copilot to serialize to JSON](/dotnet/standard/serialization/system-text-json/how-to#use-github-copilot-to-serialize-to-json) | -| [Migrate from Newtonsoft.Json to System.Text.Json](/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft) | [Use GitHub Copilot to migrate](/dotnet/standard/serialization/system-text-json/migrate-from-newtonsoft#use-github-copilot-to-migrate) | -| [How to deserialize JSON in C#](/dotnet/standard/serialization/system-text-json/deserialization) | [Use GitHub Copilot to deserialize JSON](/dotnet/standard/serialization/system-text-json/deserialization#use-github-copilot-to-deserialize-json) | -| [How to customize property names and values with System.Text.Json](/dotnet/standard/serialization/system-text-json/customize-properties) | [Use GitHub Copilot to customize property names and order](/dotnet/standard/serialization/system-text-json/customize-properties#use-github-copilot-to-customize-property-names-and-order) | - -## Questions - -Use the [Copilot in the Docs chat channel](https://aka.ms/copilotindocsquestion) in Microsoft Teams for questions or feedback, and to share the highlights you add to your docs. - -## Resources - -- [How to write better prompts for GitHub Copilot](https://github.blog/developer-skills/github/how-to-write-better-prompts-for-github-copilot/) -- [Get better results with Copilot prompting](https://support.microsoft.com/en-us/topic/get-better-results-with-copilot-prompting-77251d6c-e162-479d-b398-9e46cf73da55) -- [Prompt engineering for GitHub Copilot](https://docs.github.com/en/copilot/using-github-copilot/prompt-engineering-for-github-copilot) -- [Learn about Copilot prompts](https://support.microsoft.com/en-us/topic/learn-about-copilot-prompts-f6c3b467-f07c-4db1-ae54-ffac96184dd5) -- [Cooking up a great prompt: Getting the most from Copilot](https://support.microsoft.com/en-us/topic/cooking-up-a-great-prompt-getting-the-most-from-copilot-7b614306-d5aa-4b62-8509-e46674a29165) -- [Craft effective prompts for Microsoft 365 Copilot](/training/paths/craft-effective-prompts-copilot-microsoft-365/) -- [GitHub Copilot Chat in Visual Studio](/visualstudio/ide/visual-studio-github-copilot-chat) -- [GitHub Copilot in Visual Studio Code](https://code.visualstudio.com/docs/copilot/overview) -- [Copilot Chat Cookbook - GitHub Docs](https://docs.github.com/en/copilot/example-prompts-for-github-copilot-chat) \ No newline at end of file diff --git a/.github/projects/clipboard/temp-clipboard-articles.md b/.github/projects/clipboard/temp-clipboard-articles.md deleted file mode 100644 index 5f5cbb8a87..0000000000 --- a/.github/projects/clipboard/temp-clipboard-articles.md +++ /dev/null @@ -1,92 +0,0 @@ -# Clipboard-Related Articles in Windows Forms Documentation - -This document lists all articles in the Windows Forms documentation that reference clipboard functionality. This is intended as a reference for updating documentation about new clipboard features. - -## Core Clipboard Documentation - -### Main Articles - -1. **Drag-and-Drop Operations and Clipboard Support** - - **Path:** `dotnet-desktop-guide\winforms\advanced\drag-and-drop-operations-and-clipboard-support.md` - - **Description:** Overview article covering both drag-and-drop and clipboard functionality - - **Content:** Main hub for clipboard operations - -1. **How to: Add Data to the Clipboard** - - **Path:** `dotnet-desktop-guide\winforms\advanced\how-to-add-data-to-the-clipboard.md` - - **Description:** Step-by-step guide for adding data to the clipboard - - **Content:** Covers `Clipboard.SetText()`, `SetData()`, and `SetDataObject()` methods - -1. **How to: Retrieve Data from the Clipboard** - - **Path:** `dotnet-desktop-guide\winforms\advanced\how-to-retrieve-data-from-the-clipboard.md` - - **Description:** Guide for retrieving data from the clipboard - - **Content:** Covers `Clipboard.GetText()`, `GetData()`, and `ContainsData()` methods - -### Security and Permissions - -1. **Additional Security Considerations in Windows Forms** - - **Path:** `dotnet-desktop-guide\winforms\additional-security-considerations-in-windows-forms.md` - - **Description:** Contains a dedicated "Clipboard Access" section discussing security permissions - - **Content:** Security implications and permission requirements for clipboard access - -1. **Windows Forms and Unmanaged Applications** - - **Path:** `dotnet-desktop-guide\winforms\advanced\windows-forms-and-unmanaged-applications.md` - - **Description:** Discusses clipboard access in the context of COM interop scenarios - - **Content:** References clipboard in COM interoperability context - -### Control-Specific Articles - -1. **How to: Create a Read-Only Text Box (Windows Forms)** - - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-create-a-read-only-text-box-windows-forms.md` - - **Description:** Mentions clipboard shortcuts (Ctrl+C, Ctrl+V) work in read-only text boxes - - **Content:** Brief reference to clipboard functionality preservation - -1. **How to: Put Quotation Marks in a String (Windows Forms)** - - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-put-quotation-marks-in-a-string-windows-forms.md` - - **Description:** Example includes copying text to clipboard - - **Content:** Code example using `Clipboard.SetText()` - -1. **How to: Select Text in the Windows Forms TextBox Control** - - **Path:** `dotnet-desktop-guide\winforms\controls\how-to-select-text-in-the-windows-forms-textbox-control.md` - - **Description:** Mentions clipboard operations (copy/cut/paste) work with selected text - - **Content:** References standard clipboard keyboard shortcuts - -## Code Snippets and Examples - -### Snippet Locations - -- **Path:** `dotnet-desktop-guide\samples\snippets\winforms\*` -- **Files Found:** - - Various code examples demonstrating clipboard operations. - - Both C# and VB.NET implementations. - - Examples of text, image, and custom data formats. - -## Navigation and TOC References - -### Table of Contents - -- **Path:** `dotnet-desktop-guide\winforms\advanced\toc.yml` -- **Content:** Contains navigation entries for clipboard-related articles - -## Summary - -This repository contains comprehensive documentation covering: - -- **3 primary clipboard articles** (overview, adding data, retrieving data). -- **Multiple supporting articles** that reference clipboard functionality. -- **Security considerations** for clipboard access. -- **Control-specific guidance** on clipboard behavior. -- **Code examples** in both C# and VB.NET. - -## Notes for Updates - -When adding new clipboard features: - -1. Update the main overview article first. -1. Consider if new how-to guides are needed. -1. Update security considerations if permissions change. -1. Add code snippets for new functionality. -1. Update control-specific articles if behavior changes. - ---- - -*Generated on September 25, 2025 as a reference for clipboard feature documentation updates.* From a154219062aba2362a648156956336c64a01088c Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:54:43 -0700 Subject: [PATCH 43/51] Update the RefreshLink prompt --- .github/prompts/RefreshLinks.prompt.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/.github/prompts/RefreshLinks.prompt.md b/.github/prompts/RefreshLinks.prompt.md index 4e96defe28..cac7371e4b 100644 --- a/.github/prompts/RefreshLinks.prompt.md +++ b/.github/prompts/RefreshLinks.prompt.md @@ -1,5 +1,5 @@ --- -model: GPT-4o (copilot) +model: GPT-4.1 (copilot) mode: agent description: "Updates link text to match target content headings" --- @@ -8,6 +8,18 @@ description: "Updates link text to match target content headings" You are tasked with checking and updating all links in the current file to ensure their link text accurately reflects the target content's H1 heading or title. +## ⚠️ CRITICAL CONSTRAINT ⚠️ + +**NO OTHER EDITS OR ALTERATIONS** should be made to the file beyond updating link text. This means: +- Do NOT modify any other content in the file +- Do NOT change formatting, structure, or layout +- Do NOT add, remove, or alter any text outside of link text updates +- Do NOT modify code blocks, headings, or any other markdown elements +- Do NOT use the **title** specified in front matter as the H1 heading for local markdown articles - only use explicitly defined H1 headings in the markdown content (`# Heading Text`) +- ONLY update the display text portion of markdown links `[THIS PART](url)` + +The file content must remain completely unchanged except for link text updates. + ## Link Types and Processing Rules ### 1. Relative Links (e.g., `./folder/file.md`, `../folder/file.md`) From a31e7cee5365cb6df2625ed7ef7c416036d79c2a Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 18:59:55 -0700 Subject: [PATCH 44/51] Fix link --- .../winforms/migration/clipboard-dataobject-net10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index fc8f6d2a9b..3baa4a38f4 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -119,7 +119,7 @@ The `TryGetData<T>()` family replaces the obsolete `GetData()` method. It provid #### Use a type resolver for legacy binary data (requires BinaryFormatter; not recommended) > [!WARNING] -> Type resolvers only work when BinaryFormatter support is enabled, which isn't recommended due to security risks. For more information, see [Enable BinaryFormatter clipboard support (not recommended)](#enable-binaryformatter-clipboard-support-not-recommended). +> Type resolvers only work when BinaryFormatter support is enabled, which isn't recommended due to security risks. For more information, see [Enable BinaryFormatter clipboard support (not recommended)](../advanced/how-to-enable-binaryformatter-clipboard-support.md). Type resolvers let you handle legacy binary data by mapping type names to actual types during deserialization. From dc2c4bf8a28ede73463e93768b88019e7c18c738 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 2 Oct 2025 19:06:15 -0700 Subject: [PATCH 45/51] Fix project file --- .../csharp/ProjectCS.csproj | 2 +- .../vb/ProjectVB.vbproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj index 7e650096d4..8785ccdcdb 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/csharp/ProjectCS.csproj @@ -11,7 +11,7 @@ <!-- <PackageReference> --> <ItemGroup> - <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0"/> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/> </ItemGroup> <!-- </PackageReference> --> diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj index 117dfb332f..06a933be74 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-enable-binaryformatter-clipboard-support/vb/ProjectVB.vbproj @@ -16,7 +16,7 @@ </ItemGroup> <ItemGroup> - <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0"/> + <PackageReference Include="System.Runtime.Serialization.Formatters" Version="10.0.0*-*"/> </ItemGroup> </Project> \ No newline at end of file From 012ea55ee23431c60e1a112198bb80d2826cb0e0 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Wed, 8 Oct 2025 16:02:56 -0700 Subject: [PATCH 46/51] Update instructions again --- .../Markdown.WritingStyle.instructions.md | 83 +++++++++++++++++++ .../Snippets.Migrate.instructions.md | 4 +- .../Snippets.Push.instructions.md | 18 ++-- .github/prompts/ValidateTemplate.prompt.md | 4 +- 4 files changed, 96 insertions(+), 13 deletions(-) create mode 100644 .github/instructions/Markdown.WritingStyle.instructions.md diff --git a/.github/instructions/Markdown.WritingStyle.instructions.md b/.github/instructions/Markdown.WritingStyle.instructions.md new file mode 100644 index 0000000000..eb72f1e320 --- /dev/null +++ b/.github/instructions/Markdown.WritingStyle.instructions.md @@ -0,0 +1,83 @@ +--- +applyTo: 'dotnet-desktop-guide/**/*.md' +description: 'Follow these comprehensive writing style guidelines when creating or editing Markdown documentation. Apply active voice, conversational tone, Oxford commas, and specific formatting rules to ensure consistency and readability across all documentation.' +--- + +# Markdown Writing Style Instructions + +When writing or editing Markdown documentation, follow these style guidelines: + +## Voice and Tone Requirements + +ALWAYS write using: +- Active voice with second person ("you") +- Conversational tone with contractions +- Present tense for instructions and descriptions +- Imperative mood for instructions (write "Call the method" NOT "You should call the method") +- "might" for possibility (NOT "may") +- "can" for permissible actions (NOT "may") + +NEVER use: +- "we" or "our" when referring to documentation authors or product teams +- Jargon or overly complex technical language +- Weak phrases like "you can" or "there is/are/were" unless they add value + +ALWAYS: +- Write like you speak using everyday words +- Create a friendly, informal tone +- Start statements with verbs when possible + +## Structure and Format Rules + +### Headings and Content +- Use sentence case headings (capitalize only first word and proper nouns) +- Never use gerunds in titles +- Never place consecutive headings without content between them +- Lead with the most important information first +- Front-load keywords for scanning + +### Lists and Punctuation +- **CRITICAL: Use Oxford comma in ALL lists (item1, item2, and item3) - NO EXCEPTIONS** +- **MANDATORY: Number ordered lists using "1." for every item (NOT 1., 2., 3.) - ALWAYS USE "1."** +- **REQUIRED: Use bullets for unordered lists - NEVER use numbers for unordered content** +- **ESSENTIAL: Write complete sentences in lists with proper punctuation** +- **MUST: End list items with periods if more than three words - THIS IS NON-NEGOTIABLE** +- Skip end punctuation on titles, headings, and UI elements (3 words or fewer) + +### Spacing and Layout +- Add blank lines around Markdown elements (but don't add extra if they exist) +- Use only one space after periods, question marks, and colons +- Use no spaces around dashes (word—word) +- Break up long sentences for clarity + +### Prohibited Terms +- Never write "etc." or "and so on" - provide complete lists or use "for example" +- Use "for example" instead of "e.g." +- Use "that is" instead of "i.e." + +## Formatting Conventions + +Apply these formatting rules: +- **Bold text** for UI elements +- `Code style` for file names, folders, custom types, and non-localizable text +- Raw URLs in angle brackets +- Relative links for files in this repository +- Remove `https://learn.microsoft.com/en-us` from Microsoft Learn links + +## Word Choice Requirements + +### Verb Selection +- Choose simple verbs without modifiers +- Avoid weak verbs: "be," "have," "make," "do" +- Use precise verbs (write "tell" NOT "inform") + +### Conciseness Rules +- Use one word instead of multiple when possible (write "to" NOT "in order to") +- Choose words with one clear meaning (write "because" NOT "since" for causation) +- Omit unnecessary adverbs unless critical to meaning +- Use one term consistently for each concept + +### Contraction Guidelines +- Use common contractions: "it's," "you're," "that's," "don't" +- Avoid ambiguous contractions: "there'd," "it'll," "they'd" +- Never form contractions from noun + verb (avoid "Microsoft's developing") \ No newline at end of file diff --git a/.github/instructions/Snippets.Migrate.instructions.md b/.github/instructions/Snippets.Migrate.instructions.md index df74ecefe1..f863d39e57 100644 --- a/.github/instructions/Snippets.Migrate.instructions.md +++ b/.github/instructions/Snippets.Migrate.instructions.md @@ -100,7 +100,7 @@ description: Migrate code from the old ~/samples/snippets/ location to the relat - Article shows BOTH .NET and .NET Framework → create both `./snippets/{doc-file}/net/{code-language}/` and `./snippets/{doc-file}/framework/{code-language}/` ### 3. Migrate and update code -- **Copy**: Move the code file to the new location +- **Copy**: Copy only the snippet code (and any supporting code to compile the snippet) to the new location - **Update approach**: - **For .NET Framework articles**: Migrate with minimal changes, keep .NET Framework targeting - **For dual-framework articles**: Create both versions with appropriate targeting and update frontmatter to `ms.service: dotnet-desktop` @@ -127,7 +127,7 @@ description: Migrate code from the old ~/samples/snippets/ location to the relat ### 7. Delete - **Identify**: - Check if the old snippet file is used by any other articles - - Some articles may use a relative path to the `samples` folder, so simply search for `samples/snippets/...` + - Some articles may use a relative path to the `samples` folder, so simply search for links to `samples/snippets/...` - Be confident that all legacy snippets use a `samples/snippets` folder structure - **Delete**: If old snippet is no longer used by any article, delete it. diff --git a/.github/instructions/Snippets.Push.instructions.md b/.github/instructions/Snippets.Push.instructions.md index 209b70dc8a..b9a9028c3d 100644 --- a/.github/instructions/Snippets.Push.instructions.md +++ b/.github/instructions/Snippets.Push.instructions.md @@ -8,11 +8,11 @@ description: Push inline code block snippets out of articles into standalone fil ## Quick Reference -**WHEN TO PUSH:** Code >6 lines, complete/compilable examples, or when specifically requested -**FOLDER PATTERN:** `./snippets/{doc-file}/[net-or-framework]/{csharp|vb}/` -**PROJECT CREATION:** Always use `dotnet new {winforms|wpf|console|classlib}` commands -**LANGUAGES:** Create both C# and VB versions -**SNIPPET IDs:** Use CamelCase region markers like `<ButtonClick>` +**WHEN TO PUSH:** Code >6 lines, complete/compilable examples, or when specifically requested +**FOLDER PATTERN:** `./snippets/{doc-file}/[net-or-framework]/{csharp|vb}/` +**PROJECT CREATION:** Always use `dotnet new {winforms|wpf|console|classlib}` commands to create a new project for the code language +**LANGUAGES:** Create both C# and VB versions +**SNIPPET IDs:** Use CamelCase region markers like `<ButtonClick>` **ARTICLE REFS:** Replace with `:::code language="csharp" source="./path" id="SnippetId":::` ## When to push snippets out of articles @@ -32,7 +32,7 @@ description: Push inline code block snippets out of articles into standalone fil ## Target folder structure -**IMPORTANT**: Follow the same structure as the migration guidelines: +**IMPORTANT**: Follow a folder structure based on the article and code language: ### New snippet location (standard) - Path pattern: `./snippets/{doc-file}/[net-or-framework]/{code-language}/` @@ -75,7 +75,7 @@ description: Push inline code block snippets out of articles into standalone fil - Create folder structure: `./snippets/{doc-file}/[net-or-framework]/{csharp|vb}/` ### 2. Create projects and extract code -- Run appropriate `dotnet new` command in each language folder +- Run appropriate `dotnet new` command in each language folder, **don't** specify an output folder with `-o`. Specify a meaningful project name with `-n` if possible - Copy and complete code to make it compilable - Add missing using statements, namespaces, class declarations - Modernize code patterns if targeting current .NET @@ -105,7 +105,7 @@ dev_langs: ## Common mistakes to avoid - ❌ Extracting short snippets (≤6 lines) without request -- ❌ Skipping `dotnet new` commands or creating incomplete projects +- ❌ Skipping `dotnet new` commands or creating incomplete projects - ❌ Missing C# or VB versions - ❌ Using language tabs - ❌ Wrong project type (winforms vs wpf vs console) @@ -116,6 +116,6 @@ dev_langs: ## Quality checklist - ✅ Correct folder structure and project type -- ✅ Both C# and VB versions compile successfully +- ✅ Both C# and VB versions compile successfully - ✅ Snippet regions use CamelCase identifiers - ✅ Article uses correct `:::code...:::` syntax with valid paths \ No newline at end of file diff --git a/.github/prompts/ValidateTemplate.prompt.md b/.github/prompts/ValidateTemplate.prompt.md index 1a520f8a3c..31ca5383db 100644 --- a/.github/prompts/ValidateTemplate.prompt.md +++ b/.github/prompts/ValidateTemplate.prompt.md @@ -1,5 +1,5 @@ --- -model: GPT-4o (copilot) +model: GPT-4.1 (copilot) mode: agent description: "Validates article structure against appropriate templates" --- @@ -22,7 +22,7 @@ Analyze the current article to determine its type: ### Step 2: Select and Read Template - Map the article type to the corresponding template file: - `how-to` → `template-how-to-guide.md` - - `quickstart` → `template-quickstart.md` + - `quickstart` → `template-quickstart.md` - `tutorial` → `template-tutorial.md` - `concept` → `template-concept.md` - `overview` → `template-overview.md` From 56f9208b72b50cbd3903cbc4e62ef8d983131ebb Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Wed, 8 Oct 2025 16:03:27 -0700 Subject: [PATCH 47/51] Update snippets per feedback --- .../net/vb/Form1.vb | 23 +++- .../net/csharp/BinaryFormatterSupport.cs | 15 ++- .../net/csharp/Form1.resx | 120 ++++++++++++++++++ .../net/csharp/ITypedDataObjectExamples.cs | 22 +--- .../net/csharp/ObsoletePatterns.cs | 4 +- .../net/csharp/PrimitiveTypesExamples.cs | 20 +-- .../net/vb/BinaryFormatterSupport.vb | 15 ++- .../net/vb/CustomTypesExamples.vb | 23 +--- .../net/vb/ITypedDataObjectExamples.vb | 21 +-- .../net/vb/PrimitiveTypesExamples.vb | 22 ++-- 10 files changed, 184 insertions(+), 101 deletions(-) create mode 100644 dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.resx diff --git a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb index 8d8060a141..46d9d921f3 100644 --- a/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb +++ b/dotnet-desktop-guide/winforms/advanced/snippets/how-to-add-data-to-the-clipboard/net/vb/Form1.vb @@ -84,7 +84,7 @@ Public Class Form1 '</SetTextExample> '<CustomFormatExample> - ' Demonstrates SetDataAsJson, ContainsData, and GetData + ' Demonstrates SetData, ContainsData, and GetData ' using a custom format name and a business object. Public ReadOnly Property TestCustomFormat() As Customer Get @@ -127,20 +127,41 @@ Public Class Form1 If retrievedData.GetDataPresent("ListViewItemFormat") Then Dim item As String = Nothing + If retrievedData.TryGetData("ListViewItemFormat", item) Then Dim recreatedListViewItem As New ListViewItem(item) MessageBox.Show($"Data contains ListViewItem with text of {recreatedListViewItem.Text}") End If + End If If retrievedData.GetDataPresent(GetType(Customer)) Then Dim newCustomer As Customer = Nothing + If retrievedData.TryGetData(newCustomer) Then MessageBox.Show($"Data contains Customer with name of {newCustomer.Name}") End If + End If End Sub '</MultipleFormatsExample> + '<GenericSetDataExample> + ' Demonstrates SetData, ContainsData, and GetData. + Public Function SwapClipboardFormattedData( + ByVal format As String, ByVal data As Object) As Object + + Dim returnObject As Object = Nothing + + If Clipboard.ContainsData(format) Then + returnObject = Clipboard.GetData(format) + Clipboard.SetData(format, data) + End If + + Return returnObject + + End Function + '</GenericSetDataExample> + End Class diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs index 8f6b91b37b..a7e9c6745c 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Reflection.Metadata; using System.Windows.Forms; @@ -7,18 +7,21 @@ namespace ClipboardExamples { public class BinaryFormatterSupport { + [Serializable] public class Person { public string Name { get; set; } public int Age { get; set; } } + [Serializable] public class AppSettings { public string Theme { get; set; } public bool AutoSave { get; set; } } + [Serializable] public class MyCustomType { public string Data { get; set; } @@ -31,10 +34,10 @@ private static Type SecureTypeResolver(TypeName typeName) // Explicit allow-list of permitted types—add only what you need var allowedTypes = new Dictionary<string, Type> { - ["MyApp.Person"] = typeof(Person), - ["MyApp.Settings"] = typeof(AppSettings), - ["System.String"] = typeof(string), - ["System.Int32"] = typeof(int), + [typeof(Person).FullName!] = typeof(Person), + [typeof(AppSettings).FullName!] = typeof(AppSettings), + [typeof(string).FullName!] = typeof(string), + [typeof(int).FullName!] = typeof(int), // Add only the specific types your application requires }; @@ -64,4 +67,4 @@ private static void ProcessLegacyData(MyCustomType data) Console.WriteLine($"Processing legacy data: {data.Data}"); } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.resx b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.resx new file mode 100644 index 0000000000..1af7de150c --- /dev/null +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/Form1.resx @@ -0,0 +1,120 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <!-- + Microsoft ResX Schema + + Version 2.0 + + The primary goals of this format is to allow a simple XML format + that is mostly human readable. The generation and parsing of the + various data types are done through the TypeConverter classes + associated with the data types. + + Example: + + ... ado.net/XML headers & schema ... + <resheader name="resmimetype">text/microsoft-resx</resheader> + <resheader name="version">2.0</resheader> + <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader> + <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader> + <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data> + <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data> + <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64"> + <value>[base64 mime encoded serialized .NET Framework object]</value> + </data> + <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64"> + <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value> + <comment>This is a comment</comment> + </data> + + There are any number of "resheader" rows that contain simple + name/value pairs. + + Each data row contains a name, and value. The row also contains a + type or mimetype. Type corresponds to a .NET class that support + text/value conversion through the TypeConverter architecture. + Classes that don't support this are serialized and stored with the + mimetype set. + + The mimetype is used for serialized objects, and tells the + ResXResourceReader how to depersist the object. This is currently not + extensible. For a given mimetype the value must be set accordingly: + + Note - application/x-microsoft.net.object.binary.base64 is the format + that the ResXResourceWriter will generate, however the reader can + read any of the formats listed below. + + mimetype: application/x-microsoft.net.object.binary.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.soap.base64 + value : The object must be serialized with + : System.Runtime.Serialization.Formatters.Soap.SoapFormatter + : and then encoded with base64 encoding. + + mimetype: application/x-microsoft.net.object.bytearray.base64 + value : The object must be serialized into a byte array + : using a System.ComponentModel.TypeConverter + : and then encoded with base64 encoding. + --> + <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> + <xsd:import namespace="http://www.w3.org/XML/1998/namespace" /> + <xsd:element name="root" msdata:IsDataSet="true"> + <xsd:complexType> + <xsd:choice maxOccurs="unbounded"> + <xsd:element name="metadata"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" /> + </xsd:sequence> + <xsd:attribute name="name" use="required" type="xsd:string" /> + <xsd:attribute name="type" type="xsd:string" /> + <xsd:attribute name="mimetype" type="xsd:string" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="assembly"> + <xsd:complexType> + <xsd:attribute name="alias" type="xsd:string" /> + <xsd:attribute name="name" type="xsd:string" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="data"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" /> + <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" /> + <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" /> + <xsd:attribute ref="xml:space" /> + </xsd:complexType> + </xsd:element> + <xsd:element name="resheader"> + <xsd:complexType> + <xsd:sequence> + <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" /> + </xsd:sequence> + <xsd:attribute name="name" type="xsd:string" use="required" /> + </xsd:complexType> + </xsd:element> + </xsd:choice> + </xsd:complexType> + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>2.0</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value> + </resheader> +</root> \ No newline at end of file diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs index 3cb97f8aa3..6f566076b7 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs @@ -1,27 +1,9 @@ -using System; +using System; using System.Reflection.Metadata; using System.Windows.Forms; namespace ClipboardExamples { - // <ITypedDataObjectImplementation> - public class TypedDataObject : DataObject, ITypedDataObject - { - public new bool TryGetData<T>(string format, out T data) - { - // Use new type-safe logic - return base.TryGetData(format, out data); - } - - // This overload requires BinaryFormatter support (not recommended) - public new bool TryGetData<T>(string format, Func<TypeName, Type> resolver, out T data) - { - data = default(T)!; - return false; // Simplified implementation for example - } - } - // </ITypedDataObjectImplementation> - public class DragDropExamples { public class MyItem @@ -71,4 +53,4 @@ private void ProcessCustomItem(MyItem item) Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}"); } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs index 8945ff2011..117c6ef863 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows.Forms; namespace ClipboardExamples @@ -45,4 +45,4 @@ private static void ProcessPerson(Person person) Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs index 9cfa7d19a6..6840b049a5 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/PrimitiveTypesExamples.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Windows.Forms; @@ -24,9 +24,9 @@ public static void PrimitiveTypesExample() Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)); // Later retrieval with type safety - if (Clipboard.TryGetData("MyInt", out int value)) + if (Clipboard.TryGetData("MyTimeSpan", out TimeSpan value)) { - ProcessInteger(value); + Console.WriteLine($"Clipboard value is: {value}"); } } // </PrimitiveTypesExample> @@ -48,19 +48,9 @@ public static void CollectionsExample() // Retrieval maintains type safety if (Clipboard.TryGetData("NumberArray", out int[] retrievedNumbers)) { - ProcessNumbers(retrievedNumbers); + Console.WriteLine($"Numbers: {string.Join(", ", retrievedNumbers)}"); } } // </CollectionsExample> - - private static void ProcessInteger(int value) - { - Console.WriteLine($"Integer value: {value}"); - } - - private static void ProcessNumbers(int[] numbers) - { - Console.WriteLine($"Numbers: {string.Join(", ", numbers)}"); - } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb index 012547f249..7e5d65b3e7 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb @@ -1,20 +1,23 @@ -Imports System +Imports System Imports System.Collections.Generic Imports System.Reflection.Metadata Imports System.Windows.Forms Namespace ClipboardExamples Public Class BinaryFormatterSupport + <Serializable> Public Class Person Public Property Name As String Public Property Age As Integer End Class + <Serializable> Public Class AppSettings Public Property Theme As String Public Property AutoSave As Boolean End Class + <Serializable> Public Class MyCustomType Public Property Data As String End Class @@ -24,10 +27,10 @@ Namespace ClipboardExamples Private Shared Function SecureTypeResolver(typeName As TypeName) As Type ' Explicit allow-list of permitted types—add only what you need Dim allowedTypes As New Dictionary(Of String, Type) From { - {"MyApp.Person", GetType(Person)}, - {"MyApp.Settings", GetType(AppSettings)}, - {"System.String", GetType(String)}, - {"System.Int32", GetType(Integer)} + {GetType(Person).FullName, GetType(Person)}, + {GetType(AppSettings).FullName, GetType(AppSettings)}, + {GetType(String).FullName, GetType(String)}, + {GetType(Integer).FullName, GetType(Integer)} } ' Add only the specific types your application requires @@ -55,4 +58,4 @@ Namespace ClipboardExamples Console.WriteLine($"Processing legacy data: {data.Data}") End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb index 7b886ae49b..e5a1270eb0 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/CustomTypesExamples.vb @@ -1,23 +1,10 @@ -Imports System +Imports System Imports System.Text.Json.Serialization Imports System.Windows.Forms Namespace ClipboardExamples Public Class CustomTypesExamples ' <SimpleCustomTypes> - ' Records work without any attributes. - Public Structure PersonInfo - Public Sub New(name As String, age As Integer, email As String) - Me.Name = name - Me.Age = age - Me.Email = email - End Sub - - Public Property Name As String - Public Property Age As Integer - Public Property Email As String - End Structure - ' Simple classes serialize all public properties automatically. Public Class DocumentMetadata Public Property Title As String @@ -41,15 +28,15 @@ Namespace ClipboardExamples ' Public properties are always serialized Public Property Name As String - + ' Exclude sensitive or non-essential data <JsonIgnore> Public Property InternalId As String - + ' Handle property name differences for compatibility <JsonPropertyName("display_text")> Public Property DisplayText As String - + ' Control null value handling <JsonIgnore(Condition:=JsonIgnoreCondition.WhenWritingNull)> Public Property OptionalField As String @@ -74,4 +61,4 @@ Namespace ClipboardExamples End Sub ' </CustomTypesClipboardOperations> End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb index 97b4f98f23..86fb3679c9 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb @@ -1,25 +1,8 @@ -Imports System +Imports System Imports System.Reflection.Metadata Imports System.Windows.Forms Namespace ClipboardExamples - ' <ITypedDataObjectImplementation> - Public Class TypedDataObject - Inherits DataObject - Implements ITypedDataObject - - Public Overloads Function TryGetData(Of T)(format As String, ByRef data As T) As Boolean Implements ITypedDataObject.TryGetData - ' Use new type-safe logic - Return MyBase.TryGetData(format, data) - End Function - - ' This overload requires BinaryFormatter support (not recommended) - Public Overloads Function TryGetData(Of T)(format As String, resolver As Func(Of TypeName, Type), ByRef data As T) As Boolean - data = Nothing - Return False ' Simplified implementation for example - End Function - End Class - ' </ITypedDataObjectImplementation> Public Class DragDropExamples Public Class MyItem @@ -65,4 +48,4 @@ Namespace ClipboardExamples Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}") End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb index 25fefa5c73..b135ca6f47 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/PrimitiveTypesExamples.vb @@ -1,4 +1,4 @@ -Imports System +Imports System Imports System.Collections.Generic Imports System.Windows.Forms @@ -21,9 +21,10 @@ Namespace ClipboardExamples Clipboard.SetData("MyTimeSpan", TimeSpan.FromMinutes(30)) ' Later retrieval with type safety - Dim value As Integer - If Clipboard.TryGetData("MyInt", value) Then - ProcessInteger(value) + Dim value As TimeSpan + + If Clipboard.TryGetData("MyTimeSpan", value) Then + Console.WriteLine($"Clipboard value is: {value}") End If End Sub ' </PrimitiveTypesExample> @@ -43,18 +44,11 @@ Namespace ClipboardExamples ' Retrieval maintains type safety Dim retrievedNumbers As Integer() = Nothing + If Clipboard.TryGetData("NumberArray", retrievedNumbers) Then - ProcessNumbers(retrievedNumbers) + Console.WriteLine($"Numbers: {String.Join(", ", retrievedNumbers)}") End If End Sub ' </CollectionsExample> - - Private Shared Sub ProcessInteger(value As Integer) - Console.WriteLine($"Integer value: {value}") - End Sub - - Private Shared Sub ProcessNumbers(numbers As Integer()) - Console.WriteLine($"Numbers: {String.Join(", ", numbers)}") - End Sub End Class -End Namespace \ No newline at end of file +End Namespace From fedabbd585cf32339e43c8774a3bd7231118c35c Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Wed, 8 Oct 2025 16:03:41 -0700 Subject: [PATCH 48/51] Remove the ITypedDataObject snippet as it didn't teach anything --- .../winforms/migration/clipboard-dataobject-net10.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md index 3baa4a38f4..d1d9c83255 100644 --- a/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md +++ b/dotnet-desktop-guide/winforms/migration/clipboard-dataobject-net10.md @@ -152,10 +152,7 @@ These methods provide automatic JSON serialization using `System.Text.Json` with The <xref:System.Windows.Forms.ITypedDataObject> interface enables type-safe drag-and-drop operations by extending <xref:System.Windows.Forms.IDataObject> with typed methods. -#### Implement ITypedDataObject in a custom DataObject - -:::code language="csharp" source="./snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs" id="ITypedDataObjectImplementation"::: -:::code language="vb" source="./snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb" id="ITypedDataObjectImplementation"::: +Starting with .NET 10, <xref:System.Windows.Forms.DataObject> (a common type in drag-and-drop scenarios) implements `ITypedDataObject`. #### Use ITypedDataObject in drag-and-drop scenarios From f4e6bca03c499a4687a33bd183b341c5e5308f01 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Wed, 8 Oct 2025 16:06:30 -0700 Subject: [PATCH 49/51] Add missing instruction --- .github/copilot-instructions.md | 60 +++++++++++++-------------------- 1 file changed, 23 insertions(+), 37 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 44cef925db..0e052d01ea 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -2,7 +2,13 @@ ## Disclosure -IMPORTANT: For any Markdown files generated by AI, always disclose that they were created with the assistance of AI. Add the `ai-usage` frontmatter key/value pair: +IMPORTANT: For any Markdown files generated by AI, always disclose that they were created with the assistance of AI. If missing, add the `ai-usage` frontmatter key/value pair: + +- When reviewing a PR not created by AI: + + ```markdown + ai-usage: ai-assisted + ``` - When Copilot generates the article through GitHub without the use of a human: @@ -25,40 +31,6 @@ IMPORTANT: For any Markdown files generated by AI, always disclose that they wer - Unless otherwise specified, all .NET content refers to modern .NET (not .NET Framework). -## Writing Style - -Follow [Microsoft Writing Style Guide](https://learn.microsoft.com/en-us/style-guide/welcome/) with these specifics: - -### Voice and Tone - -- Active voice, second person addressing reader directly. -- Conversational tone with contractions. -- Present tense for instructions/descriptions. -- Imperative mood for instructions ("Call the method" not "You should call the method"). -- Use "might" instead of "may" for possibility. -- Use "can" instead of "may" for permissible actions. -- Avoid "we"/"our" referring to documentation authors or product teams. - -### Structure and Format - -- Markdown elements should have blank lines around them. Don't add extra blank lines if they already exist. -- Sentence case headings (no gerunds in titles). -- Be concise, break up long sentences. -- IMPORTANT: Oxford comma in lists. -- Number all ordered list items as "1." (not sequential numbering like "1.", "2.", "3.", etc.) -- IMPORTANT: Use bullets for unordered lists. -- VERY IMPORTANT: Ordered and unordered lists should use complete sentences with proper punctuation, ending with a period if it's more than three words. -- Avoid "etc." or "and so on" - provide complete lists or use "for example". -- No consecutive headings without content between them. - -### Formatting Conventions - -- **Bold** for UI elements. -- `Code style` for file names, folders, custom types, non-localizable text. -- Raw URLs in angle brackets. -- Use relative links for files in this repo. -- Remove `https://learn.microsoft.com/en-us` from learn.microsoft.com links. - ## API References Use cross-references: `<xref:api-doc-ID>`. @@ -125,7 +97,21 @@ Your .NET Framework content here New Markdown files: lowercase with hyphens, omit filler words (the, a, etc.). +Examples: +- ✅ Good: `getting-started-with-entity-framework.md` +- ✅ Good: `configure-logging.md` +- ✅ Good: `dependency-injection-guidelines.md` +- ❌ Bad: `Getting-Started-With-The-Entity-Framework.md` +- ❌ Bad: `configure_logging.md` +- ❌ Bad: `DependencyInjectionGuidelines.md` + ## Special Cases -- Breaking changes: Include directions from `.github/prompts/breaking-change.md`. -- When you (Copilot) are assigned an issue in GitHub, after you've completed your work and the workflows (status checks) have run, check to make sure there are no build warnings under the OpenPublishing.Build status check. If there are, open the build report (under View Details) and resolve any build warnings you introduced. +### GitHub Issue Assignment (AI Workflow) +When assigned an issue in GitHub: +1. Complete your work +2. Wait for workflows (status checks) to run +3. Check for build warnings in the OpenPublishing.Build status check +4. If warnings exist: + - Click "View Details" to open the build report + - Resolve any build warnings you introduced From 137980b6f349bfc57759b3381728d2631a561161 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Wed, 8 Oct 2025 16:39:08 -0700 Subject: [PATCH 50/51] Inlined all the silly method writelines copilot generated --- .../net/csharp/BinaryFormatterSupport.cs | 7 +-- .../net/csharp/ITypedDataObjectExamples.cs | 27 ++-------- .../net/csharp/ModernApproach.cs | 23 ++++---- .../net/csharp/ObsoletePatterns.cs | 9 +--- .../net/csharp/TypeResolver.cs | 18 ++----- .../net/csharp/TypeSafeRetrieval.cs | 45 ++++------------ .../net/vb/BinaryFormatterSupport.vb | 6 +-- .../net/vb/ITypedDataObjectExamples.vb | 18 ++----- .../net/vb/ModernApproach.vb | 20 +++---- .../net/vb/ObsoletePatterns.vb | 12 ++--- .../net/vb/TypeResolver.vb | 47 +++++++---------- .../net/vb/TypeSafeRetrieval.vb | 52 ++++--------------- 12 files changed, 75 insertions(+), 209 deletions(-) diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs index a7e9c6745c..6d20b9e83e 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/BinaryFormatterSupport.cs @@ -57,14 +57,9 @@ public static void UseSecureTypeResolver() { if (Clipboard.TryGetData("LegacyData", SecureTypeResolver, out MyCustomType data)) { - ProcessLegacyData(data); + Console.WriteLine($"Processing legacy data: {data.Data}"); } } // </SecureTypeResolver> - - private static void ProcessLegacyData(MyCustomType data) - { - Console.WriteLine($"Processing legacy data: {data.Data}"); - } } } diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs index 6f566076b7..fbddb56725 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ITypedDataObjectExamples.cs @@ -19,38 +19,17 @@ private void OnDragDrop(object sender, DragEventArgs e) { // Retrieve files from drag data using a standard format if (typedData.TryGetData(DataFormats.FileDrop, out string[] files)) - { - ProcessDroppedFiles(files); - } + Console.WriteLine($"Dropped files: {string.Join(", ", files)}"); // Retrieve text using a standard format if (typedData.TryGetData(DataFormats.Text, out string text)) - { - ProcessDroppedText(text); - } + Console.WriteLine($"Dropped text: {text}"); // Retrieve custom items using an application-specific format if (typedData.TryGetData("CustomItem", out MyItem item)) - { - ProcessCustomItem(item); - } + Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}"); } } // </DragDropUsage> - - private void ProcessDroppedFiles(string[] files) - { - Console.WriteLine($"Dropped files: {string.Join(", ", files)}"); - } - - private void ProcessDroppedText(string text) - { - Console.WriteLine($"Dropped text: {text}"); - } - - private void ProcessCustomItem(MyItem item) - { - Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}"); - } } } diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs index b9bb9e017b..5a877c6ac2 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ModernApproach.cs @@ -1,5 +1,6 @@ -using System; +using System; using System.Windows.Forms; +using static System.Runtime.InteropServices.JavaScript.JSType; namespace ClipboardExamples { @@ -14,27 +15,21 @@ public class Person // <ModernTryGetData> public static void ModernTryGetDataExample() { + var data = new Person { Name = "Alice", Age = 28 }; + Clipboard.SetDataAsJson("MyAppData", data); + // Use this - type-safe approach with TryGetData<T>() if (Clipboard.TryGetData("MyApp.Person", out Person person)) { - ProcessPerson(person); // person is guaranteed to be the correct type + // person is guaranteed to be the correct type + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); } else { // Handle the case where data isn't available or is the wrong type - ShowError("Unable to retrieve person data from clipboard"); + MessageBox.Show("Unable to retrieve person data from clipboard"); } } // </ModernTryGetData> - - private static void ProcessPerson(Person person) - { - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); - } - - private static void ShowError(string message) - { - MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); - } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs index 117c6ef863..5fdff02cb6 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/ObsoletePatterns.cs @@ -34,15 +34,10 @@ public static void ObsoleteGetDataExample() // Always returns null on a custom object type if (data != null) { - Person person = (Person)data; // Unsafe casting - ProcessPerson(person); + Person person = (Person)data; + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); } } // </ObsoleteGetData> - - private static void ProcessPerson(Person person) - { - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); - } } } diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs index 71567797f1..c935be4aa4 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeResolver.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Reflection.Metadata; using System.Windows.Forms; @@ -43,25 +43,15 @@ public static void TypeResolverExample() // Use the resolver with legacy binary data if (Clipboard.TryGetData("LegacyFormat", resolver, out Person person)) { - ProcessPerson(person); + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); } // Use a resolver with conversion control if (Clipboard.TryGetData("OldCustomData", resolver, out MyType data)) { - ProcessCustomData(data); + Console.WriteLine($"Processing custom data: {data.Data}"); } } // </TypeResolverExample> - - private static void ProcessPerson(Person person) - { - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}"); - } - - private static void ProcessCustomData(MyType data) - { - Console.WriteLine($"Processing custom data: {data.Data}"); - } } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs index 3cf6709a03..105429cad6 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/csharp/TypeSafeRetrieval.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Windows.Forms; namespace ClipboardExamples @@ -10,33 +10,23 @@ public static void BasicTypeSafeRetrievalExamples() { // Retrieve text data using a standard format if (Clipboard.TryGetData(DataFormats.Text, out string textData)) - { - ProcessTextData(textData); - } + Console.WriteLine($"Text: {textData}"); // Retrieve an integer using a custom format if (Clipboard.TryGetData("NumberData", out int numberData)) - { - ProcessNumber(numberData); - } + Console.WriteLine($"Number: {numberData}"); // Retrieve Unicode text using a standard format if (Clipboard.TryGetData(DataFormats.UnicodeText, out string unicodeText)) - { - ProcessUnicodeText(unicodeText); - } + Console.WriteLine($"Unicode: {unicodeText}"); // Retrieve raw text data with OLE conversion control if (Clipboard.TryGetData(DataFormats.Text, out string rawText)) - { - ProcessRawText(rawText); - } + Console.WriteLine($"Raw: {rawText}"); // Retrieve file drops using a standard format if (Clipboard.TryGetData(DataFormats.FileDrop, out string[] files)) - { - ProcessFiles(files); - } + Console.WriteLine($"Files: {string.Join(", ", files)}"); } // </BasicTypeSafeRetrieval> @@ -45,21 +35,15 @@ public static void CustomJsonTypesExamples() { // Retrieve a custom type stored with SetDataAsJson<T>() if (Clipboard.TryGetData("Person", out Person person)) - { - ProcessPerson(person); - } + Console.WriteLine($"Person: {person.Name}"); // Retrieve application-specific data formats if (Clipboard.TryGetData("MyApp.Settings", out AppSettings settings)) - { - ApplySettings(settings); - } + Console.WriteLine($"Settings: {settings.Theme}"); // Retrieve complex custom objects if (Clipboard.TryGetData("DocumentData", out DocumentInfo doc)) - { - LoadDocument(doc); - } + Console.WriteLine($"Document: {doc.Title}"); } // </CustomJsonTypes> @@ -81,14 +65,5 @@ public class DocumentInfo public string Author { get; set; } public DateTime Created { get; set; } } - - private static void ProcessTextData(string text) => Console.WriteLine($"Text: {text}"); - private static void ProcessNumber(int number) => Console.WriteLine($"Number: {number}"); - private static void ProcessUnicodeText(string text) => Console.WriteLine($"Unicode: {text}"); - private static void ProcessRawText(string text) => Console.WriteLine($"Raw: {text}"); - private static void ProcessFiles(string[] files) => Console.WriteLine($"Files: {string.Join(", ", files)}"); - private static void ProcessPerson(Person person) => Console.WriteLine($"Person: {person.Name}"); - private static void ApplySettings(AppSettings settings) => Console.WriteLine($"Settings: {settings.Theme}"); - private static void LoadDocument(DocumentInfo doc) => Console.WriteLine($"Document: {doc.Title}"); } -} \ No newline at end of file +} diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb index 7e5d65b3e7..f0b59c1b65 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/BinaryFormatterSupport.vb @@ -49,13 +49,9 @@ Namespace ClipboardExamples Public Shared Sub UseSecureTypeResolver() Dim data As MyCustomType = Nothing If Clipboard.TryGetData("LegacyData", AddressOf SecureTypeResolver, data) Then - ProcessLegacyData(data) + Console.WriteLine($"Processing legacy data: {data.Data}") End If End Sub ' </SecureTypeResolver> - - Private Shared Sub ProcessLegacyData(data As MyCustomType) - Console.WriteLine($"Processing legacy data: {data.Data}") - End Sub End Class End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb index 86fb3679c9..9bc12a8e42 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ITypedDataObjectExamples.vb @@ -18,34 +18,22 @@ Namespace ClipboardExamples ' Retrieve files from drag data using a standard format Dim files As String() = Nothing If typedData.TryGetData(DataFormats.FileDrop, files) Then - ProcessDroppedFiles(files) + Console.WriteLine($"Dropped files: {String.Join(", ", files)}") End If ' Retrieve text using a standard format Dim text As String = Nothing If typedData.TryGetData(DataFormats.Text, text) Then - ProcessDroppedText(text) + Console.WriteLine($"Dropped text: {text}") End If ' Retrieve custom items using an application-specific format Dim item As MyItem = Nothing If typedData.TryGetData("CustomItem", item) Then - ProcessCustomItem(item) + Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}") End If End If End Sub ' </DragDropUsage> - - Private Sub ProcessDroppedFiles(files As String()) - Console.WriteLine($"Dropped files: {String.Join(", ", files)}") - End Sub - - Private Sub ProcessDroppedText(text As String) - Console.WriteLine($"Dropped text: {text}") - End Sub - - Private Sub ProcessCustomItem(item As MyItem) - Console.WriteLine($"Dropped custom item: {item.Name} = {item.Value}") - End Sub End Class End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb index d490f6a309..2fed477671 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ModernApproach.vb @@ -1,4 +1,4 @@ -Imports System +Imports System Imports System.Windows.Forms Namespace ClipboardExamples @@ -10,23 +10,19 @@ Namespace ClipboardExamples ' <ModernTryGetData> Public Shared Sub ModernTryGetDataExample() + Dim data As New Person With {.Name = "Alice", .Age = 30} + Clipboard.SetDataAsJson("MyAppData", data) + ' Use this - type-safe approach with TryGetData(Of T)() Dim person As Person = Nothing If Clipboard.TryGetData("MyApp.Person", person) Then - ProcessPerson(person) ' person is guaranteed to be the correct type + ' person is guaranteed to be the correct type + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") Else ' Handle the case where data isn't available or is the wrong type - ShowError("Unable to retrieve person data from clipboard") + MessageBox.Show("Unable to retrieve person data from clipboard") End If End Sub ' </ModernTryGetData> - - Private Shared Sub ProcessPerson(person As Person) - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") - End Sub - - Private Shared Sub ShowError(message As String) - MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error) - End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb index 40406818d9..f4a8a1e9ac 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/ObsoletePatterns.vb @@ -1,4 +1,4 @@ -Imports System +Imports System Imports System.Windows.Forms Namespace ClipboardExamples @@ -28,14 +28,10 @@ Namespace ClipboardExamples ' Always returns null on a custom object type If data IsNot Nothing Then - Dim person As Person = CType(data, Person) ' Unsafe casting - ProcessPerson(person) + Dim person As Person = CType(data, Person) + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") End If End Sub ' </ObsoleteGetData> - - Private Shared Sub ProcessPerson(person As Person) - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") - End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb index 490eb24a19..d5797fefc6 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeResolver.vb @@ -1,4 +1,4 @@ -Imports System +Imports System Imports System.Reflection.Metadata Imports System.Windows.Forms @@ -21,42 +21,35 @@ Namespace ClipboardExamples ' <TypeResolverExample> Public Shared Sub TypeResolverExample() ' Create a type resolver that maps old type names to current types - Dim resolver As Func(Of TypeName, Type) = Function(typeName) - ' Only allow specific, known, safe types - Select Case typeName.FullName - Case "MyApp.Person" - Return GetType(Person) - Case "MyApp.Settings" - Return GetType(AppSettings) - Case "System.String" - Return GetType(String) - Case "System.Int32" - Return GetType(Integer) - Case Else - Throw New InvalidOperationException($"Type not allowed: {typeName.FullName}") - End Select - End Function + Dim resolver As Func(Of TypeName, Type) = + Function(typeName) + ' Only allow specific, known, safe types + Select Case typeName.FullName + Case "MyApp.Person" + Return GetType(Person) + Case "MyApp.Settings" + Return GetType(AppSettings) + Case "System.String" + Return GetType(String) + Case "System.Int32" + Return GetType(Integer) + Case Else + Throw New InvalidOperationException($"Type not allowed: {typeName.FullName}") + End Select + End Function ' Use the resolver with legacy binary data Dim person As Person = Nothing If Clipboard.TryGetData("LegacyFormat", resolver, person) Then - ProcessPerson(person) + Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") End If ' Use a resolver with conversion control Dim data As MyType = Nothing If Clipboard.TryGetData("OldCustomData", resolver, data) Then - ProcessCustomData(data) + Console.WriteLine($"Processing custom data: {data.Data}") End If End Sub ' </TypeResolverExample> - - Private Shared Sub ProcessPerson(person As Person) - Console.WriteLine($"Processing person: {person.Name}, Age: {person.Age}") - End Sub - - Private Shared Sub ProcessCustomData(data As MyType) - Console.WriteLine($"Processing custom data: {data.Data}") - End Sub End Class -End Namespace \ No newline at end of file +End Namespace diff --git a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb index 20c32f7c37..e52e2a6adf 100644 --- a/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb +++ b/dotnet-desktop-guide/winforms/migration/snippets/clipboard-dataobject-net10/net/vb/TypeSafeRetrieval.vb @@ -1,4 +1,4 @@ -Imports System +Imports System Imports System.Windows.Forms Namespace ClipboardExamples @@ -8,31 +8,31 @@ Namespace ClipboardExamples ' Retrieve text data using a standard format Dim textData As String = Nothing If Clipboard.TryGetData(DataFormats.Text, textData) Then - ProcessTextData(textData) + Console.WriteLine($"Text: {textData}") End If ' Retrieve an integer using a custom format Dim numberData As Integer If Clipboard.TryGetData("NumberData", numberData) Then - ProcessNumber(numberData) + Console.WriteLine($"Number: {numberData}") End If ' Retrieve Unicode text using a standard format Dim unicodeText As String = Nothing If Clipboard.TryGetData(DataFormats.UnicodeText, unicodeText) Then - ProcessUnicodeText(unicodeText) + Console.WriteLine($"Unicode: {unicodeText}") End If ' Retrieve raw text data with OLE conversion control Dim rawText As String = Nothing If Clipboard.TryGetData(DataFormats.Text, rawText) Then - ProcessRawText(rawText) + Console.WriteLine($"Raw: {rawText}") End If ' Retrieve file drops using a standard format Dim files As String() = Nothing If Clipboard.TryGetData(DataFormats.FileDrop, files) Then - ProcessFiles(files) + Console.WriteLine($"Files: {String.Join(", ", files)}") End If End Sub ' </BasicTypeSafeRetrieval> @@ -42,19 +42,19 @@ Namespace ClipboardExamples ' Retrieve a custom type stored with SetDataAsJson(Of T)() Dim person As Person = Nothing If Clipboard.TryGetData("Person", person) Then - ProcessPerson(person) + Console.WriteLine($"Person: {person.Name}") End If ' Retrieve application-specific data formats Dim settings As AppSettings = Nothing If Clipboard.TryGetData("MyApp.Settings", settings) Then - ApplySettings(settings) + Console.WriteLine($"Settings: {settings.Theme}") End If ' Retrieve complex custom objects Dim doc As DocumentInfo = Nothing If Clipboard.TryGetData("DocumentData", doc) Then - LoadDocument(doc) + Console.WriteLine($"Document: {doc.Title}") End If End Sub ' </CustomJsonTypes> @@ -74,37 +74,5 @@ Namespace ClipboardExamples Public Property Author As String Public Property Created As DateTime End Class - - Private Shared Sub ProcessTextData(text As String) - Console.WriteLine($"Text: {text}") - End Sub - - Private Shared Sub ProcessNumber(number As Integer) - Console.WriteLine($"Number: {number}") - End Sub - - Private Shared Sub ProcessUnicodeText(text As String) - Console.WriteLine($"Unicode: {text}") - End Sub - - Private Shared Sub ProcessRawText(text As String) - Console.WriteLine($"Raw: {text}") - End Sub - - Private Shared Sub ProcessFiles(files As String()) - Console.WriteLine($"Files: {String.Join(", ", files)}") - End Sub - - Private Shared Sub ProcessPerson(person As Person) - Console.WriteLine($"Person: {person.Name}") - End Sub - - Private Shared Sub ApplySettings(settings As AppSettings) - Console.WriteLine($"Settings: {settings.Theme}") - End Sub - - Private Shared Sub LoadDocument(doc As DocumentInfo) - Console.WriteLine($"Document: {doc.Title}") - End Sub End Class -End Namespace \ No newline at end of file +End Namespace From f5ce268ee711bbabfb9d684d254306f0fbf748d1 Mon Sep 17 00:00:00 2001 From: "Andy De George (from Dev Box)" <adegeo@microsoft.com> Date: Thu, 9 Oct 2025 12:40:37 -0700 Subject: [PATCH 51/51] More prompt updates --- .../Snippets.Push.instructions.md | 3 ++- .github/prompts/Editing.FullPass.prompt.md | 16 +++++++++--- .github/prompts/RefreshLinks.prompt.md | 26 ++++++++++++------- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/.github/instructions/Snippets.Push.instructions.md b/.github/instructions/Snippets.Push.instructions.md index b9a9028c3d..aff9789dd6 100644 --- a/.github/instructions/Snippets.Push.instructions.md +++ b/.github/instructions/Snippets.Push.instructions.md @@ -6,6 +6,8 @@ description: Push inline code block snippets out of articles into standalone fil **IMPORTANT**: Unless otherwise asked to, **only** edit the article file in context. At the end of your operations you may ask for permission to edit other articles that might benefit from the same snippet extraction. +**IMPORTANT**: Don't share code across multiple articles. Each article should have its own copy of the snippet in its own folder structure. + ## Quick Reference **WHEN TO PUSH:** Code >6 lines, complete/compilable examples, or when specifically requested @@ -20,7 +22,6 @@ description: Push inline code block snippets out of articles into standalone fil **PUSH SNIPPETS WHEN:** - Code blocks are longer than 6 lines or the rest of the article is using them - Code demonstrates complete, compilable examples -- Code should not be reused across multiple articles - Code represents a complete application or significant functionality - User specifically requests snippet extraction diff --git a/.github/prompts/Editing.FullPass.prompt.md b/.github/prompts/Editing.FullPass.prompt.md index 312a0915f2..d845dfd373 100644 --- a/.github/prompts/Editing.FullPass.prompt.md +++ b/.github/prompts/Editing.FullPass.prompt.md @@ -8,6 +8,8 @@ description: "Performs comprehensive editing pass following Microsoft Style Guid You are performing an edit pass on a Microsoft documentation article. Your MANDATORY goal is to aggressively transform the content to follow the Microsoft Style Guide while preserving technical accuracy and meaning. +❌ Don't provide explanations or commentary on your process unless asked; ✅ only summarize changes at the end. + ## EDITING APPROACH - FOLLOW THIS METHODOLOGY 1. **Read the entire document first** @@ -39,13 +41,11 @@ You are performing an edit pass on a Microsoft documentation article. Your MANDA 2. **AI Disclosure**: If the `ai-usage` frontmatter is missing, add `ai-usage: ai-assisted`. 3. **Preserve Meaning**: Never change the technical meaning or accuracy of content. 4. **Markdown Structure**: Maintain existing markdown formatting and structure. +5. **Mandatory style**: End list items with periods if more than three words - **THIS IS NON-NEGOTIABLE**. ## MANDATORY TRANSFORMATIONS - Apply These Aggressively -You MUST systematically scan the entire document and apply ALL of these transformations. Do not skip any that apply: - -## Primary Edit Targets - +You MUST systematically scan the entire document and apply ALL of these transformations. When editing, focus on these areas in order of priority: ### 1. VOICE AND TENSE - MANDATORY FIXES @@ -115,6 +115,7 @@ When editing, focus on these areas in order of priority: - ❌ "establish connectivity" → ✅ "connect" - ❌ "implement functionality" → ✅ "implement features" or "add functionality" - ❌ "demonstrate how to" → ✅ "show how to" +- ❌ "additional" → ✅ "other", "more", "another", or "extra" - Look for ANY unnecessarily complex or verbose phrasing **SCAN FOR AND REMOVE unnecessary words (these are examples - find ALL similar patterns):** @@ -145,6 +146,10 @@ When editing, focus on these areas in order of priority: - ❌ "In the event that you need to configure the application, you should..." → ✅ "To configure the application..." - ❌ "Before you can use the feature, you must..." → ✅ "Configure X before using the feature." +**ALWAYS add commas to introductory phrases** +- ❌ "When replacing Newtonsoft the plan switches..." → ✅ "When replacing Newtonsoft, the plan switches..." +- ❌ "In chat you see that it opened..." → ✅ "In chat, you see that it opened..." + **ALWAYS make next steps obvious:** - Use clear transitions - Number steps when there's a sequence @@ -186,6 +191,8 @@ When editing, focus on these areas in order of priority: | "You can" (in instructions) | Direct imperative | Instructions that could be commands | | "allows you to" | "lets you" | Any formal permission language | | "provides the ability to" | "lets you" | Any verbose capability descriptions | +| "Note" | Use >[!NOTE] alert syntax | Any standalone phrase starting with "Note..." | +| "The .NET Framework" | ".NET Framework" | Any instance of "The .NET Framework" | **PATTERN RECOGNITION INSTRUCTIONS:** - These examples represent PATTERNS, not exhaustive lists @@ -198,6 +205,7 @@ When editing, focus on these areas in order of priority: ### Lists - ALWAYS use Oxford comma: "Android, iOS, and Windows" - ALWAYS number ordered lists as "1." for all items (not 1., 2., 3.) +- ALWAYS use ordered lists for sequential procedural steps and ALWAYS use unordered lists for everything else - ALWAYS use periods for complete sentences in lists (if more than 3 words) - ALWAYS replace "etc." with "for example" or complete the list diff --git a/.github/prompts/RefreshLinks.prompt.md b/.github/prompts/RefreshLinks.prompt.md index cac7371e4b..b8abc19bd4 100644 --- a/.github/prompts/RefreshLinks.prompt.md +++ b/.github/prompts/RefreshLinks.prompt.md @@ -8,6 +8,8 @@ description: "Updates link text to match target content headings" You are tasked with checking and updating all links in the current file to ensure their link text accurately reflects the target content's H1 heading or title. +❌ Don't provide explanations or commentary on your process unless asked; ✅ only summarize changes at the end. + ## ⚠️ CRITICAL CONSTRAINT ⚠️ **NO OTHER EDITS OR ALTERATIONS** should be made to the file beyond updating link text. This means: @@ -57,18 +59,21 @@ The file content must remain completely unchanged except for link text updates. - Compare with current link text - Update if different -3. **H1 Extraction Rules**: +3. **Check for bookmark**: + - If the link contains a bookmark (e.g., `file.md#section`), use the markdown heading instead of H1 as the link text + +4. **H1 Extraction Rules**: - Look for markdown H1 headers (`# Heading Text`) - For repository files, check within the first 30 lines - For web pages, extract the `<h1>` tag content or `<title>` tag as fallback - Clean up the extracted text (remove extra whitespace, HTML entities) -4. **Preserve Link Functionality**: +5. **Preserve Link Functionality**: - Keep the original URL intact - Only update the display text portion - Maintain any additional link attributes if present -5. **Error Handling**: +6. **Error Handling**: - If a target cannot be reached or read, leave the link unchanged - If no H1 is found, try alternative heading levels (H2, H3) or page title - Log any issues encountered during processing @@ -76,14 +81,17 @@ The file content must remain completely unchanged except for link text updates. ## Example Transformations ```markdown -Before: [Old Link Text](../wpf/overview.md) -After: [WPF Overview](../wpf/overview.md) +Before: [Old Link Text](../core/install/windows.md) +After: [Install .NET on Windows](../core/install/windows.md) + +Before: [Old Link Text](../core/install/linux.md#system-requirements) +After: [System requirements](../core/install/linux.md#system-requirements) -Before: [Click here](/dotnet-desktop-guide/winforms/getting-started) -After: [Getting Started with Windows Forms](/dotnet-desktop-guide/winforms/getting-started) +Before: [Click here](/dotnet/fundamentals/networking/overview) +After: [Networking in .NET](/dotnet/fundamentals/networking/overview) -Before: [Link](~/dotnet-desktop-guide/wpf/controls/button.md) -After: [Button Control](~/dotnet-desktop-guide/wpf/controls/button.md) +Before: [Link](~/docs/csharp/fundamentals/types/index.md) +After: [C# Type System](~/docs/csharp/fundamentals/types/index.md) Before: [External](https://example.com/some-page) After: [Example Page](https://example.com/some-page)