Video rendering issue in WPF when moving window between monitors with different screen resolution and/or scale

114 Views Asked by At

I have a winforms application (well, it is an VSTO Outlook Add-in that runs within Outlook) in which I am using a toolbar and within this toolbar I embed a WPF user controls through the use of an ElementHost container.

My application fits well for different screen resolutions and/or scale factors if I restart it every time I change some display settings such as screen resolution and/or scale.

But now I have below two problems:

  1. It is not fitting correctly according to the screen resolution and/or scale selected from the OS without restarting it.
  2. It is not fitting correctly if I move my application from one monitor to another that has different screen resolution and/or scale.

In both cases I have rendering issues: some black lines are being drawn magically at the edge of the control, see below some screenshots (The toolbar that you see at the top which has the title "My Custom CTP" is an VSTO Outlook control that forces me to embed a winforms user control, so I do: Winforms user control <---> ElementHost <----> Wpf user control):

Horizontal black line

vertical black line

Bottom black line

Also my SVG images which are drawn using a Path and also all my TextBlocks appear blurry.

I have tried different attempts but without success.

ATTEMPT #1:

Using software rendering only as explained here. In my WPF user control, just after InitializeComponent in the constructor view, I perform below:

 public myWpfView()
 {
    InitializeComponent();

    if (ForceSoftwareRendering)
        RenderOptions.ProcessRenderMode = RenderMode.SoftwareOnly;
 }

 public bool ForceSoftwareRendering
 {
    get
    {
        int renderingTier = (System.Windows.Media.RenderCapability.Tier >> 16);
        return renderingTier == 0;
    }
 }

ATTEMPT #2: In my Wpf User Control constructor I subscribe to DisplaySettingsChanged event to detect display settings changes and in the handler I perform some invalidate actions and inmediatelly after that I update the layout. Again without success:

 public myWpfView()
 {
    InitializeComponent();

    Microsoft.Win32.SystemEvents.DisplaySettingsChanged += SystemEvents_DisplaySettingsChanged;
 }

 private void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
 {
     this.VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor;
     this.VisualClearTypeHint = ClearTypeHint.Enabled;
     this.VisualEdgeMode = EdgeMode.Unspecified;
     this.VisualTextHintingMode = TextHintingMode.Auto;
     this.VisualTextRenderingMode = TextRenderingMode.ClearType;
     this.UseLayoutRounding = true;
     this.SnapsToDevicePixels = true;
     this.InvalidateVisual();
     this.InvalidateMeasure();
     this.InvalidateArrange();

     this.UpdateLayout();
 }

It looks like after changing screen resolution and/or scale, it is needed to update the layout for the wpf user control or something like that in order it readjusts without needing to restart it, so this is just what i tried to do in the SystemEvents_DisplaySettingsChanged event handler above indicate but without success. Maybe i am missing something, i don't know....

Additional Notes: I am using AutoScaleMode = dpi. Also tried font.

1

There are 1 best solutions below

0
Jeff On

I recommend first ensuring that your WPF visual itself has SnapsToDevicePixels=true.

The big risk within WinForms apps is that they don't really understand scalability and may be asking WPF for a fixed pixel-size 'image' (think WPF "frozen" visual objects) which are then scaled by the WinForms app to fit the available space. It sounds like this is what you're getting, and that this is a limitation of the WinForms app.

Also, while the control is spanning both monitors, WPF itself will render using only one of the resolutions, and scale the resulting image to the other resolution. I don't know of a way to know that the window no longer spans two monitors, but if you can find a way then you could trigger a RefreshVisual on the WPF elements to force them to re-render at the new scale.