Window transparency in WPF vs Winforms - wpf

Why is it that I have to set the WindowStyle property to None on a WPF form to get transparency, but in Winforms I can do it on any form, and retain borders, standard buttons, etc? Clearly the API supports this, so I'm not clear on what's special about WPF that would make this an issue.
I'm guessing that WPF is jumping through some DirectX or OpenGL hoops, while Winforms is just setting the alpha for the window via the API, but I could be way off base.

Agreed, this is heavy handed:
private void VerifyConsistencyWithAllowsTransparency(WindowStyle style)
{
if (AllowsTransparency && style != WindowStyle.None)
{
throw new InvalidOperationException(SR.Get(SRID.MustUseWindowStyleNone));
}
}
WPF uses the exact same mechanism to implement this as Windows Forms, layered windows. There is no obvious reason it wouldn't work the same way in WPF. The code snippet, lifted from Window.cs, simply rules it out. There is however one hint from the UsesPerPixelOpacity property:
When you enable per-pixel opacity, the system no longer draws the non-client area. This is because the intended purpose of UsesPerPixelOpacity is to show non-rectangular top-level UI that works in interoperation scenarios, and showing the rectangular non-client area defeats that purpose.
"interoperation scenarios", I guess.

Related

Double-buffering *framework* in C and Windows GDI

