Code Monkey home page Code Monkey logo

winforms's Introduction

Windows Forms

License: MIT

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

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

Windows Forms Out-Of-Process Designer

For information about the WinForms Designer supporting the .NET runtime and the changes between the .NET Framework Designer (supporting .NET Framework up to version 4.8.1) vs. the .NET Designer (supporting .NET 6, 7, 8, 9+), please see Windows Forms Designer Documentation.

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

Relationship to .NET Framework

This codebase is a fork of the Windows Forms code in the .NET Framework 4.8. We started the migration process by targeting .NET Core 3.0, when we've strived to bring the two runtimes to a parity. Since then, we've done a number of changes, including breaking changes, which diverged the two. For more information about breaking changes, see the Porting guide.

The bar for innovation and new features

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

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

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

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

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

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

What would not make the bar:

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

Please note

⚠️ This repository contains only implementations for Windows Forms for .NET platform.
It does not contain either:

  • The .NET Framework variant of Windows Forms. Issues with .NET Framework, including Windows Forms, should be filed on the Developer Community or Product Support websites. They should not be filed on this repository.
  • The Windows Forms Designer implementations. Issues with the Designer can be filed via VS Feedback tool (top right-hand side icon in Visual Studio) or be filed in this repo using the Windows Forms out-of-process designer issue template.

How can I contribute?

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

How to Engage, Contribute, and Provide Feedback

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

Reporting security issues

Security issues and bugs should be reported privately via email to the Microsoft Security Response Center (MSRC) [email protected]. You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Further information, including the MSRC PGP key, can be found in the Security TechCenter. Also see info about related Microsoft .NET Core and ASP.NET Core Bug Bounty Program.

Code of Conduct

This project uses the .NET Foundation Code of Conduct to define expected conduct in our community. Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting a project maintainer at [email protected].

License

.NET (including the Windows Forms repository) is licensed under the MIT license.

.NET Foundation

.NET Windows Forms is a .NET Foundation project.
See the .NET home repository to find other .NET-related projects.

winforms's People

Contributors

adamyoblick avatar dotnet-bot avatar dotnet-maestro[bot] avatar dreddy-work avatar elachlan avatar epica3055 avatar gpetrou avatar halgab avatar hughbe avatar jeremykuhne avatar jsoref avatar kant2002 avatar klausloeffelmann avatar leafshi1 avatar lonitra avatar mellinoe avatar mmitche avatar qmfrederik avatar russkie avatar safern avatar sergeysmirnov-akvelon avatar sharwell avatar simonzhao888 avatar stephentoub avatar tanya-solyanik avatar v-elnovikova avatar viktorhofer avatar vladimir-krestov avatar weltkante avatar zsd4yr avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

winforms's Issues

win-x64 publish with Core3 Preview and VS2019 results in ""CheckEmbeddedRootDescriptor" task was not given a value for the required parameter "AssemblyPath""

I have been trying to publish a plain dotnet new winforms app by following the steps here, but I end up with error: error MSB4044: The "CheckEmbeddedRootDescriptor" task was not given a value for the required parameter "AssemblyPath".

See attached image for the whole process.

I am running VS2019 Preview and have the following SDKs installed: https://www.screencast.com/t/29MbjIeY04

Any advice on how I can overcome this?
linker_issue

Add the capability to automatically close the MessageBox after the specific timeout.

This request is based on popular SO question: Close a MessageBox after several seconds (100+ votes).
StackOverflow Answer

Rationale

When developing LOB application it is quite often needed to interact with the user via the MessageBox which automatically closes after the specific timeout. The standard MessageBox.Show API does not provide this capability.
The new API should be based on standard Win32 MessageBox and should be compatible with corresponding .Net implementation (System.Windows.Forms.MessageBox).

The AutoClosingMessageBox repository contains a good example of WinAPI-based wrapper on standard Win32 MessageBox compatible with the .Net System.Windows.Forms.MessageBox.
Nuget Version

Usage

Here how you can use the new API:

Scenario 1: Fire and forget - it about to be closed after default timeout(1000ms)

AutoClosingMessageBox.Show("Hello, you are using the AutoClosingMessageBox first time!");

Scenario 2: Wait for some result or make the default decision

var result = AutoClosingMessageBox.Show(
            text: "To be or not to be?", 
            caption: "The question",
            timeout: 2500,
            buttons: MessageBoxButtons.YesNo,
            defaultResult: DialogResult.Yes);
if(result == DialogResult.Yes) {
    // to be
}
else { 
    // or not
}

Additionaly you can use the AutoClosingMessageBox.Factory method to wrap the specific MessageBox showing. This way allows us do not provide all the AutoClosingMessageBox.Show method overloads which associated with the corresponting System.Windows.Forms.MessageBox.Show methods.

var toBeOrNotToBeQuestion = AutoClosingMessageBox.Factory(
        showMethod: (caption, buttons) =>
            MessageBox.Show(this, "To be or not to be?", caption, buttons, MessageBoxIcon.Question),
        caption: "The question"
    );
if(DialogResult.Yes == toBeOrNotToBeQuestion.Show(
                            timeout: 2500,
                            buttons: MessageBoxButtons.YesNo,
                            defaultResult: DialogResult.Yes)) {
    // to be
}
else {
    // or not
}

Proposed API:

public static class AutoClosingMessageBox {
    public static DialogResult Show(string text, string caption = null, int timeoutMilliseconds = 1000, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult defaultResult = DialogResult.None);
    public static DialogResult Show(IWin32Window owner, string text, string caption = null, int timeoutMilliseconds = 1000, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult defaultResult = DialogResult.None);
}

The AutoClosingMessageBox.Factory method (optional, but suggested):

public static class AutoClosingMessageBox {
    public static IAutoClosingMessageBox Factory(Func<string, MessageBoxButtons, DialogResult> showMethod, string caption = null);
    //
    public interface IAutoClosingMessageBox {
        DialogResult Show(int timeoutMilliseconds = 1000, MessageBoxButtons buttons = MessageBoxButtons.OK, DialogResult defaultResult = DialogResult.None);
    }
}

Linux 3.0 issue

  • .NET Core Version: 3.0 Preview1
  • Have you experienced this same bug with .NET Framework?: Yes/No
    No

Problem description:
I am running 3.0 winform application on linux with following command
dotnet run
But getting error

/home/owner/dotnet/sdk/3.0.100-preview-009812/Sdks/Microsoft.NET.Sdk.WindowsDesktop/targets/Microsoft.NET.Sdk.WindowsDesktop.targets(14,2): error MSB4019: The imported project "/home/owner/dotnet/sdk/3.0.100-preview-009812/Sdks/Microsoft.NET.Sdk.WindowsDesktop/targets/Microsoft.WinFX.targets" was not found. Confirm that the path in the declaration is correct, and that the file exists on disk. [/home/owner/projects/dotnet3/dotnet3.csproj]

The build failed. Please fix the build errors and run again.

I checked my path variable as well as the Microsoft.WinFX.targets exist in the path

System.Drawing.Common.Tests fails 10 tests in non-English Windows

System.Drawing.Common.Tests fails 10 tests in non-English Windows with next log:

  Starting:    System.Drawing.Common.Tests
     System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(fontStyle: Bold, Italic, Strikeout, gdiCharSet: 1, gdiVerticalFont: True, expectedNamePrefix: \"@\", expectedWeight: 700) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(719,0): at System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(FontStyle fontStyle, Byte gdiCharSet, Boolean gdiVerticalFont, String expectedNamePrefix, Int32 expectedWeight)
     System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(fontStyle: Regular, gdiCharSet: 0, gdiVerticalFont: False, expectedNamePrefix: \"\", expectedWeight: 400) [FAIL]
        Assert.Equal() Failure
        Expected: 0
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(719,0): at System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(FontStyle fontStyle, Byte gdiCharSet, Boolean gdiVerticalFont, String expectedNamePrefix, Int32 expectedWeight)
     System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(fontStyle: Regular, gdiCharSet: 10, gdiVerticalFont: False, expectedNamePrefix: \"\", expectedWeight: 400) [FAIL]
        Assert.Equal() Failure
        Expected: 10
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(719,0): at System.Drawing.Tests.FontTests.ToLogFont_Invoke_ReturnsExpected(FontStyle fontStyle, Byte gdiCharSet, Boolean gdiVerticalFont, String expectedNamePrefix, Int32 expectedWeight)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: SystemDefault, expectedQuality: 0) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: AntiAlias, expectedQuality: 3) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: AntiAliasGridFit, expectedQuality: 3) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: SingleBitPerPixel, expectedQuality: 3) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: SingleBitPerPixelGridFit, expectedQuality: 3) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(textRenderingHint: ClearTypeGridFit, expectedQuality: 5) [FAIL]
        Assert.Equal() Failure
        Expected: 1
        Actual:   204
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\tests\FontTests.cs(756,0): at System.Drawing.Tests.FontTests.ToLogFont_InvokeGraphics_ReturnsExpected(TextRenderingHint textRenderingHint, Int32 expectedQuality)
     System.Drawing.Imaging.Tests.MetafileTests.Ctor_StringIntPtrEmfType_Success(emfType: EmfPlusDual) [FAIL]
        System.Runtime.InteropServices.ExternalException : A generic error occurred in GDI+.
        Stack Trace:
           C:\Code\corefx\src\System.Drawing.Common\src\System\Drawing\Imaging\Metafile.Windows.cs(264,0): at System.Drawing.Imaging.Metafile..ctor(String fileName, IntPtr referenceHdc, EmfType type, String description)
           C:\Code\corefx\src\System.Drawing.Common\src\System\Drawing\Imaging\Metafile.Windows.cs(241,0): at System.Drawing.Imaging.Metafile..ctor(String fileName, IntPtr referenceHdc, EmfType type)
           C:\Code\corefx\src\System.Drawing.Common\tests\Imaging\MetafileTests.cs(399,0): at System.Drawing.Imaging.Tests.MetafileTests.Ctor_StringIntPtrEmfType_Success(EmfType emfType)
  Finished:    System.Drawing.Common.Tests

