2

I'm trying to convert IE web browser window into a CefSharp (v 96.0.180) window into as a part of a larger WPF application. The application itself follows the system dpi level (resizes UI with it), but the IE window kept 100% dpi no matter what was the system setting. ​When I converted the control to CefSharp, it would start to follow the system dpi. The problem is that the page is rendered zoomed in and ugly on any dpi over 100%.

To check the Cefsharp window behavior I've tried setting dpi awareness to true or per monitor using app manifest, but it didn't work (and also I'm concerned that it would set it for the whole application, while I only need it for one window/project).

Is there any way to achieve it?

EDIT: code per request: BrowserView.xaml:

<Grid>
<ContentControl Name="wBrowser" RenderOptions.BitMapScalingMode="HighQuality" />
</Grid>

BrowserView.xaml.cs:

public BrowserView()
{
    CefRuntime.SubscribeAnyCpuAssemblyResolver();
    Cef.EnableHighDPISupport();
    LoadApp();
    InitializeComponent();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private static void LoadApp()
{
    var settings = new CefSettings()
    {
        CachePath = _cachePath,
        LogSeverity = LogSeverity.Disable
    };
    //settings.CefCommandLineArgs.Add("high-dpi-support", "1");
    //settings.CefCommandLineArgs.Add("force-device-scale-factor", "1");
    settings.CefCommandLineArgs.Add("disable-gpu-compositing");
    Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
}

(I've also tried to move these calls to App.xaml.cs Main method which I've created as advised in CefSharp wiki/GeneralUsage. Those were the first calls in Main. No effect, whatever I put as commandline args.)

In the same BrowserView.xaml.cs file in an event handler for an event fired when control's been loaded:

var chromiumWebBrowser = new ChromiumWebBrowser();
wBrowser.Content = chromiumWebBrowser;
// call to Window.Show() here
chromiumWebBrowser.LoadUrl(url);

In conclusion, none of the actions above made the window look as it would look if I switched the system settings to DPI 100% and rerun the application (and that look is what I need).

EmeraldP
  • 23
  • 6
  • Please share your Xaml code for us to answer your question. – G K Jan 30 '22 at 15:15
  • I shared the relevant xaml part – EmeraldP Jan 30 '22 at 15:36
  • See https://github.com/cefsharp/CefSharp/wiki/General-Usage#high-dpi-additional-info – amaitland Jan 30 '22 at 19:33
  • @amaitland I've read this and based on what I understood I've called Cef.Initialize with "disable-gpu-compositing" commandline argument, but there was no effect. I call that initialization in the constructor of my code behind class for the view. – EmeraldP Jan 30 '22 at 20:15
  • Please edit your original question and show your code. – amaitland Jan 30 '22 at 20:59
  • @amaitland I've shared the code. Thanks – EmeraldP Jan 31 '22 at 11:45
  • It looks ok. Load chrome://version in a ChromiumWebBrowser instance and see if the command line args is present. – amaitland Jan 31 '22 at 19:46
  • @amaitland command line args are present. There is `disable-gpu-compositing` and `log-severity` which I explicitely set and also: `browser-subprocess`, `no-sandbox`, `lang`, `log-file` and `disable-features` specifying `CalculateNativeWinOcclusion,WinUseBrowserSpellChecker`. From other properties also Cache Path is set according to my setting. – EmeraldP Jan 31 '22 at 21:00
  • Looking closer and I'm confused, are you trying to make your application DPI aware? You originally said you didn't want your application to be DPI aware, in your example now you've updated the manifest and called Cef.EnableHighDPISupport (which is likely called way to late to have any meaningful effect). Please clarify. – amaitland Jan 31 '22 at 22:14
  • If you are using a recent version of Windows 10 you can check DPI awareness in task manager see https://www.thewindowsclub.com/how-to-view-dpi-awareness-mode-of-apps-in-task-manager-of-windows10#:~:text=Right%2Dclick%20on%20the%20taskbar,the%20Task%20Manager%20details%20section. There is a basic working example provided at https://github.com/cefsharp/CefSharp.MinimalExample – amaitland Jan 31 '22 at 22:15
  • @amaitland I want app to stay not dpi aware. The reason I've set manifest and called EnableHighDPISupport (as I said it was in App.xaml.cs as a first call) was a test of whether these settings will have an effect on the ChromiumWebBrowser control. Sorry if I was not clear. Originally my app has DPI Awareness set to Unavailable in task manager. When I set manifest changes it changes to PM(v2) in taskmgr. All CefBrowser subprocesses have PM. – EmeraldP Feb 01 '22 at 00:25
  • @amaitland So depending on whether I set the manifest, the window itself will rescale or not when changing the monitor. But the problem is that the ChromiumWebBrowser control content is stretched based on system DPI (when it's 175% the page gets really stretched and when 100% it looks like I want it). I'd just like the content to not be stretched and blurry no matter the system DPI – EmeraldP Feb 01 '22 at 00:25
  • I'd suggest testing with the minimal example I linked above. How are you testing DPI changes? Are you making sure your application is closed before changing DPI? Your question is quite confusing now as it has DPI awareness code which it doesn't sound like you actually want. Check the http://cefsharp.github.io/api/97.1.x/html/P_CefSharp_Wpf_ChromiumWebBrowser_DpiScaleFactor.htm after the browser has fully loaded with a DPI greater than 100%. – amaitland Feb 01 '22 at 07:47
  • I test by reopening my app after I change the system DPI. Changing DPI scale factor changes the size of the control inside window but the UI of the page is still stretched, relatively it's the same, just within smaller area. I'll keep looking for the solution – EmeraldP Feb 01 '22 at 09:40
  • @amaitland I've managed to get an acceptable solution for this case by using https://cefsharp.github.io/api/96.0.x/html/M_CefSharp_WebBrowserExtensions_SetZoomLevel.htm with a factor calculated based on retrieved machine dpi. I call that in an FrameLoadStart event handler late enough that it has an effect and early enough that it won't show the transition to the user. Thank you for your help on this issue – EmeraldP Feb 02 '22 at 00:04
  • Did you check the value of the DpiScaleFactor property? – amaitland Feb 02 '22 at 00:31
  • @amaitland Yes, in my application it matches what is set on the device. 1.25 for 125% DPI etc. Also, to make it less confusing, I removed app.manifest code from original question – EmeraldP Feb 02 '22 at 01:11
  • So your application is system DPI aware (WPF default), so it already scales correctly. What was the problem making your application per monitor DPI aware exactly? If you are targeting. Net 4.6.2 or greater then CefSharp should handle DPI changes automatically, if you are using an older version you need to manually change the DPI https://github.com/cefsharp/CefSharp/blob/cefsharp/97/CefSharp.Wpf/ChromiumWebBrowser.cs#L1692 sounds like you have a workable solution, though honestly I'd be choosing to go per monitor DPI aware. – amaitland Feb 02 '22 at 02:04
  • I don't want to use manifest to set awareness, because I don't want to modify any more behavior of the app itself than it's needed for the purpose of a single browser control. But even when I set the per monitor in the manifest the browser content is still stretched. It shows the same content to window ratio no matter what display is used. I think he problem is not about DPI changes between the monitors but rather initial view. – EmeraldP Feb 02 '22 at 02:39
  • @amaitland Unfortunately I'm targeting 4.6.1. I assume the handler from the link is what I would use on 4.6.2. So in my case it's ok that I call SetZoomLevel based on DPI I read? I think I will use DpiScaleFactor property for that as I used PresentationSource class earlier and this DpiScaleFactor seems more straightforward – EmeraldP Feb 02 '22 at 02:41
  • I mean DpiScale factor as a purpose of reading devices DPI, if that's reliable – EmeraldP Feb 02 '22 at 02:54
  • If you target .net 4.6.2 then it should all work without you doing anything. On prior versions the DPI is only updated when the ChromiumWebBrowser is attached/moved to a window. https://github.com/cefsharp/CefSharp/blob/cefsharp/97/CefSharp.Wpf/ChromiumWebBrowser.cs#L1650 You can use a sourcehook and intercept the https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-dpichanged message – amaitland Feb 02 '22 at 04:54
  • @amaitland I added a hook to intercept messages for the window but I don't receive WM_DPICHANGED msg code no matter whether I change DPI in system or move window between displays. I receive many other messages, just not this. Btw what would you expect me to do when I intercept this message? Is the purpose to read dpi in a reliable way? – EmeraldP Feb 02 '22 at 10:22
  • I also think it the message would have to be intercepted on window opened because the browser needs to be rescaled from the very beginning and I'm not sure it's when the WM_DPICHANGED is fired. Btw for now to determine DPI I use CompositionTarget.TransformToDevice.M11 – EmeraldP Feb 02 '22 at 12:28
  • Is your application per monitor DPI aware? You need to manually call NotifyDpiChange on the browser when the DPI changes. Or better yet upgrade to .Net 4.6.2 to get some of the DPI improvements. https://github.com/Microsoft/WPF-Samples/blob/master/PerMonitorDPI/readme.md is the best summary I'm aware of. – amaitland Feb 03 '22 at 03:57

0 Answers0