Background: My client has a very extensive proprietary forms library which is effectively implemented in C (actually, it's a proprietary object-oriented language that basically wraps Windows controls and interacts with them with SendMessage(), SetStyle(), etc.)
Problem I want to solve: Whenever I drag/resize a top-level window (or drag a splitter) in an app implemented in the above framework, there is massive flicker. The top-level window is repainted, and any controls it contains repaint themselves.
Question 1: Is there a way to surgically introduce double-buffering into the forms library. In particular, I want to know if I can implement double-buffering using standard Windows GDI functions.
For example, if I could cause the top-level windows to be double-buffered such that all child windows of the top-level window are automatically drawn double-buffered as well. An even better alternative would be to be able to introduce double-buffering on any arbitrary window and have all its children inherit this.
The best solution would somehow cause the BeginPaint() function for child controls to return a handle to the DC of the offscreen back buffer so that I don't have to write special code for each individual control class.
Question 2: Is there a way (such as a set of flags) to cause generic Windows controls (EDIT, BUTTON, and so on) to draw themselves double-buffered? This would be a worse solution than a more generic approach that would just seamlessly give them the back buffer to draw on, but it might also be acceptable.
All help greatly appreciated. Please let me know if I can clarify anything for you.
Look into WS_EX_COMPOSITED, which is an extended window style that turns on double-buffering for the window. It may be enough to set this style on the parent of the controls.
You actually might be able to wrap all your window drawing code with C that executes C#, and that way there is already a double-buffered implementation for you.
How to eliminate flicker in Windows.Forms custom control when scrolling?

WPF as IHTMLPainter control

I need to host WPF control inside IE, therefore I'm trying to implement IHTMLPainter and IElementBehavior interfaces. I'd like to build my custom behavior and use it inside IE, but the problem is how to draw WPF control by just having IntPtr hdc parameter.
Probably I can get Drawing.Graphics by the following code:
Graphics.FromHdc(hdc);
But I'm not sure that this is the best way. Please advise
I'm assuming you want to be able to make use of the advanced features of WPF within a MSHTML context. In that case, Graphics.FromHdc(hdc); will not do the trick for you. The resulting Graphics object will have no way to receive WPF content because WPF uses a retained-mode system and its MILCore rendering engine uses Direct3D not GDI+.
I'll give you one sure way to use WPF features inside a IHTMLPainter, plus pointers to another way that would likely be faster if you can get it to work.
Bitmap copying solution
An easy solution is to simply copy the background provided by MSHTML into an ImageBrush, use RenderTargetBitmap to let WPF render to a bitmap, then copy it back to the device.
To do this, construct your WPF content in any Visual subclass with a Background property (eg Grid or Border), then in your IHTMLPainter.Draw() method, just do the following:
Create a System.Drawing.Bitmap corresponding to rcUpdate
BitBlt from the given DC into the System.Drawing.Bitmap
Construct an ImageSoure from the System.Drawing.Bitmap (see recent SO answers for details)
Construct an ImageBrush from the BitmapSource using a viewport/viewbox that will lay it behind the portion of the visual corresponding to rcUpdate
Set your root visual's background to the ImageBrush
Set the RenderTransform on the root visual so that the rcUpdate portion starts at (0,0)
Render the root visual to a RenderTargetBitmap of rcUpdate size
BitBlt the RenderTargetBitmap to the rcUpdate area of the DC
This should work well, be simple to implement, and work for any WPF content including advanced features such as 3D, BitmapEffects, etc. The only disadvantage is that those two bitmap copies might slow things down somewhat.
Note that if you know your WPF Visual is totally opaque you can completely skip steps 1-5 and simply render your Visual to a RenderTargetBitmap and BitBlt it to the device.
Direct3D possibility (partial solution)
Obviously it would be faster to avoid all this bitmap copying during render. This is most likely possible, but I can only give you some ideas to point the way -- it will take a lot of trial and error and probably some undocumented calls to make it work.
Since WPF renders using Direct3D, obviously you would prefer to get a Direct3D surface from MSHTML and paint on it. Doing this requires two things: Getting the surface from MSHTML, and getting MILCore to draw on it.
IHTMLPainter has a flag HTMLPAINTER_3DSURFACE to request a Direct3D surface in its GetPainterInfo call, but I couldn't find any examples of how to use HTMLPAINTER_3DSURFACE. I suspect it could be figured out with a little trial and error.
I did not find any way to get WPF's native component "MILCore" to accept a Direct3D surface to paint on instead of a hWnd. There is no documentation on MILCore, and the only public API for setting up rendering tree, HwndSource, doesn't seem to be able to do the job.
Rendering behaviors through IHTMLPainter and IElementBehavior are meant to alter or supplement the display of existing elements in a page, not to render content for user controls. If you're looking to use WPF controls in a page, this is not the path to take. Instead, consider creating a blank windowed UserControl with ActiveX support, then do either of the following.
Add your WPF control at runtime as a member of the UserControl.
Perform WPF activities using the window handle (HWND) of the control.
Alternatively, you could just use Silverlight to make user controls. Silverlight has a pretty good subset of WPF display features, and even manually constructed Silverlight content is easier to manage than trying to get .NET Windows + ActiveX Hosting + WPF working.
If I've mistaken your question and you're truly intent on using WPF to perform drawing activities in an element behavior, Graphics.FromHdc() is an acceptable way to get a usable Graphics object. You should attach to the HDC specified in the Draw() callback.
Draw Method (IHTMLPainter) # MSDN
You could also attach to the window handle (HWND) of the document view (retrieved via IOleWindow), if your WPF activities involve the entire viewport. The window object can be cast to IOleWindow for this purpose (see IHTMLWindow2).
IOleWindow Interface # MSDN
IHTMLWindow2 Interface # MSDN

WinForms floating windows (like Delphi7 IDE)

I want to setup my WinForm to look like the Delphi7 IDE. Basically that means the window has no background (the desktop shows through), and child windows float around.
Here's a sample image:
I can handle the floating windows, but how would I go for the main window (the menu bar and the toolbar)? What are the WinForm properties required to get this layout? I can't seem to be able to get rid of the window's client area.
Thank you
Why can't you get rid of the client area? Just resize the main form so that it's as thin as you can make it.
You may be implementing the floating windows as UserControls in the main form's Controls collection. If so, there are two ways you can deal with this:
Implement the floating windows as actual windows. Show them using "frmToolWindows.Show(this);" (this will keep them always on top of your main form).
If you need to keep the floaters as UserControls, you can make the client area of your main form transparent by setting the form's TransparencyKey property to some arbitrary color (Color.Red, for example) and then setting the form's BackColor property to the same color. This will make your form transparent and able to be clicked through.
Please don't make a UI like this. It is very non-standard, and doesn't gain anything in the realm of usability. You could simplify things by keeping it all in one window like Visual Studio.

performance in C# Application

i use some pictures in my 'MainForm' And My Windows Application was writing by c sharp.
i use this form to start other forms in my project.
And I use some label and panel with Transparent Color.
but when the program started i see many blink in transparent label and panel.
And it is very bad.
How I Can Fix this problem?
Enabling DoubleBuffered as stax suggested above is helpful but it may not be sufficient.
In your form, add the following method override:
protected override void OnPaintBackground(PaintEventArgs e) {}
And, in the OnPaint method, paint the background yourself instead. If you don't do this, drawing the background and painting are separate events, and background painting has higher priority, meaning that it will happen earlier.
Furthermore, if you add child controls (like labels), they receive their own paint background/paint events. You may be able to disable the Label's background. If I do stuff like this, I tend to not use controls but paint the text and the images in one OnPaint.
did you test it on multiple machines.
did you use an updated machine with all the .net service packs needed.
etc

Using SetWindowTheme() on controls in WindowsFormsHost in WPF?

I have an application I'm developing which closely mirrors Windows 7's Device Stage. In Device Stage, beneath the main banner there is a ListView containing actions embodied as ListViewItems.
In my WPF application, I used WindowsFormsHost to host a WinForms ListView so that I could use SetWindowTheme() on it and apply Windows Vista/7 styling to it.
This, however, does not work and doesn't achieve the same effect it does when used in Windows Forms.
How can I achieve the Windows 7 look on a ListView in WPF? I'm not looking to create a custom style then apply it because frankly that's too much of a pain in the ass to continue using WPF for this app.
Thanks! :)
Just add the following lines:
[DllImport("uxtheme.dll", CharSet = CharSet.Unicode)]
public static extern int SetWindowTheme(IntPtr hWnd, String pszSubAppName, String pszSubIdList);
.ctor
{
System.Windows.Forms.Integration.WindowsFormsHost.EnableWindowsFormsInterop();
System.Windows.Forms.Application.EnableVisualStyles();
SetWindowTheme(MyControl.Handle, "Explorer", null);
}
Apparently after digging around, the only answer does indeed appear to be creating a custom-designed control in WPF.

Resources