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

Cross-platform solution for Right click context menu on desktop app #7777

Closed
Tracked by #9139
ziaulhasanhamim opened this issue Jun 6, 2022 · 17 comments · Fixed by #9174
Closed
Tracked by #9139

Cross-platform solution for Right click context menu on desktop app #7777

ziaulhasanhamim opened this issue Jun 6, 2022 · 17 comments · Fixed by #9174
Assignees
Labels
area-controls-contextmenu ContextMenu fixed-in-7.0.0-rc.1.6683 proposal/open t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) t/enhancement ☀️ New feature or request

Comments

@ziaulhasanhamim
Copy link

ziaulhasanhamim commented Jun 6, 2022

Context-menu support in .NET MAUI

A context menu, often known as a right-click menu, offers contextual commands that are specific to the element being clicked on. In .NET MAUI a context menu can be added to any control that is a View, which includes all the controls that "take up space on the screen," such as Label, Entry, Image, Button, WebView, and many others.

Target platforms

  • Windows: Fully supported
  • MacCatalyst: Fully supported
  • Other platforms: We will consider Android and iOS support at a later time

Note that even on supported platforms there are differences due to what each platform supports in their native context menu support.

New APIs

The main new API is a new ContextFlyout property on the View base type, via a new IContextFlyoutContainer interface. The pattern is very similar to how a MenuBarItem contains various flyout menu items.

Compatible menu flyout types and properties

Type Windows properties MacCatalyst properties
MenuFlyoutItem for menu items you can click Text, IconImageSource, Clicked, Command[Parameter] Text, IconImageSource, Clicked, Command[Parameter]
MenuFlyoutSubItem to contain sub-menu items Text Text
MenuFlyoutSeparator for horizontal lines N/A N/A

Usage examples and screenshots

A simple context menu to enable right-click support on a label has XAML like this:

    <Label Text="Right-click to pick my color" x:Name="ColorLabel">
        <Label.ContextActions>
            <MenuFlyoutItem Text="Make label red" Clicked="MakeLabelRed"></MenuFlyoutItem>
            <MenuFlyoutItem Text="Make label blue" Clicked="MakeLabelBlue"></MenuFlyoutItem>
        </Label.ContextActions>
    </Label>

