WPF WebView in dialogue window shows no content first time displayed - wpf

I have a WPF application running on a Win10 desktop using the new (Microsoft.Toolkit.Wpf.UI.Controls.WebView v5.0.0.0) WebView control in a dialog window. The first time this dialog window is created, WebView navigation successfully completes but most of the time the WebView stubbornly continues to display a blank page.
If I minimise that first instance of the dialogue window and restore it, the content is instantly rendered. If I close that window instance and create a new one, the control generally renders as expected.
Changing the WebView.Visibility in code to Collapsed and then back to Visible on navigation completion doesn't fix the blank page.
Has anyone seen this behaviour? Does anyone have a solution to provoke WebView to actually render?
In theory the new WebView is a better architectural option than reverting to the old WebBrowser so I'm loathe to go down that path.
Additional detail
Windows 10 desktop, x64, targeting .NET 4.6.2, WPF 4.x.
The WebView instance is defined in XAML (without a Source binding) inside a UserControl.
The UserControl is embedded in a window defined in XAML, which only contains a root level Grid to contain the UserControl.
That window is shown via ShowDialog().
Source navigation is performed in code behind controlled by the current selection of a TabControl.
The WebView is NOT defined in the TabControl item template (doing so throws exceptions most of the time on tab selection change). It is in a container that is a sibling to the TabControl.
The NavigationCompleted event reports success.

I found that attempting to minimise and then restore the containing window in code didn't fix it, despite minimise & restore working when the user does it. Invalidating the control layout or visual or arrange didn't work. Maximising and restoring the window in code did, but is visually annoying, but it led me to two reasonable workarounds:
Configure the WebView.Visibility to be Collapsed in XAML and either:
handle the UserControl.Loaded event and set the visibility to Visible; or
handle the WebView.NavigationStarting event and set it to Visible.
Those are easiest if starting out collapsed won't cause unacceptable visual disruption. Getting in early via the Loaded event helps. Starting out Hidden doesn't work.
Leave WebView.Visibility configured to Visible in XAML, handle the WebView.NavigationStarted event in the UserControl, and then if it's the first time the handler called in this process do something like this to cause the control to resize and then restore the original size:
var height = Height;
Height = 0;
Application.Current.Dispatcher.BeginInvoke(
(Action)(() => { Height = height; }),
DispatcherPriority.Input
);
Dispatching the value restoration seems to be required (although maybe calling something like InvalidateLayout() in between would suffice).

Related

Silverlight combo popup not displayed correctly when window resizes

If I create a ComboBox from scratch, when the window is resized, the content is correctly displayed above/below, etc.
Why this doesn't happen when you create your own Combo-derived class? What am I missing?
Controls aren't magical. They need to be told that things happen (call a method on them) or look for them to happen (register for an event).
Find your Application.RootVisual and register for a SizeChanged event. Then resize your control. If it is in browser you may need to create a javascript bridge (hopefully not) that tells your SL object when the browser resizes.

Force WPF to render a window while hidden?

I've noticed that when I make a change to the visual presentation of a window while the window is hidden, the changes are not immediately visible when the window is shown. Rather, the window appears briefly in the state it was in when it was last-visible, taking 0.5-1 seconds to display the updated form.
This can be confusing and ugly as when my window is shown, it defaults to having no items selected, yet if there were items selected when it was closed, it will appear as though those items are selected again when it is opened, only to disappear a second later.
Is there any way I can force WPF to render the window even though it is not visible, so that when it is shown it is in the correct state?
Turns out this is a limitation of the operating system--apparently WPF can't access the window bitmap or something if the window is hidden. I found a workaround by setting the Opacity of the window to 0 or 1 instead of hiding/showing and it seems to work pretty well.

Closing a window when it's "no longer needed"

