MicrosoftEdge / WebView2Feedback

Feedback and discussions about Microsoft Edge WebView2
https://aka.ms/webview2
450 stars 54 forks source link

Select dropdown positioning #780

Open hunkydoryrepair opened 3 years ago

hunkydoryrepair commented 3 years ago

Description Using a regular SELECT dropdown, I regularly see the dropdown appear in the wrong place the first time it is opened. Closing and reopening repositions it correctly. I also see the dropdown stay open and remain in the same place on screen when the application window is moved. The starting position does not seem to be predictable and doesn't seem to matter if it is generated by javascript or not.

Version SDK: 1.0.721-prerelease Runtime: WebView2 Runtime 87.0.664.66 Framework: WinForms OS: Win10

Repro Steps Open page (via http in my case) which contains a select element:

Move main window (doing this before opening seems to cause the issue)

Click the drop arrow to open the drop down.

Note position is (usually) in the wrong place when first opened, sometimes not even close to the control.

Move parent/application window, the popup does not move with it.

Close the popup and open it again and it appears in the correct place.

Screenshots image

Additional context does not seem to occur in Edge with same runtime version, however the popup closes when moving window, presumably when losing keyboard focus.

AB#31232908

hunkydoryrepair commented 3 years ago

This can be demostrated using the sample WebView2 app and navigating to this simple fiddle https://jsfiddle.net/7r92mpxf/1/

Move the app window after loading page but before clicking on the SELECT dropdown.

image

jasonstephen15 commented 3 years ago

Thanks @hunkydoryrepair for the feedback, I've definitely experienced this bug as well. Opening a bug report internally, hope to get this fixed for you soon! Apologize for any inconvenience in the meanwhile.

RWeigelt commented 3 years ago

Any news on this issue? This turned out to be a major showstopper for a project I am working on, so work literally had to stop some time ago. I am hosting an existing business application which I have no control over. The proof-of-concept is working great - except for this issue, which makes the solution "un-demo-able" at the moment.

kczx3 commented 3 years ago

This particular issue is resolved by properly calling NotifyParentWindowPositionChanged. Calling this does not however fix the issue where the dropdown is open and the window is then moved. The dropdown list does not follow with the window.

kczx3 commented 3 years ago

It seems to me that WebView should handle this better. That said, my current fix is to simply monitor WM_NCLBUTTONDOWN and call SetFocus() and pass the parent's hwnd. That's what seems to occur in normal Edge at least. This causes the drop list of the select element to close. The use of NotifyParentWindowPositionChanged then handles the droplist appearing in the correct place when re-opened after the parent window has moved.

nabils commented 3 years ago

Any update on this one? Just realised I reported a duplicate. This is a showstopper for us too.

Any workaround for WPF at all? @jasonstephen15

DominicFarrington commented 3 years ago

@jasonstephen15 any updates on this? We're almost 5 months on from the issue being reported.

@kczx3's solution works but the CoreWebView2Controller for the webview is not exposed in C# so implementing this for WinForms is very ugly.

hunkydoryrepair commented 3 years ago

@kczx3's solution works but the CoreWebView2Controller for the webview is not exposed in C# so implementing this for WinForms is very ugly.

I can't find how to do this at all in WinForms. Any suggestion what the "ugly" solution is?

DominicFarrington commented 3 years ago

@hunkydoryrepair you'll need to use reflection to get access to the CoreWebView2Controller that's a private member of the WebView - like this:

var controller = webView.GetType().GetField("_coreWebView2Controller",
                    BindingFlags.NonPublic |
                    BindingFlags.Instance).GetValue(webView) as CoreWebView2Controller;

Once you have the controller you can call NotifyParentWindowPositionChanged on the controller and shift the focus to another control then the workaround will work.

nabils commented 3 years ago

Unfortunately the above did not work. I got a null ref exception when trying to call it via c#/WPF.

nicholasdgoodman commented 3 years ago

