FlowDocument loses ClearType in child elements when placed in window with custom glass - wpf

So the new WPF 4 text rendering looks great, but enabling the aero glass effect on a window requires that you change the background to transparent, which of course disables ClearType rendering.
Using the provided RenderOptions.ClearTypeHint=Enabled allows you to designate child elements to reenable ClearType rendering from that point in the tree. I've found a few other topics that talk about doing this for the ScrollViewer used internally inside RichTextBox and FlowDocumentScrollViewer, and creating a custom style does indeed fix it so that my FlowDocument gets ClearType rendering again.
However, this only applies to top level paragraphs in the FlowDocument. If I add floaters or figures, or a table, any text inside them is inexplicably grayscale again. I know that the glass effect is to blame, since disabling it reenables the ClearType rendering.
I looked through the visual tree with Snoop, but both the main content (which renders properly) and the sub-content (which is grayscale) have similar element hierarchies without anything to which I can attach RenderOptions.ClearTypeHint.
Has anyone run into this problem? Is there a workaround or a solution? I checked Connect but there isn't any bug filed about this. It's quite an annoying problem.

After doing a lot more research, and comparing the way different controls work on and off of aero glass, I've found a few answers. The TextBox control doesn't work properly either, but portions of FlowDocument and things like TextBlock do, which prompted me to explore why.
After digging around in reflector for a while, I found that when using the advanced text formatting APIs to get text and render it onto a drawing context, the RenderOption flags essentially go ignored, since the drawing system knows from the root visual (the window) that transparency was enabled. Once that happens, all the RenderOptions flags in the world aren't going to get ClearType back.
I did happen to stumble on a work-around though. If you have access to the DrawingContext and are doing the low-level text rendering yourself, you can do a DrawRectangle behind the text with a fill, and ClearType gets reenabled. I assume that this is the only way for the renderer to be sure that it has a proper background to draw on.
So in summary, you need to do your own text drawing, and additionally you need to explicitly draw a background using the same DrawingContext behind your text in order for ClearType to get rendered properly.

I know this could get tedious, but have you tried setting general styles like so:
<Style TargetType="Paragraph">
<Setter Property="RenderOptions.ClearTypeHint" Value="Enabled"/>
</Style>

Related

Why is there a black lag every time a WPF window is resized?

Other questions on SE address how to speed up nested UI control resizing, but- what if there aren't any controls?
As you drag the edge of a WPF window, even a main window with no content, black bars flicker briefly during the drag. This produces a crummy feel- one that I don't want to inflict on customers:
It does get slower and heavier with a full UI on top of it as well. This doesn't even get into how ugly it looks when resizing using the top or left edges. Windows Forms- even with the heaviest UI I've built- never looks this bad right off the bat.
What can be done to make WPF window resizing performance comparable to win forms?
(I have Windows 7 x64 and a triple monitor system on an AT Radeon HD 7470.)
You could update your graphic card and try it out again but that wont change anything. The reason is pretty simple. We all get to see this sometimes based how fast/slow our computer is. Sometimes it runs smooth because we do not have many visuals to draw. The reason is no proper background color is found in graphic card at that moment in redrawing process. Your drivers are fine, and its not just because you use Wpf. Other techniques use the same mechanism behind redrawing.
The first thing WPF will do is clear out the dirty region that is going to redraw. The purpose of dirty regions is to reduce the amount of pixels sent to the output merger stage of the GPU pipeline. Here is where we see the black color. Window itself at that point has no background color or its background color is set to transparent and so to us the GPU draws the black background. Things run async in wpf which is good so.
To fix this you could set a fix color such as "White" to the Window. Then the WPF system will clean out the dirty region but fill it automatically with white color instead of black. This usually helps.
Match the window color or the color of top most layer. Dont let GPU use black and you should do fine. Btw Wpf is faster than WinForm so dont worry.
The look is crummy indeed, especially when using the top or left border.
Which exact problem your screen shot is showing depends on how long your app is taking to render as well as a couple of background related settings that you might be able to tweak to get better resize. Plus part of the ugly resize is specific to Aero.
While I can't address the specific crazy slowness of WPF redraw, I can at least give some insight on why you see black, where that is coming from, and whether you can change to a less annoying fill-in color.
It turns out there are multiple different sources of the black and the bad resize behavior from different Windows versions that combine together. Please see this Q&A which explains what is going on and provides advice for what to do (again, not specific to making WPF faster but just seeing what you can do given the speed you have):
How to smooth ugly jitter/flicker/jumping when resizing windows, especially dragging left/top border (Win 7-10; bg, bitblt and DWM)?