And some C# code to handle the events like this:

	private void MakeLabelRed(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.Red;
	private void MakeLabelBlue(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.LightBlue;

And this is what it looks like on Windows:

image

And slightly more advanced with sub-menus and icons in XAML:

    <Label Text="Right-click to pick my color" x:Name="ColorLabel">
        <Label.ContextActions>
            <MenuFlyoutItemText="Make label red" Clicked="MakeLabelRed">
                <MenuFlyoutItem.IconImageSource>
                    <FontImageSource Glyph="X" FontFamily="Arial" Color="Red" />
                </MenuFlyoutItem.IconImageSource>
            </MenuFlyoutItem>
            <MenuFlyoutItem Text="Make label blue" Clicked="MakeLabelBlue">
                <MenuFlyoutItem.IconImageSource>
                    <FontImageSource Glyph="X" FontFamily="Arial" Color="Blue" />
                </MenuFlyoutItem.IconImageSource>
            </MenuFlyoutItem>
            <MenuFlyoutSubItem Text="More colors">
                <MenuFlyoutItem Text="Hot pink" Clicked="MakeLabelHotPink">
                    <MenuItem.IconImageSource>
                        <FontImageSource Glyph="X" FontFamily="Arial" Color="HotPink" />
                    </MenuItem.IconImageSource>
                </MenuFlyoutItem>
                <MenuFlyoutItem Text="Pale Goldenrod" Clicked="MakeLabelPaleGoldenrod">
                    <MenuItem.IconImageSource>
                        <FontImageSource Glyph="X" FontFamily="Arial" Color="PaleGoldenrod" />
                    </MenuItem.IconImageSource>
                </MenuFlyoutItem>
            </MenuFlyoutSubItem>
        </Label.ContextActions>
    </Label>

And similar C# event handlers:

	private void MakeLabelRed(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.Red;
	private void MakeLabelBlue(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.LightBlue;
	private void MakeLabelHotPink(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.HotPink;
	private void MakeLabelPaleGoldenrod(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.PaleGoldenrod;

And you get this lovely user interface on Windows:

image

And similarly on MacOS (note that there are no icons supported):

image

Custom context menus with Entry (textbox)

  • On Windows, this works automatically
  • On MacOS this does not yet work (you always get the default MacOS menu with clipboard functions, etc.)

Custom context menus with WebView

  • On Windows you need code like this to disable WebView2's default menu:
                        // In the constructor, after calling InitializeComponent();
    #if WINDOWS
    			ContextMenuWebView.HandlerChanged += OnWebViewHandlerChanged;
    #endif
    
    #if WINDOWS
    	void OnWebViewHandlerChanged(object sender, EventArgs e)
    	{
    		if (ContextMenuWebView.Handler != null)
    		{
    			var webView2 = (Microsoft.UI.Xaml.Controls.WebView2)ContextMenuWebView.Handler.PlatformView;
    			webView2.CoreWebView2Initialized += OnWebView2CoreWebView2Initialized;
    		}
    	}
    
    	private void OnWebView2CoreWebView2Initialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args)
    	{
    		sender.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
    	}
    #endif
  • On MacOS this is being investigated.

Custom context menu location

Not yet supported. The context menu shows up exactly where the pointer was right-clicked, and opens in the appropriate orientation for the device.

Dynamic context menu items

Changing the contents of the context menus dynamically is not fully supported at this time. The code in the PR contains some comments to that effect. It should be implemented in both Windows and macOS.

Using {Binding ...} for context menu items

There are some limitations with binding in menu items. This is related to the following issues:

Original Description

Description

Right-click context menus are a very very important feature for desktop apps. Almost every desktop app needs this feature. But I don't think there is a cross-platform way to do it in MAUI.

Public API Changes

Have to introduce a new control for the context menu like other desktop frameworks.

Intended Use-Case

This can be very useful for providing desktop-specific options or when you are building a desktop-only app with MAUI

@jsuarezruiz jsuarezruiz added t/enhancement ☀️ New feature or request legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) labels Jun 6, 2022
@janseris
Copy link

janseris commented Jun 6, 2022

This is also useful on mobile apps.
The use case is long tap on anything on Android -> context menu or trigger multiselect.
This is equivalent to rightclick for desktop. Also in browser frameworks (touch vs mouse).

Considering the fact that an alternative for context menu which is swipe menu doesn't work with custom items (it's been 2 months but yet it is still included in the official docs) (#6018), this is a really needed feature.

@ziaulhasanhamim
Copy link
Author

@janseris agreed. On mobile, it is also useful. But normally I see them used more on the desktop side. I know ios/maccatalyst has native controls for context menu. WinUi and android also might have something like that.

@jfversluis jfversluis added this to the Future milestone Jun 16, 2022
@ghost

This comment was marked as outdated.

@Eilon Eilon self-assigned this Jul 7, 2022
@Eilon

This comment was marked as outdated.

@ziaulhasanhamim
Copy link
Author

At least, on Windows for now

It wouldn't be harder to do on ios and mac either. They have specific control for that. Just using that wouldn't be easy?

@Eilon

This comment was marked as outdated.

@Eilon

This comment was marked as outdated.

@Eilon

This comment was marked as outdated.

@janseris
Copy link

janseris commented Jul 13, 2022

Looks like MacCatalyst is indeed fairly easy:

image

The code is still in veeeeeeeery early stages so it will be quite some work to get it ship-ready. But it's looking good!

What about Android? We are currently using a workaround with Display Alert with string options to simulate context menu for collectionview items but that isn't really a robust solution, the menu item needs an object binding, just like Tag property in Windows Forms controls and anything to display, not just plain string.

@Eilon
Copy link
Member

Eilon commented Jul 13, 2022

Yeah Android will be interesting and I haven't thought about it much. My aim is to first have a good desktop experience where context menus are most expected. Once I get that working reasonably well, I'll look at iOS/iPadOS and Android.

@Eilon

This comment was marked as outdated.

@Eilon
Copy link
Member

Eilon commented Jul 21, 2022

Context-menu support in .NET MAUI

A context menu, often known as a right-click menu, offers contextual commands that are specific to the element being clicked on. In .NET MAUI a context menu can be added to any control that is a View, which includes all the controls that "take up space on the screen," such as Label, Entry, Image, Button, WebView, and many others.

Target platforms

  • Windows: Fully supported
  • MacCatalyst: Fully supported
  • Other platforms: We will consider Android and iOS support at a later time

Note that even on supported platforms there are differences due to what each platform supports in their native context menu support.

New APIs

The main new API is a new ContextFlyout property on the View base type, via a new IContextFlyoutContainer interface. The pattern is very similar to how a MenuBarItem contains various flyout menu items.

Compatible menu flyout types and properties

Type Windows properties MacCatalyst properties
MenuFlyoutItem for menu items you can click Text, IconImageSource, Clicked, Command[Parameter] Text, IconImageSource, Clicked, Command[Parameter]
MenuFlyoutSubItem to contain sub-menu items Text Text
MenuFlyoutSeparator for horizontal lines N/A N/A

Usage examples and screenshots

A simple context menu to enable right-click support on a label has XAML like this:

    <Label Text="Right-click to pick my color" x:Name="ColorLabel">
        <Label.ContextActions>
            <MenuFlyoutItem Text="Make label red" Clicked="MakeLabelRed"></MenuFlyoutItem>
            <MenuFlyoutItem Text="Make label blue" Clicked="MakeLabelBlue"></MenuFlyoutItem>
        </Label.ContextActions>
    </Label>

And some C# code to handle the events like this:

	private void MakeLabelRed(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.Red;
	private void MakeLabelBlue(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.LightBlue;

And this is what it looks like on Windows:

image

And slightly more advanced with sub-menus and icons in XAML:

    <Label Text="Right-click to pick my color" x:Name="ColorLabel">
        <Label.ContextActions>
            <MenuFlyoutItemText="Make label red" Clicked="MakeLabelRed">
                <MenuFlyoutItem.IconImageSource>
                    <FontImageSource Glyph="X" FontFamily="Arial" Color="Red" />
                </MenuFlyoutItem.IconImageSource>
            </MenuFlyoutItem>
            <MenuFlyoutItem Text="Make label blue" Clicked="MakeLabelBlue">
                <MenuFlyoutItem.IconImageSource>
                    <FontImageSource Glyph="X" FontFamily="Arial" Color="Blue" />
                </MenuFlyoutItem.IconImageSource>
            </MenuFlyoutItem>
            <MenuFlyoutSubItem Text="More colors">
                <MenuFlyoutItem Text="Hot pink" Clicked="MakeLabelHotPink">
                    <MenuItem.IconImageSource>
                        <FontImageSource Glyph="X" FontFamily="Arial" Color="HotPink" />
                    </MenuItem.IconImageSource>
                </MenuFlyoutItem>
                <MenuFlyoutItem Text="Pale Goldenrod" Clicked="MakeLabelPaleGoldenrod">
                    <MenuItem.IconImageSource>
                        <FontImageSource Glyph="X" FontFamily="Arial" Color="PaleGoldenrod" />
                    </MenuItem.IconImageSource>
                </MenuFlyoutItem>
            </MenuFlyoutSubItem>
        </Label.ContextActions>
    </Label>

And similar C# event handlers:

	private void MakeLabelRed(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.Red;
	private void MakeLabelBlue(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.LightBlue;
	private void MakeLabelHotPink(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.HotPink;
	private void MakeLabelPaleGoldenrod(object sender, EventArgs e) => ColorLabel.BackgroundColor = Colors.PaleGoldenrod;

And you get this lovely user interface on Windows:

image

And similarly on MacOS (note that there are no icons supported):

image

Custom context menus with Entry (textbox)

  • On Windows, this works automatically
  • On MacOS this does not yet work (you always get the default MacOS menu with clipboard functions, etc.)

Custom context menus with WebView

  • On Windows you need code like this to disable WebView2's default menu:
                        // In the constructor, after calling InitializeComponent();
    #if WINDOWS
    			ContextMenuWebView.HandlerChanged += OnWebViewHandlerChanged;
    #endif
    
    #if WINDOWS
    	void OnWebViewHandlerChanged(object sender, EventArgs e)
    	{
    		if (ContextMenuWebView.Handler != null)
    		{
    			var webView2 = (Microsoft.UI.Xaml.Controls.WebView2)ContextMenuWebView.Handler.PlatformView;
    			webView2.CoreWebView2Initialized += OnWebView2CoreWebView2Initialized;
    		}
    	}
    
    	private void OnWebView2CoreWebView2Initialized(Microsoft.UI.Xaml.Controls.WebView2 sender, Microsoft.UI.Xaml.Controls.CoreWebView2InitializedEventArgs args)
    	{
    		sender.CoreWebView2.Settings.AreDefaultContextMenusEnabled = false;
    	}
    #endif
  • On MacOS this is being investigated.

Custom context menu location

Not yet supported. The context menu shows up exactly where the pointer was right-clicked, and opens in the appropriate orientation for the device.

Dynamic context menu items

Changing the contents of the context menus dynamically is not fully supported at this time. The code in the PR contains some comments to that effect. It should be implemented in both Windows and macOS.

Using {Binding ...} for context menu items

There are some limitations with binding in menu items. This is related to the following issues:

@janseris
Copy link

@Eilon please consider Android as soon as possible

@Eilon
Copy link
Member

Eilon commented Jul 22, 2022

@Eilon please consider Android as soon as possible

For sure. It's all about priorities and what we can get done in time for .NET 7, so we will have to see how far we can get.

@Qws
Copy link

Qws commented Jul 24, 2022

Remember the right click context menu style of Windows 8 Metro apps?

Right-click (or hold-tap) on an item, and the Windows 8 style option bar fades in.

image

It's simple and functional, and would work on any screen size.

@Eilon
Copy link
Member

Eilon commented Jul 25, 2022

@Qws that's an interesting idea but out-of-scope for the current feature set. Right now we're aiming to get "regular" context menus available for desktop apps.

@Redth Redth mentioned this issue Aug 2, 2022
22 tasks
Eilon added a commit that referenced this issue Aug 5, 2022
Eilon added a commit that referenced this issue Aug 9, 2022
Add context menu (right-click menu) support for Windows and MacCatalyst.

Fixes #7777
Eilon added a commit that referenced this issue Aug 9, 2022
Add context menu (right-click menu) support for Windows and MacCatalyst.

Fixes #7777
PureWeen pushed a commit that referenced this issue Aug 10, 2022
Add context menu (right-click menu) support for Windows and MacCatalyst.

Fixes #7777
@samhouts samhouts changed the title Cross-platform solution for Right click context menu on desktop app 🔲Cross-platform solution for Right click context menu on desktop app Aug 16, 2022
@samhouts samhouts changed the title 🔲Cross-platform solution for Right click context menu on desktop app Cross-platform solution for Right click context menu on desktop app Aug 16, 2022
PureWeen pushed a commit that referenced this issue Aug 19, 2022
Add context menu (right-click menu) support for Windows and MacCatalyst.

Fixes #7777
PureWeen added a commit that referenced this issue Aug 23, 2022
* Context menus for all Views

Add context menu (right-click menu) support for Windows and MacCatalyst.

Fixes #7777

* Add Public API info

* Update PublicAPI.Unshipped.txt

* - add tests and fix BC propagation

* - cleanup winui handler

* - add comment and issue reference

* - add some additional samples for testing

* - add link to github issue

* - simplify ios mapcontextflyout

* - cleanup

* - Convert to MenuFlyout

* - fix handler names

* - fix test names

* - inline creating of args

* - add FlyoutBase API

* - fix Tizen API

* - fix device tests

* - switch to attached property

* - IContextFlyoutElement

* - fixed BP

* - fix propagated bindingcontext

* - rewire context menu code to be more on demand ios

- wire up context menu for MKWebView

* Update ContextFlyoutTests.Windows.cs

* Update Element.Impl.cs

* - fix extra ZIndex APIs

Co-authored-by: Shane Neuville <shneuvil@microsoft.com>
@hybridherbst
Copy link

I was wondering if this is also related to shell context menu methods coming to MAUI – a way to specify these in a cross-platform way would be very welcome (e.g. right click a folder in windows > specific shell menus come up).

@ghost ghost locked as resolved and limited conversation to collaborators Sep 22, 2022
@samhouts samhouts modified the milestones: Backlog, .NET 8 May 24, 2023
@Eilon Eilon added t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) area-controls-contextmenu ContextMenu and removed legacy-area-desktop Windows / WinUI / Project Reunion & Mac Catalyst / macOS specifics (Menus & other Controls)) labels May 10, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-controls-contextmenu ContextMenu fixed-in-7.0.0-rc.1.6683 proposal/open t/desktop The issue relates to desktop scenarios (MacOS/MacCatalyst/Windows/WinUI/WinAppSDK) t/enhancement ☀️ New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

9 participants