Does anyone know why the DropShadowBitmapEffect and the EmbossBitmapEffect won't work on a TextBlock (not textBOX) in WPF? OuterGlow, Blur and Bevel seem to work fine.
The transparent background brush is apparently not the answer because you can get a dropshadow with a null background brush. The default softness on a dropshadow is 50% and if you have a small font, the softness dissipates the shadow too much. There seems to be a steep drop off around softness of 39% (at which point the shadow more or less disappears). Try setting it to 0 and slowly moving you're way up until you find a number that still shows the shadow.
Yet another note: the softness is definitely a factor, but be aware in Xaml the valid values are really only 0 to 1, but in Blend it shows it as a percentage up to 100. So if you set the value to 100 in Xaml, it will be completely dissipated.
The background brush = transparent solution still may work for the embossing effect
Bitmap effects work by looking at the post-rendered pixels and running standard image manipulation on them. It should only be dependent on the color of the pixels. I wonder if their algorithms don't work well on white. Try changing the color to see if that has an effect -- if it does, you might want to try putting a black panel underneath with drop shadow set on it.
Edit: The questioner found the answer
"Thanks for pointing me in the correct general direction. It wasn't the color of the text or the DropShadow that mattered, what is needed is to make the Background Brush on the TextBlock the Transparent Brush (Alpha = 0) instead of null."
Important Sidenote: you shouldn't really be using BitmapEffects any more. Use the Effect property based on ShaderModel effects introduced in .net 3.5 SP1, it uses hardware rendering and has far better performance.
More Information
Related
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)?
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).
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>
The System.Drawing.Graphics class has a property CompositionMode with two options: SourceOver (which, based on the alpha component, blends whatever is drawn with the background already existing) or SourceCopy which simply overwrites the background with whatever is being drawn.
Does something similar exist in WPF?
In WPF when i draw a PolyLine for example on top of another the new PolyLine always alphablends with the background. I think that is independent of the container being used. I am using a Canvas but could not find a blend mode property anywhere. What I want to do is what the SourceCopy compositionmode mentioned above does. I.e. the new PolyLine should simply overwrite whatever is already on the Canvas.
Is there a simple way to do that, short of using pixel shaders (which - as far as I understand - wouldn't work anyways because I don't have access to the Canvas backbuffer).
I am not stuck with a Canvas and would be happy to use any container that supports overwrite mode.
I currently have a solution based on a WriteableBitmap for which I obtain a System.Drawing.Graphics context and then manipulate the CompositionMode. It works but since my window is fullscreen that solution has serious performance impacts.
Clarification and example:
The WPF window is fully transparent and so is the Canvas (back ground color(0,0,0,0)). Now I draw a PolyLine with a Color.FromArgb(128,128,0,0). I now have a semi-transparent red polyline. Next I draw the same PolyLine with Color.FromArgb(0,0,0,0). The result is the same as before because of the alpha blending taking place. What I want, however, is that the red polyline is erased with the second polyline (which is exactly what the SourceCopy mode in the Graphics class does.
I think all you need to do is make sure that the brushes used to fill/stroke the PolyLine have fully opaque alpha values (i.e. 255). Then the background shouldn't be blended into it.
You could apply a Clipping Mask, this way you can provide the path to clip over the elements that are below it, but it might be tough to maintain after a lot elements are required to be clipped...
I have a custom canvas that I can drop controls on, move, and resize. I need to be able to at least start with a pre-determined size but then allow re-sizing.
My problem is that I have a user control that doesn't appear to resize. I set Height and Width on the user control (works on drop). But then as the control is resized on the canvas the visual size stays the same (the sizing handles are changing). I can see the Height property changing (usercontrol.height) as the control is resized. But again, the appearance of the control stays the same size.
I had a thought that the inner container on the user control should be bound to the usercontrol.height but that didn't seem to help. (or maybe I didn't have the binding right).
On the same canvas, if the dropped control is for example, an Image control, I can set an explicit height on the drop and everything resizes as it should. So it seems to be UserControl thing.
So is there something special I need to do with UserControls to get the visuals to resize? Should I be using explicit height and width to get it all started?
Thanks for any help.
The WPF layout system can be confusing, as you've discovered. There is no substitute for a solid understanding of the layout and measurement system. If you plan on doing much WPF development, it's worth taking 20 minutes to read this article on the layout system and then experimenting for a while in an iterative environment such as Kaxaml until you feel comfortable.
The system is very logical. It won't take long for the penny to drop. Sorry for the indirect answer, but I don't believe there's enough information in your question to really explain what's going on.
You might also look at the HorizontalAlignment and VerticalAlignment properties.
Not a WPF expert but I believe you need to enable auto-sizing in order to achieve the scenario you are looking for. This is done by setting the Height/Width of a control to Double.NaN which essentially says, "I have no specific size". Once you do that, the control should resize to occupy available space based on the need of the control.