Winforms semi-transparent PNG over semi-transparent PNG

I think I must be missing something obvious, but I'm unable to find this after several hours of searching. Is there no way to use a PictureBox or other control to contain an image with partial transparent/alpha-blended pixels, and place that over another image and have the blending be based on the image under it?
For example, this produces the results I want:
Place a panel on a form.
Add an OnPaint handler.
In the OnPaint handler draw 1 PNG, then draw another PNG over it, using Graphics.DrawImage for both.
This does not:
Place a PictureBox on a form and set it to a PNG.
Place another PictureBox on the form and set it to a PNG.
Place the 2nd picture box over the first.
...even if the 2nd picture box is just empty and has a background color of Transparent, it still covers the picture below it.
I've read this stems from all winform controls being windows, so by nature they aren't transparent.
...but even the 15 year old platform I'm migrating from, Borland's VCL, had several windowless controls, so it's hard to imaging winforms doesn't at least have some easy solution?
My first example above is one answer, true, but that adds a lot of work when you can only use one big panel and draw all of your "controls" inside of it. Much nicer if you can have separate controls with separate mouse events/etc. Even if not an image control, and a control I have to draw myself, that would be fine, as long as I can just put one image in each control. In VCL they called this a "paint box", just a rectangle area you could place on a form and draw whatever you want on it. Has it's own mouse events, Bounds, etc. If you don't draw anything in it, it is like it's not even there (100% transparent) other than the fact it still gets mouse events, so can be used as a "hot spot" or "target" as well.
The PictureBox control supports transparency well, just set its BackColor property to Transparent. Which will make the pixels of its Parent visible as the background.
The rub is that the designer won't let you make the 2nd picture box a child of the 1st one. All you need is a wee bit of code in the constructor to re-parent it. And give it a new Location since that is relative from the parent. Like this:
public Form1() {
InitializeComponent();
pictureBox1.Controls.Add(pictureBox2);
pictureBox2.Location = new Point(0, 0);
pictureBox2.BackColor = Color.Transparent;
}
Don't hesitate to use OnPaint() btw.
Sorry, I just found this... once I decided to Google for "winforms transparent panel" instead of the searches I was doing before, the TransPictureBox example show seems to do exactly what I need:
Transparency Problem by Overlapped PictureBox's at C#
Looks like there are 2 parts to it:
Set WS_EX_TRANSPARENT for the window style
Override the "draw background" method (or optionally could probably make the control style Opaque).

Remove all extra space around a button with an image?

Alright, try as I might, I cannot for the life of me get rid of this tiny little border around my buttons.
Edit: I should mention, in case I didn't make it clear, these are buttons with an image on them, set to flat with the button sized to the image.
Images below:
Number one, I can't for the life of me get these borders to GO AWAY. I've checked everything I can think of. They're:
flat
border 0
no margins
no padding
manually sized to the size of the image (75px)
in a table layout where the columns are all:
manually sized to the width of the image (75px)
borderless
Nothing seems to really "work" to get rid of these. If I size the columns down to be 74px instead of 75px, most of them go away, but a few remain. I've triple and quadruple checked the images, and they don't have anything that I can pick up on that should be causing this... no transparency around the borders, definitely no border that looks like that.
Which leads me to the second problem:
Settings button when dialog is small...
Settings button when dialog is stretched out.
Settings button is also in the same table layout panel.
I've checked all the settings on the table layout panel as well.. I can't find any padding or margin or anything settings that suggest this should be happening.
Does anyone have any experience with this? What am I missing..?
Simple solution: using directly a PictureBox as if it was a button. You can change your image on mouse over or mouse click.
Have you tried a Toolbar/strip/whatever it's called these days? Probably not going to help as I believe it pads on your behalf, but worth a shot.
In the end you can toss the buttons in the trash and write your own control. A single control that manages N buttons will work well here.
I don't understand your second problem. What's the problem? It'll be fixed if you roll your own control anyhow.
While not a fix for the spacing issue, as a workaround you can make that gray gradient currently "behind" the "tabs" and control panel image into a BackgroundImage for the TableLayoutPanel using BackgroundImageLayout of Stretch. While not fixing the spacing issue, it would make it unnoticeable.
Writing a winforms control has its challenges (experience speaking here). I would agree that that is whats needed however. Depending on your project you may consider using XAML and WPF. It provides that fine detail you seem to be looking for in you application.
There are ways to host XAML controls in a winform app, but if you went this route it would be best to create a native WPF application. The reverse is also true (winform controls in a WPF app).
Did you check if the image has transparent pixels around the graphic pixels you want?
May be a simple crop solution.