On my computer font.ToLogFont(logFont); always set logFont.lfCharSet to 204.

Is it error in test or in implementation?

Component designer does not display when targeting .NET Core/.NET Standard

From @JinShil on April 29, 2017 7:47

.Net Standard 2.0 and .Net Core 2.0 have included APIs in System.ComponentModel for building and extending the Visual Studio designer (e.g Component class, DesignerAttribute, TypeConverter, etc..)

However, if one tries to use these classes in the current release of Visual Studio 2017 to create designers for their classes, Visual Studio displays errors in the designer like

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

namespace CoreDesignerTest
{
    public class Class1 : Component
    {
    }
}

In Visual Studio, right-click on the "Class1.cs" node and choose "View Designer".

Could not load file or assembly 'System.ComponentModel.Primitives, Version=4.2.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' or one of its dependencies. The system cannot find the file specified.

With some hacking in my .config files, I can resolve the above error, but eventually Visual Studio fails to load the .Net Core assemblies with an "Invalid Format" error.

I'm assuming this is due to the fact that Visual Studio, being a .Net Framework-based application, is trying to load a .Net Core assembly into a .Net Framework application, and therefore failing.

My question is, with the coming release of .Net Core 2.0 and .Net Standard 2.0, will there also be an accompanying Visual Studio update that will provide the ability to create designers for .Net Core 2.0 and .Net Standard 2.0 classes?

Copied from original issue: dotnet/corefx#19139

Add documentation on running WInformsControlsTest when validating changes

This will be a temporary measure for basic validation of changes until functional test are incorporated in the process. Consider covering the following points:

  1. how to build the app
  2. how to run it against the newly updated System.Windows.Forms.dll and how to put breakpoint in the newly changed code
  3. what actions to perform in the app besides clicking all the buttons (move across the screens, once the sample is dpi aware)
  4. how to add missing controls, and edit the SP script

Windows Task Dialog

Hi,

On Windows Vista and higher, the Task Dialog is available that provides many more features than a Message Box. While you can show a Message Box in WinForms and WPF, there is no "official" implementation of the Task Dialog yet in .NET WinForms/WPF.

There was an implementation in the Windows API Code Pack 1.1, but it is no longer available/updated, it did not implement all features (like navigation or modifying common/standard buttons), and I believe it had some memory management issues (like not calling Marshal.DestroyStructure() after calling Marshal.StructureToPtr() in order to free allocated strings for custom/radio buttons) and a few other issues.

At my company, we currently use the Task Dialog in a (commercial) WPF application to show a marquee progress bar while an operation (like database backup) is running, and then navigate it to one showing a green header to indicate the operation is finished.

Visual Studio is also using a Task Dialog:
taskdialog-vs

Also, the Windows Design Guidelines (Desktop Apps) for Messages and Dialog Boxes show features of the task dialog.

Do you think a Task Dialog could also be added directly to WinForms/WPF? Thank you!

Edit:


Rationale and Usage

The Windows Task Dialog (which is available since Windows Vista) has a lot of configuration options comparing to a regular Message Box, can show additional controls like a progress bar, and supports event handling. However, it has not yet been integrated officially into WinForms/WPF, so if you wanted to use it, you had to implement the native APIs yourself, or use a 3rd party library.

Implementing the Task Dialog directly in WinForms allows users to directly use the Task Dialog in any new WinForms/WPF .NET Core application, just like a MessageBox. You can then either use the simple static Show() method (similar to a MessageBox), or you can create an instance of the TaskDialog, configure its TaskDialogPage and then show it.

Features of the proposed Task Dialog:

  • Supports all of the native Task Dialog elements (like custom buttons/command links, progress bar, radio buttons, checkbox, expanded area, footer)
  • Some dialog elements can be updated while the dialog is displayed, and the dialog can be closed from code
  • Additionally to standard icons, supports shield icons that show a green, yellow, red, gray or blue bar
  • Can navigate to a new page (by reconstructing the dialog from current properties) by calling TaskDialogPage.Navigate(TaskDialogPage) while the dialog is displayed
  • Can be shown modal or non-modal (when showing modal, can be centered to the parent)
  • Exposes its window handle (hWnd) through the Handle property so that the dialog window can be further manipulated (or used as owner for another window)

See also the Task Dialog Demo App for examples.

Show a simple Task Dialog

    TaskDialogButton resultButton = TaskDialog.ShowDialog(new TaskDialogPage()
    {
        Text = "Hello World!",
        Heading = "Hello Task Dialog!   👍",
        Caption = "Dialog Title",
        Buttons = {
            TaskDialogButton.Yes,
            TaskDialogButton.Cancel
        },
        Icon = TaskDialogIcon.ShieldSuccessGreenBar
    });

    if (resultButton == TaskDialogButton.Yes)
    {
        // Do something...
    }

simpletaskdialog

Dialog similar to the Visual Studio dialog

    TaskDialogCommandLinkButton buttonRestart = new TaskDialogCommandLinkButton()
    {
        Text = "&Restart under different credentials",
        DescriptionText = "This text will be shown in the second line.",
        ShowShieldIcon = true
    };

    TaskDialogCommandLinkButton buttonCancelTask = new TaskDialogCommandLinkButton()
    {
        Text = "&Cancel the Task and return"
    };

    var page = new TaskDialogPage()
    {
        Icon = TaskDialogIcon.Shield,
        Heading = "This task requires the application to have elevated permissions.",
        // TODO - Hyperlinks will be possible in a future version
        Text = "Why is using the Administrator or other account necessary?",

        // TODO - will be possible in a future version
        //EnableHyperlinks = true,

        Buttons =
        {
            TaskDialogButton.Cancel,
            buttonRestart,
            buttonCancelTask
        },
        DefaultButton = buttonCancelTask,

        // Show a expander.
        Expander = new TaskDialogExpander()
        {
            Text = "Some expanded Text",
            CollapsedButtonText = "View error information",
            ExpandedButtonText = "Hide error information",
            Position = TaskDialogExpanderPosition.AfterFootnote
        }
    };

    // Show the dialog and check the result.
    TaskDialogButton result = TaskDialog.ShowDialog(page);

    if (result == buttonRestart)
    {
        Console.WriteLine("Restarting...");
    }

grafik

Show a multi-page dialog that shows current progress, then navigates to a result

See also: Multi-page dialog boxes

    // Disable the "Yes" button and only enable it when the check box is checked.
    // Also, don't close the dialog when this button is clicked.
    var initialButtonYes = TaskDialogButton.Yes;
    initialButtonYes.Enabled = false;
    initialButtonYes.AllowCloseDialog = false;

    var initialPage = new TaskDialogPage()
    {
        Caption = "My Application",
        Heading = "Clean up database?",
        Text = "Do you really want to do a clean-up?\nThis action is irreversible!",
        Icon = TaskDialogIcon.ShieldWarningYellowBar,
        AllowCancel = true,

        Verification = new TaskDialogVerificationCheckBox()
        {
            Text = "I know what I'm doing"
        },

        Buttons =
        {
            TaskDialogButton.No,
            initialButtonYes
        },
        DefaultButton = TaskDialogButton.No
    };

    // For the "In Progress" page, don't allow the dialog to close, by adding
    // a disabled button (if no button was specified, the task dialog would
    // get an (enabled) 'OK' button).
    var inProgressCloseButton = TaskDialogButton.Close;
    inProgressCloseButton.Enabled = false;

    var inProgressPage = new TaskDialogPage()
    {
        Caption = "My Application",
        Heading = "Operation in progress...",
        Text = "Please wait while the operation is in progress.",
        Icon = TaskDialogIcon.Information,

        ProgressBar = new TaskDialogProgressBar()
        {
            State = TaskDialogProgressBarState.Marquee
        },

        Expander = new TaskDialogExpander()
        {
            Text = "Initializing...",
            Position = TaskDialogExpanderPosition.AfterFootnote
        },

        Buttons =
        {
            inProgressCloseButton
        }
    };

    var finishedPage = new TaskDialogPage()
    {
        Caption = "My Application",
        Heading = "Success!",
        Text = "The operation finished.",
        Icon = TaskDialogIcon.ShieldSuccessGreenBar,
        Buttons =
        {
            TaskDialogButton.Close
        }
    };

    TaskDialogButton showResultsButton = new TaskDialogCommandLinkButton("Show &Results");
    finishedPage.Buttons.Add(showResultsButton);

    // Enable the "Yes" button only when the checkbox is checked.
    TaskDialogVerificationCheckBox checkBox = initialPage.Verification;
    checkBox.CheckedChanged += (sender, e) =>
    {
        initialButtonYes.Enabled = checkBox.Checked;
    };

    // When the user clicks "Yes", navigate to the second page.
    initialButtonYes.Click += (sender, e) =>
    {
        // Navigate to the "In Progress" page that displays the
        // current progress of the background work.
        initialPage.Navigate(inProgressPage);

        // NOTE: When you implement a "In Progress" page that represents
        // background work that is done e.g. by a separate thread/task,
        // which eventually calls Control.Invoke()/BeginInvoke() when
        // its work is finished in order to navigate or update the dialog,
        // then DO NOT start that work here already (directly after
        // setting the Page property). Instead, start the work in the
        // TaskDialogPage.Created event of the new page.
        //
        // This is because if you started it here, then when that other
        // thread/task finishes and calls BeginInvoke() to call a method in
        // the GUI thread to update or navigate the dialog, there is a chance
        // that the callback might be called before the dialog completed
        // navigation (*) (as indicated by the Created event of the
        // new page), and the dialog might not be updatable in that case.
        // (The dialog can be closed or navigated again, but you cannot
        // change e.g. text properties of the page).
        //
        // If that's not possible for some reason, you need to ensure
        // that you delay the call to update the dialog until the Created
        // event of the next page has occured.
        // 
        // 
        // (*) Background info: Although the WinForms implementation of
        // Control.Invoke()/BeginInvoke() posts a new message in the
        // control's owning thread's message queue every time it is
        // called (so that the callback can be called later by the
        // message loop), when processing the posted message in the
        // control's window procedure, it calls ALL stored callbacks
        // instead of only the next one.
        // 
        // This means that even if you start the work after setting
        // the Page property (which means BeginInvoke() can only be
        // called AFTER starting navigation), the callback specified
        // by BeginInvoke might still be called BEFORE the task dialog
        // can process its posted navigation message.
    };

    // Simulate work by starting an async operation from which we are updating the
    // progress bar and the expander with the current status.
    inProgressPage.Created += async (s, e) =>
    {
        // Run the background operation and iterate over the streamed values to update
        // the progress. Because we call the async method from the GUI thread,
        // it will use this thread's synchronization context to run the continuations,
        // so we don't need to use Control.[Begin]Invoke() to schedule the callbacks.
        var progressBar = inProgressPage.ProgressBar;

        await foreach (int progressValue in StreamBackgroundOperationProgressAsync())
        {
            // When we display the first progress, switch the marquee progress bar
            // to a regular one.
            if (progressBar.State == TaskDialogProgressBarState.Marquee)
                progressBar.State = TaskDialogProgressBarState.Normal;

            progressBar.Value = progressValue;
            inProgressPage.Expander.Text = $"Progress: {progressValue} %";
        }

        // Work is finished, so navigate to the third page.
        inProgressPage.Navigate(finishedPage);
    };

    // Show the dialog (modeless).
    TaskDialogButton result = TaskDialog.ShowDialog(initialPage);
    if (result == showResultsButton)
    {
        Console.WriteLine("Showing Results!");
    }


    static async IAsyncEnumerable<int> StreamBackgroundOperationProgressAsync()
    {
        // Note: The code here will run in the GUI thread - use
        // "await Task.Run(...)" to schedule CPU-intensive operations in a
        // worker thread.

        // Wait a bit before reporting the first progress.
        await Task.Delay(2800);

        for (int i = 0; i <= 100; i += 4)
        {
            // Report the progress.
            yield return i;

            // Wait a bit to simulate work.
            await Task.Delay(200);
        }
    }

