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.
Related
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).
I have a WPF RichTextBox in my application that sits in Grid. It gets updated every second or two as it displays logs (though sometimes there are no logs for up to a minute depending on the load).
The grid is not always visible, as it sits in its own tab. If the user is on another tab, the logger is not visible.
My problem is that I want the RichTextBox to scroll to the end every time a new paragraph is added. It seemed simple as there is a 'ScrollToEnd' method on the RichTextBox control and so I call that method every time text is added to the control.
The problem is that that method only works if the control is visible, if the user is on another tab, the RichTextBox will not scroll to the end and it looks weird when you click on the tab with the logger and after a couple of seconds or longer it scrolls to the bottom when it should already be at the bottom.
Is there a way around this annoying "feature" of the control? I would like to ALWAYS have the RichTextBox be at the bottom unless the user is manually taking control of the scroll bar.
Thanks!
By default, the TabControl actually doesn't change its contents visibility, it removes them from the view completely when you change tabs and then "re-attachs" them when you navigate back to the previous tab.
That's why the Visibility change doesn't get fired. Instead, you should handle the Loaded event, which should get fired right before the view is re-rendered.
Is there a reason you cannot simply call ScrollToEnd in response to the text box becoming visible? That seems like the simplest approach. Did you try it and run into an issue?
Edit: If you are using a TabControl, each TabItem has an IsSelected property you can bind to from the ItemContainerStyle. You could probably scroll your text box in response to the tab becoming selected.
As a separate note: if you are planning to make a custom control for this, here are some things to consider.
I wrote an auto-scrolling version of a FlowDocumentScrollViewer. (I never needed a RichTextBox specifically, but they display similar content.) I can tell you that there are a lot of things to account for, such as knowing when and when not to auto-scroll based on what the user is currently doing.
For example:
If the user takes over the scrolling themselves via the scrollbar or mousewheel, you don't want the control to fight with them.
If they start selecting text, you don't want to scroll it away from them mid selection.
If they scroll to the bottom, you probably want it to start auto-scrolling again.
Also, determining what the user is doing to begin with can sometimes be a complex process on its own.
I have created a custom popup to decorate my buttons with animated tooltips. I track Button.MouseEnter for the button to decide when to display the popup. I use Button.MouseLeave to determine when to hide the popup.
Problem is Button.MouseLeave is fired prematurely if the popup moves over the mouse cursor (its appearance is animated) despite the fact that I have set IsHitTestVisible = false for the popup and all its visual children.
Is this the way WPF is designed to work? I need MouseLeave to only fire when the cursor moves away from the button itself and not be influenced by the popup.
Thanks
I believe that the Popup control is actually contained within a window, which is why the popup can extend beyond the window bounds in some cases. (It's also why popup transparency is not supported in Silverlight.)
I believe that while the popup control is no longer processing "hits", the container window is, which is why you are losing your button's mouse focus.
I've not tested this, but you might try creating a template for your button and actually declaring the popup as part of the button (rather than below it). This may cause WPF to view the popup control as part of the button and eliminate the problem of losing mouse focus. This works in other scenarios, but I'm not 100% sure how this will work with a Popup.
EDIT: As a side note, the deault WPF tooltip allows you to override the template. I'm not sure what your goals are, but you may find it easier to change the appearance and behavior of the default tooltip than to try to roll your own, as a lot of these sorts of problems have already been solved in the default Tooltip.
I have an ItemsControl with a number of elements, each one with its own ViewModel instance. Each item's ViewModel knows whether that item should be visible (currently each ViewModel has a Visibility property that the UI binds to). When my window first opens, some of these items are visible, others are collapsed. Later, some items' visibility might change in response to user interaction. The window sizes to its content, so the window resizes when items are shown or hidden. And the window is initially centered on the screen (which means everything has to be arranged properly right away, so the window knows its initial size and can center itself accordingly).
Now I want to add animations whenever an item is shown or hidden -- but I only want to animate if the item's visibility changes after the window is already shown. So if the window is already open, and the user does something that makes one of the ViewModels want to appear, it animates in; if the user does something to make one of the ViewModels disappear, it animates out. But when the window first opens, I want everything to start out rock-solid -- no lingering animations.
And I want the window to still set its initial size based on its initially-visible content, and I still want it to be initially centered onscreen. (Although actually, in this case, it would be acceptable if it centered itself as if all items were visible, if event ordering made it work out that way.)
I know a fair bit about WPF, but I admit I'm lost when it comes to triggers and storyboards. I haven't really done anything with WPF animations before, and I'm not sure where to begin.
I already tried using Reveal from the Bag of Tricks, but I had several problems with it, the biggest being that it doesn't have the "only use animations after the window is shown" behavior that I want -- my window would appear and the initially-visible elements would still be animating in. It also didn't play well with my layout (it was centering the elements horizontally, instead of stretching them to the ItemsControl's width), and a few other problems that might or might not be fixable.
I'm not too picky about whether I animate by stretching (e.g. by animating a LayoutTransform from SizeX=1 SizeY=0 to SizeX=1 SizeY=1, thus starting with squished text and expanding to normal size) or by just changing the Height (thus starting with only part of the content visible and revealing more as the animation progresses) -- I'm fine with either.
I'm open to writing my own Panel descendant (I've done it before) if that's the best way to solve this, and I can always steal code from Reveal and hack until I get it working -- but it seems like there should already be an easier way to do this, if I just knew what it was. I'm open to learning about triggers and storyboards, or whatever, if someone can point me in the right direction.
From what I understand, the popup exists within it's own visual tree. However, I've noticed a few properties, Clip and ClipToBounds. What I am wanting to do is Visually clip a popup at the right and bottom edges of a window regardless of the fact that the popup is independent of the bounds of the window. I'm not using XAML, but if somebody knows how to do it in XAML, then that's fine. I can get to the main window using System.Windows.Application.Current.MainWindow. Is it possible from this to get a value that I can use to clip the popup? I'm assuming that if there is a value that I can use, then I would be able to bind the clipping of the popup to that value. This is really not necessary since after the popup initially opens, if the window gets moved or resized, the popup closes. So I would really only need to clip the popup when it opens. The reason I would like to do this is because although I am using a popup, I don't want it to appear as a popup that exists outside of the window. FYI this is for a popup calendar for a custom datebox. Any ideas, as well as clarification of misconceptions that I may have, would be greatly appreciated.
Furthermore, the popup can be launched from a user control that is not directly on the Main Window. So in that case it would be easier to use a popup. As apposed to a UC inside the XAML
I know this is a year old post, but in case any others come here looking for answers... If you don't need the popup to be outside of your window, why use a popup at all? It'd be far easier to simply use a control in a canvas (for instance) and control it via its Visibility property. Then you'd automagically get your clipping.