Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Implement the Windows Task Dialog #1133

Merged
merged 169 commits into from
Apr 18, 2020
Merged

Implement the Windows Task Dialog #1133

merged 169 commits into from
Apr 18, 2020

Conversation

kpreisser
Copy link
Contributor

@kpreisser kpreisser commented Jun 16, 2019

This PR implements the Windows Task Dialog as described in #146.

Fixes #146

(Background info: This PR is based on my earlier implementation in the TaskDialog repo.)

Demo App

I have created a demo app (C# and VB) that consists of a Form with buttons, showing various Task Dialog scenarios. You can find it here: https://github.com/kpreisser/TaskDialogDemo

This app references System.Windows.Forms.dll and System.Windows.Forms.Primitives.dll built from this PR; you can simply place the app's repo folder near the winforms repo folder.

Known TODOs

  • Extract exception messages into resources
  • Have an accessibility assessment
  • Add tests - can be done separately

Implementation Notes

  • TaskDialog.ShowDialog() will only work if you have previously called Application.EnableVisualStyles() (or your app uses a manifest that enables common controls v6).
    Otherwise, it will fail with an InvalidOperationException caused by an EntryPointNotFoundException.
  • When calling TaskDialog.ShowDialog() and specifying an owner window, other windows of the current UI thread will not be disabled.
    This is different to the MessageBox.Show() behavior which also disables the other, non-owner windows (but they don't behave the same as the owner window, because when you click on them, the message box is not brought to the foreground; but clicking on the owner window brings the message box into foreground).
  • Because the handle of the task dialog is exposed by the TaskDialog.Handle property, in theory a user could send task dialog messages directly to the dialog and bypass the .NET implementation.
    The implementation is not protected against that case, but this should be OK since the user cannot expect the implementation to handle that.
  • The native (OS) Task Dialog implementation seems to have some issues/bugs for which we need to implement work-arounds. These are described in markdown files in the Documentation/src/System/Windows/Forms/TaskDialog folder of this PR, including C++ samle code to reproduce them.

@dnfclas
Copy link

dnfclas commented Jun 16, 2019

CLA assistant check
All CLA requirements met.

@kpreisser kpreisser mentioned this pull request Jun 16, 2019
@RussKie RussKie requested review from OliaG, terrajobst and a team June 16, 2019 22:55
@RussKie
Copy link
Member

RussKie commented Jun 16, 2019

Thank you, we'll start looking at it.

Just a heads up, before a merge the PR will need to be tidied up:

  • rebased on top of the master, and
  • not necessarily squashed into a single commit, but certainly collapsed into a smaller number of logical commits.

@kpreisser
Copy link
Contributor Author

Hi @RussKie,
thank you!

I rebased the PR with a single commit on top of master, as that was the easiest way.

@RussKie
Copy link
Member

RussKie commented Jun 17, 2019

I rebased the PR with a single commit on top of master, as that was the easiest way.

Champion!

Copy link
Member

@RussKie RussKie left a comment

Choose a reason for hiding this comment

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

The first sweep of reviews, I have probably missed things and may call them later (apologies in advance).

Overall it is quite impressive 👍

  • A number of comments of stylistic nature, I am not a big fan of line wrapping. I don't think we need to constrain ourselves to 80 char wide lines.
    Here's how it looks on my screen:
    image
    Granted not everyone is blessed with a 4K screen, but ultra-wide monitors are far from being rare these days.

  • All exceptions must be moved to resources and all public API must have valid xml-docs. @merriemcgaw / @OliaG - I suppose we need to help here, please advise.

  • There are number of personal gists referenced in the code. We'll need to either remove them or migrate into docs (?). @merriemcgaw / @OliaG - please advise.

The big question, of course, is how do we test this. We'll need unit- and integration-level tests.
Have you given any thought to this?

Thank you

/// Note: The dialog will not show until this handler returns (even if the
/// handler would run the message loop).
/// </remarks>
public event EventHandler Opened;
Copy link
Member

Choose a reason for hiding this comment

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

🤔 Would it be more appropriate to call this Opening since it is yet to actually open? ...Or Created?

Copy link
Member

Choose a reason for hiding this comment

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

/cc: @OliaG

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Note that the current event model is illustrated in section "Event Cycle" in the initial post of #146.
(Also note that because this is part of the public API, it would also need to be changed in the API Proposal.)

Currently, on the TaskDialog there are events Opened+Shown (before and after show), and Closing+Closed (before and after close).

The Opened event could be renamed to Opening, but it is called at the same time with TaskDialogPage.Created, which means we might also need to rename that one.

Copy link
Contributor

Choose a reason for hiding this comment

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

For public surface area, @RussKie I am inclined to elevate any concerns to @OliaG and @terrajobst for API Review

Copy link
Member

Choose a reason for hiding this comment

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

I have had a chat with @OliaG about API, and we have a certain freedom and discretion to exercise.
A review has been scheduled but it is some time away.

kpreisser and others added 5 commits June 19, 2019 20:53
…bclass of WindowSubclassHandler, use a separate virtual method for that.

Otherwise, when another subclass overrides WndProc(), its exceptions would not be caught.
-Use longer lines
-Use the default 4 instead of 8 spaces indentation after a line wrap
-Add braces for single-statement blocks
- Use "//" instead of "////" comments
-Remove explicit base() calls
Co-Authored-By: Igor Velikorossov <[email protected]>
@kpreisser
Copy link
Contributor Author

Hi @RussKie,
thanks a lot for your feedback!

I have applied some of the changes and will do the remaining ones later.

Regarding testing, I must admit that I do not have much experience with unit/integration tests of GUI frameworks. I will probably need to look at how existing tests are done, and check what could be applied to the task dialog.

Thank you!

@RussKie
Copy link
Member

RussKie commented Jun 20, 2019

Regarding testing, I must admit that I do not have much experience with unit/integration tests of GUI frameworks. I will probably need to look at how existing tests are done, and check what could be applied to the task dialog.

There are few things we'll need to have before we can merge it:

  • a demo app that will act as a demonstration of the functionality and a primer for other devs, and as a manual test for our QA team, and
  • a good unit test coverage - there is a lot of functionality we can test without needing a UI driver.

If we ask nicely @hughbe, he may be able to help with writing tests.

-Rename TaskDialog.DialogIsShown to .IsShown.
-Rename TaskDialog.HandleAvailable to .IsHandleCreated.
This ensures the task dialog con be used when you call Application.EnableVisualStyles() without having to add a manifest that enables common controls v6.
RussKie
RussKie previously approved these changes Apr 17, 2020
Copy link
Member

@RussKie RussKie left a comment

Choose a reason for hiding this comment

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

This is one fine piece of software craftmanship! 🎉

Few nits. My eyes are aching after reviewing 10K lines of code...

@kpreisser
Copy link
Contributor Author

What does "close while navigating" conceptually mean? Do we close the dialog instead of showing the next page? Or do we show the next page and then immediately close?

The dialog will close immediately before navigation is finished.
Technically, calling Navigate() means the dialog sets the caption of the new page as title, and prepares to create the controls of the new page and updates the dialog window height accordingly, and posts a message to the thread's message queue that, when processed, will finish navigation by actually displaying the new controls.
However, when calling Close() before this happens, the dialog window will close immediately and TaskDialog.ShowDialog() will return (the TaskDialogPage.Created event of the new page will not have been raised in that case).

Feels like a logic error on a dev's part...

Probably, but I don't see a reason to disallow closing the dialog in that case; it might complicate implementation of navigation for the user when they have to deal with the issue that they cannot call Close() before navigation is finished.

@RussKie
Copy link
Member

RussKie commented Apr 17, 2020 via email

@kpreisser
Copy link
Contributor Author

Maybe worth add a remark to the Close docs stating this (if it's stating this).

The docs of Close() already note that the method can be called while the dialog is waiting for navigation to finish. I also added docs to Navigate() to document that the page may not be updatable until the Created event occurs, but you can still call Close() during that time.

Thank you!

@RussKie
Copy link
Member

RussKie commented Apr 18, 2020

I'm not @shanselman, and I'm not on a stage in front of hundreds of developers, but I'm merging this!
Thank you for your patience and commitment. We made the history my friend, the first major addition to Windows Forms in 15 years! Hope you have a champagne on ice, it is time to pop the cork.

@RussKie RussKie merged commit 5fbdbde into dotnet:master Apr 18, 2020
@kpreisser kpreisser deleted the taskdialog branch April 18, 2020 12:10
@kpreisser
Copy link
Contributor Author

Thanks a lot! 🎉

@merriemcgaw
Copy link
Member

This is so exciting for WinForms developers around the world. @OliaG - time to brag about it for the next preview of .NET 5?

@kpreisser
Copy link
Contributor Author

kpreisser commented May 7, 2020

As an update, with VB support for WinForms announced for .NET 5, I have added a VB.NET project to the TaskDialogDemo repository which contains roughly the equivalent code of the C# project.

I had to make a some modifications to the VB code, because VB doesn't seem to support a number of recent C# language features (for example, pattern matching, local functions, async streams, collection initializer for existing collections within an object initializer), but it should have the same behavior.

@paul1956
Copy link
Contributor

paul1956 commented May 7, 2020

@kpreisser thanks for the VB demo and doing this, besides cloning this Repos and running VS 2019 Version 16.6.0 Preview 6.0 what else do I need to do to run the demo?

@RussKie
Copy link
Member

RussKie commented May 8, 2020

You need to have .NET 5.0 Preview 4 installed, that's where we merged it. Otherwise you need to build the source, and replace assemblies.

@paul1956
Copy link
Contributor

paul1956 commented May 8, 2020

@RussKie I think I do

dotnet --list-sdks
1.1.13 [C:\Program Files\dotnet\sdk]
2.2.402 [C:\Program Files\dotnet\sdk]
3.1.100 [C:\Program Files\dotnet\sdk]
3.1.201 [C:\Program Files\dotnet\sdk]
3.1.300-preview-015135 [C:\Program Files\dotnet\sdk]
5.0.100-alpha1-015536 [C:\Program Files\dotnet\sdk]
5.0.100-preview.3.20216.6 [C:\Program Files\dotnet\sdk]
5.0.100-preview.4.20202.8 [C:\Program Files\dotnet\sdk]

If you mean the runtime, only 3 is available.

@RussKie
Copy link
Member

RussKie commented May 8, 2020

Then you should all be set to run the demo

@kpreisser
Copy link
Contributor Author

kpreisser commented May 9, 2020

@paul1956 If the TaskDialogDemo isn't working for you, can you try to install the lastest Preview 4 build (5.0.100-preview.4.20258.7) from the daily builds page?

It could be that your version (5.0.100-preview.4.20202.8) is an older build that did not yet contain the changes of this PR.

@paul1956
Copy link
Contributor

paul1956 commented May 9, 2020

@kpreisser thanks that fixed it.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Windows Task Dialog