wizarddialog

Other examples from existing applications

"Save document" dialog from Notepad/Paint/WordPad

    TaskDialogButton btnCancel = TaskDialogButton.Cancel;
    TaskDialogButton btnSave = new TaskDialogButton("&Save");
    TaskDialogButton btnDontSave = new TaskDialogButton("Do&n't save");

    var page = new TaskDialogPage()
    {
        Caption = "My Application",
        Heading = "Do you want to save changes to Untitled?",
        Buttons =
        {
            btnCancel,
            btnSave,
            btnDontSave
        }
    };

    // Show a modal dialog, then check the result.
    TaskDialogButton result = TaskDialog.ShowDialog(this, page);

    if (result == btnSave)
        Console.WriteLine("Saving");
    else if (result == btnDontSave)
        Console.WriteLine("Not saving");
    else
        Console.WriteLine("Canceling");

taskdialog-savedocument

Windows 7 Minesweeper Difficulty Selection

    var page = new TaskDialogPage()
    {
        Caption = "Minesweeper",
        Heading = "What level of difficulty do you want to play?",
        AllowCancel = true,

        Footnote = new TaskDialogFootnote()
        {
            Text = "Note: You can change the difficulty level later " +
                "by clicking Options on the Game menu.",
        },

        Buttons =
        {
            new TaskDialogCommandLinkButton("&Beginner", "10 mines, 9 x 9 tile grid")
            {
                Tag = 10
            },
            new TaskDialogCommandLinkButton("&Intermediate", "40 mines, 16 x 16 tile grid")
            {
                Tag = 40
            },
            new TaskDialogCommandLinkButton("&Advanced", "99 mines, 16 x 30 tile grid")
            {
                Tag = 99
            }
        }
    };

    TaskDialogButton result = TaskDialog.ShowDialog(this, page);

    if (result.Tag is int resultingMines)
        Console.WriteLine($"Playing with {resultingMines} mines...");
    else
        Console.WriteLine("User canceled.");

taskdialog-minesweeperdifficulty

Windows Security dialog when trying to access network files

    var page = new TaskDialogPage()
    {
        Caption = "My App Security",
        Heading = "Opening these files might be harmful to your computer",
        Text = "Your Internet security settings blocked one or more files from " + 
            "being opened. Do you want to open these files anyway?",
        Icon = TaskDialogIcon.ShieldWarningYellowBar,
        // TODO - will be possible in a future version
        //EnableHyperlinks = true,

        Expander = new TaskDialogExpander("My-File-Sample.exe"),

        Footnote = new TaskDialogFootnote()
        {
            // TODO - Hyperlinks will be possible in a future version
            Text = "How do I decide whether to open these files?",
        },

        Buttons =
        {
            TaskDialogButton.OK,
            TaskDialogButton.Cancel
        },
        DefaultButton = TaskDialogButton.Cancel
    };

    TaskDialogButton result = TaskDialog.ShowDialog(this, page);

    if (result == TaskDialogButton.OK)
    {
        Console.WriteLine("OK selected");
    }

taskdialog-windowssecurity

Auto-closing Dialog (closes after 5 seconds)

    const string textFormat = "Reconnecting in {0} seconds...";
    int remainingTenthSeconds = 50;

    var reconnectButton = new TaskDialogButton("&Reconnect now");
    var cancelButton = TaskDialogButton.Cancel;

    var page = new TaskDialogPage()
    {
        Heading = "Connection lost; reconnecting...",
        Text = string.Format(textFormat, (remainingTenthSeconds + 9) / 10),
        ProgressBar = new TaskDialogProgressBar()
        {
            State = TaskDialogProgressBarState.Paused
        },
        Buttons =
        {
            reconnectButton,
            cancelButton
        }
    };

    // Create a WinForms timer that raises the Tick event every tenth second.
    using var timer = new System.Windows.Forms.Timer()
    {
        Enabled = true,
        Interval = 100
    };

    timer.Tick += (s, e) =>
    {
        remainingTenthSeconds--;
        if (remainingTenthSeconds > 0)
        {
            // Update the remaining time and progress bar.
            page.Text = string.Format(textFormat, (remainingTenthSeconds + 9) / 10);
            page.ProgressBar.Value = 100 - remainingTenthSeconds * 2;
        }
        else
        {
            // Stop the timer and click the "Reconnect" button - this will
            // close the dialog.
            timer.Enabled = false;
            reconnectButton.PerformClick();
        }
    };

    TaskDialogButton result = TaskDialog.ShowDialog(this, page);
    if (result == reconnectButton)
        Console.WriteLine("Reconnecting.");
    else
        Console.WriteLine("Not reconnecting.");

autoclosingdialog

Proposed API

TODO: Which namespace to use for the types? In the PR I used System.Windows.Forms for now.

public class TaskDialog : IWin32Window
{
    // Returns the window handle while the dialog is shown, otherwise returns IntPtr.Zero.
    public IntPtr Handle { get; }

    // Note: The ShowDialog() methods do not return until the
    // dialog is closed (similar to MessageBox.Show()), regardless of whether the
    // dialog is shown modal or non-modal.

    public static TaskDialogButton ShowDialog(TaskDialogPage page, TaskDialogStartupLocation startupLocation = TaskDialogStartupLocation.CenterOwner);
    public static TaskDialogButton ShowDialog(IWin32Window owner, TaskDialogPage page, TaskDialogStartupLocation startupLocation = TaskDialogStartupLocation.CenterOwner);
    public static TaskDialogButton ShowDialog(IntPtr hwndOwner, TaskDialogPage page, TaskDialogStartupLocation startupLocation = TaskDialogStartupLocation.CenterOwner);

    // Close() will simulate a click on the "Cancel" button (but you don't
    // have to add a "Cancel" button for this).
    public void Close();
}
public class TaskDialogPage
{
    public TaskDialogPage();

    public TaskDialog? BoundDialog { get; }

    // Properties "Caption", "MainInstruction", "Text", "Icon" can be set
    // set while the dialog is shown, to update the dialog.
    public string? Caption { get; set; }
    public string? Heading { get; set; }
    public string? Text { get; set; }

    // Icon can either be a standard icon or a icon handle.
    // (In the future, we could allow to show a resource icon.)
    // Note that while the dialog is shown, you cannot switch between a 
    // handle icon type and a non-handle icon type.
    // The same applies to the footer icon.
    public TaskDialogIcon? Icon { get; set; }    
    
    public bool AllowCancel { get; set; }
    public bool AllowMinimize { get; set; }
    public bool RightToLeftLayout { get; set; }
    public bool SizeToContent { get; set; }

    public TaskDialogButtonCollection Buttons { get; set; }
    public TaskDialogRadioButtonCollection RadioButtons { get; set; }
    public TaskDialogButton? DefaultButton { get; set; }

    // Note: When creating a TaskDialogPage instance, these four properties
    // contain default/empty control instances (for better Designer support) that
    // do not show up in the dialog unless you modify their properties
    // (because their initial "Text" is null and initial ProgressBarState is "None" -
    // however when you create a new ProgressBar instance, its default State
    // is "Normal"), but you can also set them to null.
    public TaskDialogVerificationCheckBox? Verification { get; set; }
    public TaskDialogExpander? Expander { get; set; }
    public TaskDialogFootnote? Footnote { get; set; }
    public TaskDialogProgressBar? ProgressBar { get; set; }

    // See section "Event Cycle" for a diagram illustrating the events.

    // Raised after this TaskDialogPage is bound to a TaskDialog (and therefore
    // the controls have been created): after the dialog was created (directly after event
    // TaskDialog.Opened/TDN_CREATED) or navigated (in the TDN_NAVIGATED handler).
    public event EventHandler? Created;
    // Raised when this TaskDialogPage is about to be unbound from a TaskDialog
    // (and therefore the controls are about to be destroyed): when the dialog is
    // about to be destroyed (directly before event TaskDialog.Closed) or about
    // to navigate.
    public event EventHandler? Destroyed;