This is kind of a hard question to describe, and I've searched for about an hour now to no avail.
Essentially, picture a small 'flyout' window like the Windows 7 Wireless Control or the Volume Slider from the system tray(notification area). When you click on the icon, the application pops up with focus, and if you click off of it, the window destroys itself.
I thought it woudl be easily solved by simply having my window destroy it self when it loses focus (I've been listening for WM_KILLFOCUS), but the problem is, if the icon is clicked, my window does not always get focus. Since this isn't the case, if the user clicks my icon, and then clicks away because it was a mistake (on the desktop say), then how can I set my app to close?
I've tried messing with SPY++ but checking the volume control / wireless control apps are proving difficult as they disappear when I try to get their window/process handles.
Thanks!
The usual way this is implemented is by starting a timer on the window creation. If the window gets the focus before the timer has triggered, this means the user has interacted with the window. In this case, the window will just stop the timer and will destroy itself when it loses the focus. In the case the window did not get the focus before the timer was triggered, the window will destroy itself on the timer event.
This is also usually combined with opacity animation, so that the window is fading out while waiting for the user. Sort of a visual feedback to the user that it will be soon gone. However, the opacity animation is used mostly for notification toasts, and is rarely used for control windows like the volume control.
The alternative is to force set the focus in your window when the user interacts with your systray icon.
Also note that if your window is a top-level window, the preferred message to listen is not WM_KILLFOCUS, but WM_ACTIVATE and WM_MOUSEACTIVATE. You can also listen to WM_NCACTIVATE, but that one has some specifics, if you are doing a custom non-client area.
Update: You can set the focus to your window by calling either SetActiveWindow or SetFocus on it when you create it (or when you make it visible, if you're hiding it).
A long, long time ago I wrote a drop-in replacement for the Windows 3.1 Task Manager that accomplished this by handling WM_ACTIVATEAPP. Give that a try.
Have you looked into the Popup? That one will disappear once you click outside it (unless you set StaysOpen to true).

Set focus to another control after TreeView click

I have a TreeView control in a Windows application. I am opening another window from the TreeView click (Single Click) event (in tabbed environment, so all windows will appear as a tab in Visual Studio). I want to set focus to one control of the new window.
The problem is that, I am able to set the focus on the double click event of the TreeView. But same doesn't seem to be working with the TreeView single-click event.
Any workarounds?
Have you tried doing this in MouseUp instead? If that fails, there's always an easy (but disgusting) solution when it comes to UI issues like this: start a timer (with a running time of 10 ms or so) that will set the focus when it fires.

WPF Popup and WindowsFormsHost Problem

I am hosting windowsforms control in WPF popup. Problems below:
If i make StaysOpen=False i can't interact with winform control. StaysOpen to false is required because when clicked outsidet the Popup region, it should close.
if i make StaysOpen=True i can interact with winform control but when i click outside the area of popup, it is not getting closed.
I tried setting StaysOpen=true in MouseEnter of popup and StaysOpen=False in MouseLeave, but MouseLeave fires as and when mouse is over winform control resulting in unexpected behaviour.
I even tried IsMouseCaptureWithin property of popup and found it does not work with winforms (i guess its a bug in framework).
Another problem, i was trying to close popup when root main form (which is windows form) is deactivated (pressed Alt+Tab), but this event (deactivate) is fired even when i enter into one of the controls in windowshostControl in popup.
Desired Behaviour:
should be able to host and interact with winform control in wpf popup.
on clicking on outside the area of popup, popup should close.
Appreciate any inputs.
Thanks.
I've had many problems with the defacto-standard popups in WPF, because they are in fact a new window with their own handle. This means if you drag your application around the screen, the popup stays put (it doesn't move with your window). It also means your popup has some strange behaviors and doesn't interact with your application in ways other controls normally do.
I've created 2 decorator classes to address this problem:
PopupDecorator.cs and
TimeoutPopupDecorator.cs
It's pretty simple to use:
Add a namespace declaration for the new popup classes. i.e.
xmlns:dday_wpf="clr-namespace:DDay.WPF"
Surround the area you want the popup to be able to be displayed with the decorator. i.e.
<dday_wpf:PopupDecorator x:Name="popup">
<dday_wpf:PopupDecorator.Popup>
... contents of popup go here ...
</dday_wpf:PopupDecorator.Popup>
... contents of panel go here ...
</dday_wpf:PopupDecorator>
It works pretty much identically to a normal Popup from that moment on.
This may not solve all your problems, but hopefully it helps.
This sounds a bit like my problem launching a modeless winform control from a WPF form.
Check out my question Why is my WPF textbox "kinda" readonly?.
The just being, based on what Doug said about popups being a window with its own handle, makes this applicable.

Resources