Shell Integration Library WindowChrome with Drop Shadow

Ive been googling this alot but can't find any working solution. Im using Shell Integration Library to cerate custom Window Chrome and I also need drop shadows for this window. Some say setting GlassFrameThickness to -1 do the trick but its not working for me. And Jeremiah Morrill suggested using DwmExtendFrameIntoClientArea. Ive tried that and it works, sort of. The shadows looks ok but when the window is shown it is first shown as a glass-frame and then a second later the real content is superimposed. This causes to much flickering for me. Is there any way to get rid of this flickering or is there any better way using only Shell Integration Library?
I had a similar problem where it wouldn't display any shadow when using a custom chrome. It worked fine when using the glass.
I got a shadow by setting GlassFrameThickness="0,0,0,1". The glass didn't show and I got the shadow.
Be warned, the shadow is a simple RECT to Windows, so if you have a funky chrome with transparencies it may look funny.
Also if you support the maximized state be aware the you'll need to set a margin on your top-level panel element of "8,8,8,8" when in maximized mode. All other modes should be "0,0,0,0".
To alimbada, the WindowStyle defaults to None on custom chrome.
The Shell Integration Library uses DwmExtendFrameIntoClientArea, plus handling of several Window messages to get the effects. If you're using the full window rect (i.e. no rounded corners) then setting it to (0,0,0,1) as suggested will give you the drop shadows as you want. If you want to simulate the rounded corners of Aero, then setting it to (8,8,8,8) will extend the glass frame enough that the corners also stay rounded, and then you're responsible for not drawing over the corners of the rectangle. The shape of the drop shadow doesn't change regardless of the glass frame thickness.
The flashing you're seeing when setting the thickness to -1 still exists even when not fully extending the glass frame. What's happening is the window is getting shown while the content is still compositing. What you can do is simplify the default UI so it displays quicker (or you can stage it, bringing in a simnple background first and then replacing it with something usable), or you can create and show the window off-screen, and then move it to the desired start location once the content has been rendered. The easy way to detect when it's probably ready is to invoke a DispatchTimer with Priority=Loaded. That should only get invoked once the basic first layout has been completed.

WPF Tiled Background Misalignment

We have quite a complex WPF application (that I cannot show here) that somehow has the tiled background misaligned of one of its user controls. I was unable to reproduce this problem in a "clean" WPF project but will try to illustrate the problem in this picture:
(source: kintespace.com)
The gray area represents the user control and the black and red checks represents the tiled background inside the user control. The white background represents the window hosting the control. The VisualBrush is used here but the same problem comes with the DrawingBrush. I would prefer not to use the ImageBrush.
Can you open a "clean" WPF project and build something that will cause a tiled background to be misaligned like this?
You can do this if the layout root of the user control has a -10 left margin and a -10 top margin. the tiled backgoround in on the layout root of the usercontrol so, it looks like a alignment problem not a brush problem.
This problem is related to the tiled background cramming itself into the calculated height of the UserControl instance in the hosting Window. I am still unable to replicate this problem in a new project but it is "solved" (by stacking panels in the user control horizontally instead of vertically).
Here are two diagnostic techniques that can be useful in situations like yours:
Take your complex project, make a copy, and start tearing out large sections of code and XAML until the problem disappears. Then put the last section back and tear things out more gently. Repeat until you find the change that makes the difference.
Run the application, break where a local variable references your UserControl, then explore the visual tree just above and below your UserControl in the Locals or Watch window. Look at each Visual's internal properties VisualOffset, VisualTransform, and VisualContentBounds. These properties will usually clue you in to what property is being set incorrectly, and from there you can figure out why.

Resources