In Winforms there is a fairly straightforward hacky workaround that will get the dropdowns in the correct position.

First, you have to find some event to trigger off of that fires whenever the absolute position of your WebView2 has moved on the screen. If you own the entire app / form, this could be as simple as Form.Resize event or Form.Move. It gets a little more complicated if the WebView2 can move within its parent form, and then you need to traverse up the control tree and handle any move or resize events.

Then, in order to get Chromium to understand it has moved, you simply "wiggle" one of the WebView2 size dimensions, Width or Height. This works especially well if the view is docked with DockStyle.Fill as there are no visual consequences of doing so.

In this example I will use a simple polling timer to determine if the WebView2 has moved:

public class ControlWithWebView2: Control
{
  private WebView2 webView;
  private Point currentLocation;
  private Timer locationPoll;

  public ControlWithWebView2()
  {
    this.webView = new WebView2()
    {
      Dock = DockStyle.Fill
    };
    this.Controls.Add(this.webView);

    this.currentLocation = this.PointToScreen(Point.Empty);
    this.locationPoll = new Timer()
    {
      Interval = 1000,
      Enabled = true
    };
    this.locationPoll.Tick += LocationPoll_Tick;
  }

  private void LocationPoll_Tick(object sender, EventArgs e)
  {
    var newLocation = this.PointToScreen(Point.Empty);

    if(newLocation != this.currentLocation)
    {
      this.webView.Width++;  // no effect, but tricks Chromium into resetting its bounds
      this.webView.Width--;
      this.currentLocation = newLocation;
    }
  }
}
hdaniel1 commented 2 years ago

Using WPF, I don't have this issue with the select opening in the wrong place, but if I move my window, the dropdown doesn't collapse or move with it (I would expect the former, seeing it is the normal browser behavior).

Is there any workaround this? I can't seem to figure out how to programatically collapse the select element using JS, which was the approach I was attempting on window.locationChanged.

**EDIT - I fixed it using the webview2 .Focus() method on position changed.

TheWillard commented 2 years ago

@jasonstephen15 Are there any news on this?

nathanbabcock commented 2 years ago

Are there any plans to fix this?

nicholasdgoodman commented 2 years ago

As @hdaniel1 points out, calling webView.Focus() when the window position is changing will close a select element dropdown if it is currently showing (and also keeps it correctly focused so pressing spacebar will re-open it).

If you have a WPF window with more than one WebView2 control or other WPF controls on it, you can improve on this by only calling focus on the WebView when it already has it. Unfortunately, because of the way the focus is transferred into a non-WPF control, checking webview.IsFocused always returns false.

Using some Win API it is possible to "smart focus" the control to close the dropdown. On position change event or polling, you can call:

[DllImport("user32.dll")]
private static extern IntPtr GetFocus();

[DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern IntPtr GetParent(IntPtr hWnd);

private void CloseDropdownIfFocused(WebView2 webView)
{
    var hwnd = GetFocus();

    while (hwnd != IntPtr.Zero)
    {
        if (hwnd == webView.Handle)
        {
            webView.Focus();
            break;
        }
        hwnd = GetParent(hwnd);
    }
}
SharpEnvelope commented 1 year ago

We are also running into this..

one1lion commented 1 year ago

I read through this thread and see that it is common. I was able to get the select list to collapse in my Blazor UI in the Window's OnLocationChanged event, but I am experiencing the issue where expanding a select element after moving the window still has the dropdown open in the wrong place. I believe the answer is to use NotifyParentWindowPositionChanged, but I don't know how to do this. I have searched and found stuff about using SendMessage, but I don't know if this is correct. Does someone have a sample of calling NotifyParentWindowPositionChanged in a WPF application? Is OnLocationChanged the right place to do this? I appreciate your time.

HO-COOH commented 6 months ago

2024 now and the bug still exist. The major issue for me is after moving the window, the select menu is positioned at the window's previous location. I am using Win32 HWND mode for webview2.

image