    // Raised when the user presses F1 or clicks the "Help" standard button
    public event EventHandler? HelpRequest;

    protected internal void OnCreated(EventArgs e);
    protected internal void OnDestroyed(EventArgs e);
    protected internal void OnHelpRequest(EventArgs e);
}
public class TaskDialogIcon : IDisposable
{
    // "Standard" icons
    public static readonly TaskDialogIcon None;
    public static readonly TaskDialogIcon Information;
    public static readonly TaskDialogIcon Warning;
    public static readonly TaskDialogIcon Error;
    public static readonly TaskDialogIcon Shield;
    public static readonly TaskDialogIcon ShieldBlueBar;
    public static readonly TaskDialogIcon ShieldGrayBar;
    public static readonly TaskDialogIcon ShieldWarningYellowBar;
    public static readonly TaskDialogIcon ShieldErrorRedBar;
    public static readonly TaskDialogIcon ShieldSuccessGreenBar;

    public TaskDialogIcon(Bitmap image);
    public TaskDialogIcon(Icon icon);
    public TaskDialogIcon(IntPtr iconHandle);

    // Note: This will throw (InvalidOperationException) if this is an
    // instance representing a standard icon.
    public IntPtr IconHandle { get; }
}
public abstract class TaskDialogControl
{
    public TaskDialogPage? BoundPage { get; }
    public object? Tag { get; set; }
}
public class TaskDialogButton : TaskDialogControl
{
    public TaskDialogButton();
    public TaskDialogButton(string? text, bool enabled = true, bool allowCloseDialog = true);

    public static TaskDialogButton OK { get; }
    public static TaskDialogButton Cancel { get; }
    public static TaskDialogButton Abort { get; }
    public static TaskDialogButton Retry { get; }
    public static TaskDialogButton Ignore { get; }
    public static TaskDialogButton Yes { get; }
    public static TaskDialogButton No { get; }
    public static TaskDialogButton Close { get; }
    // Note: Clicking the "Help" button will not close the dialog, but will
    // raise the TaskDialogPage.Help event.
    public static TaskDialogButton Help { get; }
    public static TaskDialogButton TryAgain { get; }
    public static TaskDialogButton Continue { get; }
    
    // Properties "Enabled" and "ShowShieldIcon" can be set while
    // the dialog is shown.
    public string? Text { get; set; }
    public bool AllowCloseDialog { get; set; }
    public bool Enabled { get; set; }
    public bool ShowShieldIcon { get; set; }
    // Setting "Visible" to false means the button will not be shown in the task dialog
    // (the property cannot be set while the dialog is shown). This allows you
    // to intercept button click events, e.g. "Cancel" when "AllowCancel" is true
    // and the user presses ESC, without having to actually show a "Cancel" button.
    public bool Visible { get; set; }

    // Raised when this button is clicked while the dialog is shown (either because the
    // user clicked it, or by calling PerformClick() or TaskDialog.Close()).
    public event EventHandler? Click;

    public override bool Equals(object? obj);
    public override int GetHashCode();
    public void PerformClick();
    public override string ToString();

    public static bool operator ==(TaskDialogButton? b1, TaskDialogButton? b2);
    public static bool operator !=(TaskDialogButton? b1, TaskDialogButton? b2);
}
public sealed class TaskDialogCommandLinkButton : TaskDialogButton
{
    public TaskDialogCommandLinkButton();
    public TaskDialogCommandLinkButton(string? text, string? descriptionText = null, bool enabled = true, bool allowCloseDialog = true);

    public string? DescriptionText { get; set; }
}
public sealed class TaskDialogRadioButton : TaskDialogControl
{
    public TaskDialogRadioButton();
    public TaskDialogRadioButton(string? text);

    public string? Text { get; set; }
    // Properties "Enabled" and "Checked" can be set while the dialog is shown
    // (but "Checked" can then only be set to "true").
    public bool Checked { get; set; }
    public bool Enabled { get; set; }

    // Raised when the "Checked" property changes while the dialog is shown (because
    // the user clicked one of the radio buttons, or due to setting the "Checked"
    // property of one of the radio buttons to "true").
    public event EventHandler? CheckedChanged;

    public override string ToString();
}
public sealed class TaskDialogVerificationCheckBox : TaskDialogControl
{
    public TaskDialogVerificationCheckBox();
    public TaskDialogVerificationCheckBox(string? text, bool isChecked = false);

    public string? Text { get; set; }
    // "Checked" can be set while the dialog is shown.
    public bool Checked { get; set; }

    // Raised when the "Checked" property changes while the dialog is shown (because
    // the user clicked it or due to setting the "Checked" property).
    public event EventHandler? CheckedChanged;

    public override string ToString();

    public static implicit operator TaskDialogVerificationCheckBox(string verificationText);
}
public sealed class TaskDialogExpander : TaskDialogControl
{
    public TaskDialogExpander();
    public TaskDialogExpander(string? text);

     // "Text" can be set while the dialog is shown.
    public string? Text { get; set; }
    public string? ExpandedButtonText { get; set; }
    public string? CollapsedButtonText { get; set; }
    // Note: "Expanded" can NOT be set while the dialog is shown.
    public bool Expanded { get; set; }
    public TaskDialogExpanderPosition Position { get; set; }

    // Raised when the "Expanded" property changes while the dialog is shown (because
    // the user clicked the expando button).
    public event EventHandler? ExpandedChanged;

    public override string ToString();
}
public sealed class TaskDialogFootnote : TaskDialogControl
{
    public TaskDialogFootnote();
    public TaskDialogFootnote(string? text);

    // Properties "Text",  "Icon" can be set while
    // the dialog is shown (see comments for TaskDialogPage.Icon).
    public string? Text { get; set; }
    public TaskDialogIcon? Icon { get; set; }

    public override string ToString();

    public static implicit operator TaskDialogFootnote(string footnoteText);
}
public sealed class TaskDialogProgressBar : TaskDialogControl
{
    public TaskDialogProgressBar();
    public TaskDialogProgressBar(TaskDialogProgressBarState state);

    // Properties "State", "Minimum", "Maximum", "Value", "MarqueeSpeed" can
    // be set while the dialog is shown.
    public TaskDialogProgressBarState State { get; set; } // "Style"?
    public int Minimum { get; set; }
    public int Maximum { get; set; }
    public int Value { get; set; }
    public int MarqueeSpeed { get; set; }
}
// Note: The button order in this collection is not necessarily the same as the actual
// order of buttons displayed in the dialog. See:
// https://github.com/kpreisser/winforms/issues/5#issuecomment-584318609
public class TaskDialogButtonCollection : Collection<TaskDialogButton>
{
    public TaskDialogButtonCollection();

    public TaskDialogButton Add(string? text, bool enabled = true, bool allowCloseDialog = true);
    protected override void ClearItems();
    protected override void InsertItem(int index, TaskDialogButton item);
    protected override void RemoveItem(int index);
    protected override void SetItem(int index, TaskDialogButton item);
}
public class TaskDialogRadioButtonCollection : System.Collections.ObjectModel.Collection<TaskDialogRadioButton>
{
    public TaskDialogRadioButtonCollection();

    public TaskDialogRadioButton Add(string? text);

    protected override void ClearItems();
    protected override void InsertItem(int index, TaskDialogRadioButton item);
    protected override void RemoveItem(int index);
    protected override void SetItem(int index, TaskDialogRadioButton item);
}
public enum TaskDialogStartupLocation
{
    CenterScreen = 0,
    CenterOwner = 1
}
// Rename to "TaskDialogProgressBarStyle"?
public enum TaskDialogProgressBarState
{
    Normal = 0,
    Paused = 1,
    Error = 2,
    Marquee = 3,
    MarqueePaused = 4,
    // "None" is used for the default ProgressBar instance in the TaskDialogPage so
    // that you need to set the State to a different value (or create a new ProgressBar
    // instance) to actually show a progress bar in the dialog.
    None = 5
}
public enum TaskDialogExpanderPosition
{
    AfterText = 0,
    AfterFootnote = 1
}

Event Cycle

The events in the proposed API currently have the folowing cycle at runtime (the diagram illustrates navigating the dialog in the TaskDialogButton.Click event):

Caller                                          Events

TaskDialog.ShowDialog();
       ↓
    (Calls TaskDialogIndirect())
       ────────────>
                    ↓      (Window handle available now)
                Callback(TDN_CREATED) ─────────> TaskDialogPage[1].Created
                    ↓      (Window becomes visible)
                    ↓
                  (...)
                    ↓
                Callback(TDN_BUTTON_CLICKED) ──> TaskDialogButton.Click
                                                   ↓
                      TaskDialogPage.Navigate() <───────
                              ↓
                              ─────────────────> TaskDialogPage[1].Destroyed
                              ↓
                    <──────────
                    ↓
                Callback(TDN_NAVIGATED) ───────> TaskDialogPage[2].Created
                    ↓
                  (...)
                    ↓
                Callback(TDN_BUTTON_CLICKED) ──> TaskDialogButton.Click
                    ↓      (Window closes; Dialog no longer navigable as it set a result button)
                    ↓
                Callback(TDN_DESTROYED) ───────> TaskDialogPage[2].Destroyed
                    ↓      (Window handle no longer available)
       <────────────
       (TaskDialogIndirect() returns)
       ↓
(TaskDialog.ShowDialog() returns)

Implementation

The proposed API is implemented with PR #1133.

API Updates

  • Removed property TaskDialogContents.DoNotSetForeground as it doesn't seem to have an effect
  • Removed base classes TaskDialogControlCollection and TaskDialogButtonCollection
  • TaskDialogCustomButtonCollection and TaskDialogRadioButtonCollection inherit from Collection instead of KeyedCollection
  • Added an implicit cast operator from TaskDialogButtons to TaskDialogCommonButtonCollection
  • Removed property ResultVerificationFlagChanged from TaskDialog
  • Renamed property ExpandedByDefault to Expanded (TaskDialogExpander) (so its value will be updated when the user clicks the expando button)
  • Removed non-predefined icons (that were used from imageres.dll)
  • Class TaskDialog extends System.ComponentsModel.Component (and is disposable)
  • Added Tag property to TaskDialogControl
  • Class TaskDialogCommonButton now has a default constructor (like other control classes)
  • Renamed properties/events (e.g. MainInstruction -> Instruction, Content -> Text, ButtonClicked -> Click)
  • Properties and events of TaskDialogRadioButton and TaskDialogVerificationCheckbox has been aligned with WinForms concepts (property Checked, event CheckedChanged).
  • Renamed class TaskDialogVerificationCheckbox to TaskDialogCheckBox (along with properties)
  • Created struct TaskDialogProgressBarRange to be used for the TaskDialogProgressBar.Range property instead of (int min, int max) for better designer support
  • Restored property TaskDialogContents.DoNotSetForeground as it is actually working.
  • Removed TaskDialogBooleanStatusEventArgs.
  • Remaned TaskDialogProgressBarState enum value MarqueeDisabled to MarqueePaused
  • Made class TaskDialogControl abstract
  • Renamend enum value TaskDialogIcon.Stop to Error
  • Removed the TaskDialogProgressBar.Range property (along with the TaskDialogProgressBarRange struct) and instead added properties Minimum and Maximum directly on the TaskDialogProgressBar and also renamed property Position to Value, to simplify the API and align with the WinForms ProgressBar
  • Removed the WPF types
  • Extracted the footer-specific properties on TaskDialogContents (FooterText, FooterIcon, FooterIconHandle) into their own TaskDialogFooter class. The reasoning for this is that a separate dialog area is added for the footer when it is used (as shown in the below image), similar to the expander (and it reduces the number of properties in TaskDialogContents).
    Also, when you intially don't create a footer when showing the task dialog, you cannot later add one by updating the FooterText property, similar to the Text property of the Expander (which is different from the other text properties like TaskDialogContents.Text and Instruction that can be added later).
    A separate TaskDialogFooter class that inherits from TaskDialogControl can thus share the behavior with taskDialogExpander to throw an InvalidOperationException when trying to update its Text property but the control wasn't created because it was initially null (or string.Empty).
    taskdialog-footer
  • Renamed events TaskDialog.Closing to Closed and TaskDialogContents.Destroying to Destroyed, and added a new TaskDialog.Closing event that is called directly after a TaskDialogButton.Click event if the button would close the dialog, and it allows to cancel the close (similar to Form.FormClosing event in WinForms) - see this comment (Option B).
  • Renamed property TaskDialogExpander.ExpandoButtonClicked to ExpandedChanged
  • Renamed class TaskDialogContents to TaskDialogPage and property TaskDialog.CurrentContents to TaskDialog.Page. This is because the documentation also talks about "navigating to a new page" - for example see Multi-page dialog boxes.
  • Removed the TimerTick event on TaskDialogPage:
    This event represents the TDN_TIMER notification that is called every 200 ms if the TDF_CALLBACK_TIMER flag was set in the task dialog config. The previous implementation specified the flag if the event handler has been set (like the implementation in the Windows API Code Pack did), but this means you could not add an event handler to the TimerTick event after the dialog is displayed/navigated. Also, the interval of 200 is fixed (and a user might get the impression that the dialog can only be updated every 200 ms, which is not the case).
    Instead, the user can use one of the already existing UI timer implementations like System.Windows.Forms.Timer. Both the Task Dialog timer and the WinForms Timer use a Windows timer (WM_TIMER messages), so using the WinForms timer should have the same behavior as the TaskDialog timer but with more flexibility.
  • Moved property StartupLocation from TaskDialogPage to TaskDialog because it only has an effect when showing the dialog (but not when navigating it) and therefore isn't related to the page (which represents the contents of the dialog).
  • Added events TaskDialog.Activated and TaskDialog.Deactivated. Edit: Removed these again because of an unresolved issue when closing the dialog.
  • Added event TaskDialog.Shown (similar to Form.Shown).
  • Renamed class TaskDialogCommonButton to TaskDialogStandardButton (along with collections and property names).
  • Moved property TaskDialogPage.DoNotSetForeground to TaskDialog because it only has an effect when showing the dialog, but not when navigating it.
  • Unified mutually exclusive properties Icon+IconHandle on TaskDialogPage and TaskDialogFooter into a single Icon property use subclasses to differentiate between icon types (see #146 (comment)).
    This should avoid confusion about having two mutually exclusive properties (and it allows to initially not showing an icon but then updating it to one using a handle (without using navigation)).
    Additionally, it will allow us in the future to add an additional icon type that represents integer/string resource icons (e.g. from imageres.dll or the application's executable), which could also be shown using a colored bar (which is not possible when using a handle).
  • Renamed property TaskDialogPage.CommandLinkMode to CustomButtonStyle (along with the enum).
  • TaskDialog no longer inherits from System.ComponentModel.Component which was used for trying to implement designer support, but that would require additional work. It be revisited for a future version.
  • Renamed event TaskDialogPage.Help to HelpRequest (and method OnHelp to OnHelpRequest) as discussed in #1133.
  • Renamed property TaskDialog.DoNotSetForeground to TaskDialog.SetToForeground (the default value is still false), as per the feedback in #1133.
  • Enabled nullable reference types.
  • Made events nullable (see dotnet/coreclr#25752).
  • API Review Feedback:
    • Renamed method group TaskDialog.Show to ShowDialog.
    • Renamed property TaskDialogPage.Instruction to MainInstruction (same with parameter names for the static TaskDialog.Show methods).
    • Renamed property TaskDialogPage.Title to Caption (same with parameter names for the static TaskDialog.Show methods).
    • Removed class TaskDialogButtonClickedEventArgs and instead added boolean property TaskDialogButton.ShouldCloseDialog that allows to specify whether clicking the button should close the task dialog.
    • Removed types TaskDialogStandardIcon and TaskDialogIconHandle, and instead added static fields on TaskDialogIcon for the standard icons, and added a constructor taking an icon or icon handle.
  • Added an int indexer to TaskDialogStandardButtonCollection to avoid an overload resolution in the C# compiler for expressions like page.StandardButtons[0]. See #1133 (comment)
  • Changes from kpreisser#1:
    • Added implicit cast operator from string to TaskDialogFooter.
  • Replaced property TaskDialogExpander.ExpandFooterArea with Position (using enum type TaskDialogExpanderPosition).
  • Added properties TaskDialogPage.BoundDialog and TaskDialogControl.BoundPage, so that it is possible e.g. to access the current TaskDialog instance in a button click handler. See discussion here.
  • Renamed icons SecurityShield, SecurityShieldBlueBar, SecurityShieldGrayBar, SecurityWarningYellowBar, SecurityErrorRedBar, SecuritySuccessGreenBar to Shield, ShieldBlueBar, ShieldGrayBar, ShieldWarningYellowBar, ShieldErrorRedBar, ShieldSuccessGreenBar; as the term "security" would imply that such icons will/must be used for security purposes.
  • Changes from kpreisser#3:
    • Renamed TaskDialogPage.CanBeMinimized to AllowMinimize.
    • Renamed TaskDialogButton.ShouldCloseDialog to AllowCloseDialog.
    • Add optional parameters to the TaskDialogStandardButton and TaskDialogCustomButton constructors and to the TaskDialogStandardButtonCollection.Add and TaskDialogCustomButtonCollection.Add methods.
  • Simplified type of event TaskDialogButton.Click from EventHandler<EventArgs> to EventHandler.
  • Removed hyperlink functionality for now - see kpreisser#4.
  • Refactored Button API - see kpreisser#12
  • Streamlined single/multipage API - see kpreisser#14
  • Move instance property StartupLocation to a parameter of ShowDialog() - see kpreisser#16
  • Allow to create TaskDialogIcon from a Bitmap - see kpreisser#15
  • Renamed property TaskDialogPage.MainInstruction to Heading - see kpreisser#6
  • Renamed class TaskDialogFooter (and corresponding properties) to TaskDialogFootnote - see kpreisser#8
  • Renamed TaskDialogStartupLocation.CenterParent to CenterOwner
  • Removed method TaskDialogCheckBox.Focus()
  • Renamed property TaskDialogButton.ElevationRequired to ShowShieldIcon
  • Renamed class TaskDialogCheckBox (and corresponding properties) to `TaskDialogVerificationCheckBox´ - see kpreisser#18
  • Removed property TaskDialogPage.Width

Possible API TODOs

  • Maybe rename TaskDialogProgressBarState to TaskDialogProgressBarStyle
  • Maybe add property Tag on TaskDialogPage (which is already present on TaskDialogControl)
  • Check how method ShowDialog() should behave. Currently, it either shows the dialog modal (when specifying an owner) or non-modal, but in both cases the method does not return until the dialog has closed (similar to Form.ShowDialog()), which is the behavior of the native TaskDialogIndirect function.
    This is the same as with MessageBox.Show(); however, the MessageBox automatically uses the current foreground window as owner when you don't specify the owner. For the Task Dialog however, it definitely should be possible to show it non-modal.
    Note that this means you can show multiple non-modal dialogs at once, but each open dialog will add a TaskDialog.Show() entry in the call stack.

API Usage Notes

  • Because some parts of the Task Dialog can be updated while it is shown (while others cannot), properties that cannot be updated while the dialog is shown will throw an InvalidOperationException (this was also the behavior of the task dialog implementation in the Windows API Code Pack).
    For example, radio buttons cannot be unselected while the dialog is shown (but they can be selected). This means that assigning false to the TaskDialogRadioButton.Checked property (while the radio button is shown in a task dialog) will throw.
  • The button order in the TaskDialogButtonCollection does not necessarily reflect the order in which the task dialog actually displays the buttons (since common buttons are specified by flags in the TASKDIALOGCONFIG structure, whereas custom buttons are stored in an array).
    The native task dialog displays buttons from the collection in the following order:
    1. Custom Buttons/Command Links in their relative order from the collection
    2. Standard Buttons in an OS-defined order:
      1. OK
      2. Yes
      3. No
      4. Abort
      5. Retry
      6. Cancel
      7. Ignore
      8. TryAgain
      9. Continue
      10. Close
      11. Help
  • TaskDialog.ShowDialog() can return a TaskDialogButton which was not added to the dialog in the following cases (which results from the native task dialog implementation):
    • No button has been added to the dialog, in which case it automatically gets an OK button, and so the TaskDialogButton.OK button is returned when the user clicks it.
    • No Cancel button has been added to the dialog, but the dialog is programmatically closed by calling the Close() method, or TaskDialogPage.AllowCancel has been set and the dialog is closed by the user by pressing ESC or Alt+F4 or clicking the X button in the title bar. In these cases the TaskDialogButton.Cancel button will be returned.
      This can also happen when a non-modal task dialog is shown but the main window of the app is closed, in which case the task dialog is also closed and returns a Cancel result.
  • It is possible to use a color bar with a different icon (one of the predefined icons or an icon resource from imageres.dll), by initially specifying one of the Shield...Bar icons, and when the dialog is shown, update it to a different icon:
    taskdialog-colorbar-customicon
    However, it isn't possible to use a color bar with a icon handle, because after showing the dialog you can only update the icon member that was initially used to show a dialog, and specifying a color bar requires to use the non-handle icon member.
    This means currently you can only use one of the standard icons with a color bar, but in a later version we could add support for showing icons from integer/string resources of DLLs/EXEs (e.g. from imageres.dll) (by specifying the hInstance field of the native TASKDIALOGCONFIG struct), which would then allow you to show a custom icon with a colored bar.

InvalidCastException when icon is set in autogenerated form designer code

  • .NET Core Version: 3.0 Preview1
  • Have you experienced this same bug with .NET Framework?: No

Problem description:

Crash at runtime where icon is set as follows in autogenerated form designer code

            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));

Actual behavior:

Following exception is thrown when running using dotnet CLI or vscode

Exception has occurred: CLR/System.InvalidCastException
An unhandled exception of type 'System.InvalidCastException' occurred in...

Expected behavior:

No crash, form icon is set. Crash does not happen and icon is set when debugging via Visual Studio 2019 preview.

Minimal repro:

SRDescriptionAttribute and SRCategoryAttribute should be calling GetResourceString

The purposes of both of these attributes is to translate from an ID known at build time to a localized value that can only be known at runtime.

As such the string they contain needs to be looked up, by calling SR.GetResourceString.

Today both of these classes are treating the ID as if it were a localized value:


base.DescriptionValue = base.Description;

/cc @dreddy-work @Shyam-Gupta

Deal with globally suppressed warnings (618 and 649) from System.Windows.Forms code

618: use of obsolete code. Used probably because of legacy code, but globally surpressing the warning turns it off for new code too. Hence check if the code can be modified to avoid them. If not then add #pragmas instead of globally suppressing this warning.

649: field is never assigned. We should not ignore this warning except in the rare cases when we need to preserve an unused field for back-compat (eg: serialization). Recommend replace with pragma.

Can't use the Pack command from Visual Studio. PackageProjectUrl is not set

If you try and pack a project in WinForms like this:

image

You're met with the build error:
image

This happens both to the projects System.Windows.Forms and System.Windows.forms.Ref

This can easily be fixed by adding <PackageProjectUrl>http://github.com/dotnet/winforms</PackageProjectUrl> to the two project files (or as a global setting).

Porting System.Windows.Forms.DataVisualization to .NET core

Creating this issue to track the porting of System.Windows.Forms.DataVisualization.dll into Core.

  • We have seen multiple reports on not being able to migrate because of missing the dll in core.
  • Porting of this binary may have dependency on System.Data.Oledb.
  • Winforms applications using "Chart" control are primary target of this issue.

Update WebBrowser control in .NET Core

Copied from dotnet/core#2093

Since WinForms is moving to .NET Core 3.0, I hope you upgrade the WebBrowser control to use the IE version installed on the user PC. The current WebBrowser control uses IE 7 and causes many problems. There is a workaround to solve this, but doing it in the user's PC needs permissions. See this topic for more details:
https://stackoverflow.com/questions/17922308/use-latest-version-of-internet-explorer-in-the-webbrowser-control?noredirect=1&lq=1

Test failure: System.Drawing.Drawing2D.Tests.LinearGradientBrushTests.Ctor_PointF_PointF_Color_Color

Note that the failure occurs on Arm64 only!

The test: https://github.com/dmklementiev/corefx/blob/master/src/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs has failed with the following details:

Unhandled Exception of Type Xunit.Sdk.EqualException
Message :
Assert.Equal() Failure
Expected: {X=0,Y=0,Width=2,Height=2}
Actual: {X=0,Y=-1,Width=2,Height=2}

Stack Trace :
at System.Drawing.Drawing2D.Tests.LinearGradientBrushTests.Ctor_PointF_PointF_Color_Color(Point point1, Point point2, Color color1, Color color2, RectangleF expectedRectangle) in /mnt/j/workspace/dotnet_corefx/master/linux-TGroup_netcoreapp+CGroup_Release+AGroup_arm64+TestOuter_false_prtest/src/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs:line 39

Exactly the same problem with another test:

Stack Trace :
at System.Drawing.Drawing2D.Tests.LinearGradientBrushTests.Ctor_Point_Point_Color_Color(Point point1, Point point2, Color color1, Color color2, RectangleF expectedRectangle) in /mnt/j/workspace/dotnet_corefx/master/linux-TGroup_netcoreapp+CGroup_Release+AGroup_arm64+TestOuter_false_prtest/src/System.Drawing.Common/tests/Drawing2D/LinearGradientBrushTests.cs:line 68

Investigate failing System.Drawing.Common tests in RS4

 System.Drawing.Tests.BitmapTests.MakeTransparent_GrayscalePixelFormat_ThrowsArgumentException [FAIL]
      Assert.Throws() Failure
      Expected: typeof(System.Runtime.InteropServices.ExternalException)
      Actual:   (No exception was thrown)
      Stack Trace:
            at System.Drawing.Tests.BitmapTests.MakeTransparent_GrayscalePixelFormat_ThrowsArgumentException()
   System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_Default_ReturnsExpected [FAIL]
      System.OutOfMemoryException : Out of memory.
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Graphics.Windows.cs(119,0): at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(631,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(PageSettings pageSettings)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrinterSettingsTests.cs(476,0): at System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_Default_ReturnsExpected()
   System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_Bool_ReturnsExpected [FAIL]
      System.DivideByZeroException : Attempted to divide by zero.
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs(86,0): at System.Drawing.Printing.PageSettings.get_HardMarginX()
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(622,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(Boolean honorOriginAtMargins)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrinterSettingsTests.cs(491,0): at System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_Bool_ReturnsExpected()
   System.Drawing.Printing.Tests.PrintDocumentTests.QueryPageSettings_SetValue_ReturnsExpected [FAIL]
      System.NullReferenceException : Object reference not set to an instance of an object.
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs(388,0): at System.Drawing.Printing.PageSettings.get_ExtraBytes()
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs(368,0): at System.Drawing.Printing.PageSettings.CopyToHdevmode(IntPtr hdevmode)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrintController.Windows.cs(276,0): at System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document, PrintEventArgs e)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs(275,0): at System.Drawing.Printing.Tests.PrintDocumentTests.TestPrintController.OnStartPrint(PrintDocument document, PrintEventArgs e)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrintController.Windows.cs(117,0): at System.Drawing.Printing.PrintController.Print(PrintDocument document)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs(225,0): at System.Drawing.Printing.Tests.PrintDocumentTests.QueryPageSettings_SetValue_ReturnsExpected()
   System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_Null_ThrowsNullReferenceException [FAIL]
      Assert.Throws() Failure
      Expected: typeof(System.NullReferenceException)
      Actual:   typeof(System.OutOfMemoryException): Out of memory.
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Graphics.Windows.cs(119,0): at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(631,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(PageSettings pageSettings)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(640,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(PageSettings pageSettings, Boolean honorOriginAtMargins)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrinterSettingsTests.cs(536,0): at System.Drawing.Printing.Tests.PrinterSettingsTests.<>c__DisplayClass49_0.<CreateMeasurementGraphics_Null_ThrowsNullReferenceException>b__1()
   System.Drawing.Printing.Tests.PrintDocumentTests.Ctor_Default_Success [FAIL]
      System.ArgumentNullException : Value cannot be null.
      Parameter name: ptr
      Stack Trace:
            at System.Runtime.InteropServices.Marshal.StructureToPtr(Object structure, IntPtr ptr, Boolean fDeleteOld)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs(361,0): at System.Drawing.Printing.PageSettings.CopyToHdevmode(IntPtr hdevmode)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs(235,0): at System.Drawing.Printing.PageSettings.get_PrinterResolution()
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs(255,0): at System.Drawing.Printing.Tests.PrintDocumentTests.AssertDefaultPageSettings(PageSettings pageSettings)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs(44,0): at System.Drawing.Printing.Tests.PrintDocumentTests.Ctor_Default_Success()
   System.Drawing.Printing.Tests.PrinterSettingsTests.IsPlotter_ReturnsExpected [FAIL]
      Assert.False() Failure
      Expected: False
      Actual:   True
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrinterSettingsTests.cs(180,0): at System.Drawing.Printing.Tests.PrinterSettingsTests.IsPlotter_ReturnsExpected()
   System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_PageSettingsBool_ReturnsExpected [FAIL]
      System.OutOfMemoryException : Out of memory.
      Stack Trace:
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Graphics.Windows.cs(119,0): at System.Drawing.Graphics.FromHdcInternal(IntPtr hdc)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(631,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(PageSettings pageSettings)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs(640,0): at System.Drawing.Printing.PrinterSettings.CreateMeasurementGraphics(PageSettings pageSettings, Boolean honorOriginAtMargins)
         D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrinterSettingsTests.cs(521,0): at System.Drawing.Printing.Tests.PrinterSettingsTests.CreateMeasurementGraphics_PageSettingsBool_ReturnsExpected()

cc: @danmosemsft

CopyFromScreen tests causing intermittent failures

System.Drawing.Tests.GraphicsTests.CopyFromScreen_ValidRange_AffectsGraphics(sourceX: 1, sourceY: 1, destinationX: 2, destinationY: 2, width: 3, height: 3) [FAIL]
20:39:03         System.ComponentModel.Win32Exception : The handle is invalid
20:39:03         Stack Trace:
20:39:03              at System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX, Int32 destinationY, Size blockRegionSize, CopyPixelOperation copyPixelOperation)
20:39:03              at System.Drawing.Graphics.CopyFromScreen(Int32 sourceX, Int32 sourceY, Int32 destinationX, Int32 destinationY, Size blockRegionSize)

I believe these tests are invalid, given that they are failing against the .NET Framework. We should give them some scrutiny, and potentially remove them.

Add .editorconfig file

Please add a .editorconfig file that fully specifies the conventions and naming rules for these projects.

MakeTransparent_GrayscalePixelFormat_ThrowsArgumentException failed in CI on desktop

https://ci3.dot.net/job/dotnet_corefx/job/master/job/windows-TGroup_netfx+CGroup_Release+AGroup_x86+TestOuter_false_prtest/793/consoleText

ystem.Drawing.Tests.BitmapTests.MakeTransparent_GrayscalePixelFormat_ThrowsArgumentException [FAIL]
        Assert.Throws() Failure
        Expected: typeof(System.Runtime.InteropServices.ExternalException)
        Actual:   (No exception was thrown)
        Stack Trace:
          D:\j\workspace\windows-TGrou---2a8f9c29\src\System.Drawing.Common\tests\BitmapTests.cs(0,0): at System.Drawing.Tests.BitmapTests.MakeTransparent_GrayscalePixelFormat_ThrowsArgumentException()

Arithmetic operation resulted in an overflow

I created .NET Core (2.1) console app and added reference to System.Drawing.Common nuget (4.5.1). I'm trying to run the following code from docs, but it fails on bitmap1.GetEncoderParameterList with System.OverflowException:

'Arithmetic operation resulted in an overflow.'

What is wrong with this code? Do I make something illegal?

class Program
{

   public static void Main(string[] args)
   {
      new Program().GetSupportedParameters();
   }
   private void GetSupportedParameters()
   {
       Bitmap bitmap1 = new Bitmap(1, 1);
       ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Jpeg);
       //this one also does not work:
       //Bitmap bitmap1 = new Bitmap(Image.FromFile(@"C:\temp\0\2.png"));
       //ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Png);
       EncoderParameters paramList = bitmap1.GetEncoderParameterList(jpgEncoder.Clsid);
       EncoderParameter[] encParams = paramList.Param;
       StringBuilder paramInfo = new StringBuilder();

       for (int i = 0; i < encParams.Length; i++)
       {
           paramInfo.Append("Param " + i + " holds " + encParams[i].NumberOfValues +
                    " items of type " +
                encParams[i].ValueType + "\r\n" + "Guid category: " + encParams[i].Encoder.Guid + "\r\n");

       }            
   }

   private ImageCodecInfo GetEncoder(ImageFormat format)
   {
       ImageCodecInfo[] codecs = ImageCodecInfo.GetImageDecoders();

       foreach (ImageCodecInfo codec in codecs)
       {
          if (codec.FormatID == format.Guid)
          {
               return codec;
          }
       }
       return null;
    }
 }

StackTrace:

at System.Drawing.Imaging.EncoderParameters.ConvertFromMemory(IntPtr memory)
at System.Drawing.Image.GetEncoderParameterList(Guid encoder)
at ConsoleApp16.Program.GetSupportedParameters() in Program.cs:line 19
at ConsoleApp16.Program.Main(String[] args)
in Program.cs:line 13

This one also crashes:

Bitmap bitmap1 = new Bitmap(Image.FromFile(@"C:\temp\0\2.png"));
ImageCodecInfo jpgEncoder = GetEncoder(ImageFormat.Png);

PlaceholderText API addition to TextBox control

With the following PR (#96 -> moved to #238) we have proposed addition of new property to the TextBox control called PlaceholderText. The property accepts string which will be drawn when the control has no text it in and is not on focus. Quite useful to indicate what is the expected input.

Rationale

Currently, in order to provide guidance for the users what input is expected in a text field, the only option is to have a label next to the TextBox control. However, there are cases, where label is not appropriate and it is much more user friendly to have a placeholder text in the TextBox itself, to guide the user as to what input is expected. Think of scenarios for "Enter your username/password"

Proposed API

public string PlaceholderText {get; set;}

Description

A single public property called PlaceholderText is introduced, with no value. When the property is set, AND the TextBox has no Text set nor focus, the string from the PlaceholderText will be drawn in the TextBox control, using the SystemColors.GrayText. Once the property value is changed the new text will be drawn, if currently visible. Once the user focuses on the control, the text disappears. Different text alignments and RightToLeft are taken into consideration when the PlaceholderText is being drawn. In addition, it also works in Multiline mode.

In addition AccessibilityObject has been implemented to return the PlaceholderText when the Text is empty, hence screen readers read the PlaceholderText value and guide the users to what is expected from them as input.

On the bottom left side of the image you can see a TextBox with PlaceholderText drawn.
image

System.Drawing.Imaging.ImageAttributes.SetColorKey() is set but not applied.

I am writing test for System.Drawing.Imaging.ImageAttributes dotnet/runtime#22130:

private readonly Rectangle _rectangle = new Rectangle(0, 0, 64, 64);

[ConditionalFact(nameof(PlatformDetection) + "." + nameof(PlatformDetection.IsNotWindowsNanoServer))]
public void SetColorKey_Success()
{
    using (var bitmap = new Bitmap(_rectangle.Width, _rectangle.Height))
    using (var graphics = Graphics.FromImage(bitmap))
    using (var imageAttr = new ImageAttributes())
    {
        imageAttr.SetColorKey(Color.FromArgb(50, 50, 50), Color.FromArgb(150, 150, 150));

        bitmap.SetPixel(0, 0, Color.FromArgb(255, 100, 100, 100));
        graphics.DrawImage(bitmap, _rectangle, _rectangle.X, _rectangle.Y, _rectangle.Width, _rectangle.Height, GraphicsUnit.Pixel, imageAttr);
        Assert.Equal(Color.FromArgb(0, 0, 0, 0), bitmap.GetPixel(0, 0));
    }
}

Expected: Color.FromArgb(0, 0, 0, 0)
Actual: Color.FromArgb(255, 100, 100, 100)

I am running the test on netfx and netcoreapp and it fails on both.

Looks like transparency isn't get applied.

[EDIT] Fixed code formatting - @karelz

Modernize FolderBrowserDialog

The Windows Forms FolderBrowserDialog uses an old folder picker control. Starting in Windows Vista, there is a newer COM-based control available.

My proposal is to enhance the existing FolderBrowserDialog to use that newer control by default when running on Vista and higher.

The existing API can be used, but the newer API gives us a few new options:

  1. The default location may be any folder, not just a known folder. The current API uses an enum for the RootFolder. How should we take this forward to allow a user to set the path? One option could be to document that the property has no effect if the Vista style dialogs are used. This is what Ookii dialogs does.
  2. SelectedPath has a setter, should we use that value as the default folder? Ookii uses this property as the default and then to retrieve the selection.
  3. ShowNewFolderButton is always visible on the new dialog. The doc comments can be updated to reflect this.
  4. The new dialog has a Title property. We can add that.
  5. Presumably there should be a property to allow a user to choose the original dialog. What should we call it?

Does .NET Core 3 support pre-Vista operating systems? Do we need to consider that, or can Vista detection code be removed? How about CAS and Security Demand code? Does that need to remain or be added for net-new code or can that be removed & omitted for .NET Core?

EndPrint_SetValue_ReturnsExpected and PrintPage_SetValue_ReturnsExpected throws excpetion

Unhandled Exception of Type System.ComponentModel.Win32Exception
Error in remote procedure call

   at System.Drawing.Printing.PrinterSettings.GetHdevmodeInternal(String printer) in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrinterSettings.Windows.cs:line 896
   at System.Drawing.Printing.PageSettings.get_ExtraBytes() in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs:line 384
   at System.Drawing.Printing.PageSettings.CopyToHdevmode(IntPtr hdevmode) in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PageSettings.Windows.cs:line 368
   at System.Drawing.Printing.PrintController.OnStartPrint(PrintDocument document, PrintEventArgs e) in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrintController.Windows.cs:line 276
   at System.Drawing.Printing.Tests.PrintDocumentTests.TestPrintController.OnStartPrint(PrintDocument document, PrintEventArgs e) in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs:line 274
   at System.Drawing.Printing.PrintController.Print(PrintDocument document) in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\src\System\Drawing\Printing\PrintController.Windows.cs:line 117
   at System.Drawing.Printing.Tests.PrintDocumentTests.EndPrint_SetValue_ReturnsExpected() in D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Printing\PrintDocumentTests.cs:line 182

Link https://mc.dot.net/#/user/Anipik/pr~2Fjenkins~2Fdotnet~2Fcorefx~2Fmaster~2F/test~2Ffunctional~2Fcli~2F/928be92417ee8f200df812e3dfc002abcf80f787/workItem/System.Drawing.Common.Tests/analysis/xunit/System.Drawing.Printing.Tests.PrintDocumentTests~2FEndPrint_SetValue_ReturnsExpected

cc @danmosemsft @safern @JeremyKuhne

WinForms Designer Support

In Visual Studio 2019 Preview 1, there is no project template for generating .NET Core 3 WinForms projects. If I instead run on the command line:

dotnet new winforms -o winforms_core_test

a project is created successfully. I can then open the generated .csproj file in VS2019. But the WinForms designer doesn't seem to be available. Typically the right-click context menu shows "view designer", but it is missing, and shift+f7 after opening the code doesn't work either:

missing designer

On a standard WinForms project, the Designer.cs file is typically shown as a child of the form source code, and the designer is available on the context menu:

what it should look like

Is there any way to use the designer with .NET Core 3, or is it planned in the future?

Setting/Getting HighDpiMode in WinForms Core Apps

Rationale

Developers in WinForms Core currently have no way to set the HighDPI mode in their WinForms App. In a future version of .NET Core 3.0, this will again be possible via App.Manifest; however, a change in the settings requires then their app to be rebuilt. The previous option in the classic framework to control this setting via App.Config has been completely dropped in .NET Core. Currently, the only way to set the HighDPIMode is via P/Invoke. The Application.SetHighDpiMode method and Application.HighDpiMode property are an easy to apply and to discover alternative.

Proposed API

namespace System.Windows.Forms
{
    public sealed class Application
    {
        // Existing methods/properties (excerpt)
        public static void EnableVisualStyles();
        public static bool RenderWithVisualStyles { get; }

        // Proposed method/property
        public static bool SetHighDpiMode(HighDpiMode highDpiMode);
        public static HighDpiMode HighDpiMode { get; }
    }

    public enum HighDpiMode
    {
        DpiUnaware,
        SystemAware,
        PerMonitor,
        PerMonitorV2,
        DpiUnawareGdiScaled
    }
}

Description

Following EnableVisualStyles()/RenderWithVisualStyles of the Application class, we propose the method SetHighDpiMode which switches to the corresponding HighDPI mode, if that HighDPIMode setting a) has not been set before by other means (App.Manifest, P/Invoke before Application.Run – in this case the value to be set is ignored), and b) that HighDPIMode setting was set via SetHighDpiMode before calling Application.Run (or the first UI Element has been rendered).

Possible settings values are provided by the HighDpiMode Enum:

  • DpiUnaware
  • SystemAware
  • PerMonitor
  • PerMonitorV2
  • DpiUnawareGdiScaled

If a setting is attempted to be set which is not supported by the underlying OS, SetHighDpiMode automatically assumes the next possible setting on that OS; SetHighDpiMode never directly triggers an exception, but gives feedback as to whether the setting could be successfully set (true) or not (false).

In addition developers can query the actual setting of the current HighDpiMode at any time using the Application.HighDpiMode property, which returns one of the available HighDpiMode Enum values.

In the current implementation, we should limit the method/property to the process DpiAwareness rather than a Window DpiAwareness, and should probably think about extending this to a static method/property of the Control class to the windows DpiAwareness (@Tanya-Solyanik, thoughts?).

VisualStyles fails to activate with current setup to build System.Windows.Forms.dll

Every modern WinForms App uses VisualStyles to get a proper look and feel. When VisualStyles fail for an App to be activated, Apps look like running under an ancient OS like Windows 2000.

With the way the build system is currently set up, System.Windows.Forms.dll seems to be build differently compared to the internal build system we had before. On start of a WinForms app, the Application class tries to activate VisualStyles, and for that to end, passes the WinForms assembly to the method CreateActivationContext. This method then tries to read certain resources from the WinForms assembly.

Now, when we compile the WinForms assembly System.Windows.Forms.dll with the current build setup, that does not work. CreateActCtx inside of CreateActivationContext return 1813 - ERROR_RESOURCE_TYPE_NOT_FOUND. If we build with the previous build system (same source code), this works.

Test: System.Drawing.Tests.FontFamilyTests/Ctor_Name failed with "System.ArgumentException"

Opened on behalf of @JiayiLi1

The test System.Drawing.Tests.FontFamilyTests/Ctor_Name(name: \"Microsoft Sans Serif\", expectedName: \"Microsoft Sans Serif\") has failed.

System.ArgumentException : Font 'Microsoft Sans Serif' cannot be found.

    Stack Trace:

       at System.Drawing.FontFamily.CreateFontFamily(String name, FontCollection fontCollection)
   at System.Drawing.Tests.FontFamilyTests.Ctor_Name(String name, String expectedName)

Build : Master - 20170726.01 (Core Tests)
Failing configurations:

  • Windows.10.Amd64.Core-x86
    • Release
  • Windows.10.Amd64.Core-x64
    • Release

Detail: https://mc.dot.net/#/product/netcore/master/source/official~2Fcorefx~2Fmaster~2F/type/test~2Ffunctional~2Fcli~2F/build/20170726.01/workItem/System.Drawing.Common.Tests/analysis/xunit/System.Drawing.Tests.FontFamilyTests~2FCtor_Name(name:%20%5C%22Microsoft%20Sans%20Serif%5C%22,%20expectedName:%20%5C%22Microsoft%20Sans%20Serif%5C%22)

DrawLines_PointFs, DrawBezier_PointFs, DrawBezier_Points and DrawLines_Points failing sporadically in CI

I've seen these fail multiple times in CI now, e.g.
https://mc.dot.net/#/user/dotnet-maestro-bot/pr~2Fjenkins~2Fdotnet~2Fcorefx~2Fmaster~2F/test~2Ffunctional~2Fcli~2F/7868028f16d0fb97037930838ec20cba5077191f/workItem/System.Drawing.Common.Tests/wilogs

2018-06-26 22:47:39,723: INFO: proc(54): run_and_log_output: Output:    System.Drawing.Tests.Graphics_DrawBezierTests.DrawBezier_PointFs [FAIL]
2018-06-26 22:47:39,723: INFO: proc(54): run_and_log_output: Output:       Assert.Equal() Failure
2018-06-26 22:47:39,723: INFO: proc(54): run_and_log_output: Output:       Expected: Byte[] [208, 0, 8, 33, 6, ...]
2018-06-26 22:47:39,723: INFO: proc(54): run_and_log_output: Output:       Actual:   Byte[] [27, 206, 219, 21, 255, ...]
2018-06-26 22:47:39,737: INFO: proc(54): run_and_log_output: Output:       Stack Trace:
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:          D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\DrawingTest.cs(21,0): at System.Drawing.Tests.DrawingTest.ValidateImageContent(Image image, Byte[] expectedHash)
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:          D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Graphics_DrawBezierTests.cs(59,0): at System.Drawing.Tests.Graphics_DrawBezierTests.DrawBezier_PointFs()
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:    System.Drawing.Tests.Graphics_DrawLineTests.DrawLines_PointFs [FAIL]
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:       Assert.Equal() Failure
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:       Expected: Byte[] [142, 194, 251, 180, 222, ...]
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:       Actual:   Byte[] [89, 188, 96, 22, 200, ...]
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:       Stack Trace:
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:          D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\DrawingTest.cs(21,0): at System.Drawing.Tests.DrawingTest.ValidateImageContent(Image image, Byte[] expectedHash)
2018-06-26 22:47:39,987: INFO: proc(54): run_and_log_output: Output:          D:\j\workspace\windows-TGrou---f8ac6754\src\System.Drawing.Common\tests\Graphics_DrawLineTests.cs(32,0): at System.Drawing.Tests.Graphics_DrawLineTests.DrawLines_PointFs()

I could be wrong, but I believe I only started seeing it after dotnet/corefx#30099.
cc: @safern, @JeremyKuhne

Control can't be properly GC-collected after disposing because of it referenced via the System.Windows.Forms.Control.cachedLayoutEventArgs field

The same bug is reproducible with .NET Framework but it seems it has no chance to be ever fixed.
But the .NET Core looks like a good place for introducing some improvements in this area.

Problem description

Each instance of the System.Windows.Forms.Control type contains a private member variable of the LayoutEventArgs type - cachedLayoutEventArgs . And, the LayoutEventArgs instance typically contains a reference to some specific control.
Sometimes, the cachedLayoutEventArgs field is not cleared when the child control disposing of does not affect the layout process of the parent control due to some reasons.

Reproduction

Here are the minimal reproduction-steps:

  1. Create a form with two buttons.
  2. Add the following code for the corresponding Button.Click handlers:
void btnOpenView_Click(object sender, System.EventArgs e) {
    var view = new Panel() { BackColor = Color.Red };
    view.Name = "View";
    view.Bounds = new Rectangle(100, 100, 100, 100);
    view.Parent = this;
}
void btnCloseView_Click(object sender, System.EventArgs e) {
    SuspendLayout();
    var view = this.Controls.Find("View", false)[0];
    if(view != null)
        view.Dispose();
    ResumeLayout(false);
}
  1. Press the "Open View" button - red panel appears.
  2. Press the "Close View" button - red panel disappears.

Actual behavior:
The panel is still referencing via the System.Windows.Forms.Control.cachedLayoutEventArgs field at the form level. As result, it can't be GC-collected properly and still in memory.

Expected behavior:
The panel should not be referenced.

Proposal for Fix

It looks like we should use the WeakReference when caching the LayoutEventArgs.
As an alternative solution, we can validate the cachedLayoutEventArgs value on child control removing and clear the problematical field.

Use system cursors in System.Windows.Forms.Cursors

Currently, System.Windows.Forms.Cursors has a few embedded cursors that where added for backwards compatibility with old operating systems that are not supported anymore. They should be replaced to use system cursors.

The following cursors are embedded:

  • HSplit
  • VSplit
  • NoMove2D
  • NoMoveHoriz
  • NoMoveVert
  • PanEast
  • PanNE
  • PanNorth
  • PanNW
  • PanSE
  • PanSouth
  • PanSW
  • PanWest
  • Hand (Fixed with #2038)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.