I wrote a WinForm control that can render and edit 3D objects using managed directX 1.1 a while ago. Now I want to port the control to a pure WPF control. I have almost achieved this except that the WPF control's default rendering (which will render a white background) is fighting with my DirectX rendering (which will render a black background). So when the control appears initially at runtime, it is rendered as white background. But when I resize it, it starts to flicker between black and white until I stopped resizing, then it will become white again.
Is there any way to stop Wpf control's rendering altogether? In my case, I am providing a custom rendering and I don't want the default rendering. Having a Wpf 3D control is useful because I can put it anywhere in the Wpf visual tree without having to use ElementHost.
Here is what I did:
1. Derive a Wpf3DControl from System.Windows.Controls.Control.
2. Create managed DirectX device by providing Wpf3DControl's handle (Hwnd).
2. Override OnRender() method of System.Windows.Controls.Control and call my DirectX rendering method.
The OnRender() don't have a base implementation and I am not calling the base implementation anyway.
Controls in WPF don't have HWND handles unless you intentionally create a child window and host it using HwndHost. So I don't quite understand what your technique is. However, if you are using the HWND for the main window (from the Window class or the HwndSource class) then you will have a problem, since WPF and DX will both try to render to the same HWND.
I suspect the easiest thing for you is to derive from HwndHost, and use that to host a child HWND that you create, which you can tell DX to render to.
Thanks for the reply, Dwayne. I did a test using Spy++ and you are right - WPF control does not have an Hwnd. But I somehow get the Wpf control's handle with the following code:
mHandle = wpfHandle.Handle;
Where "this" is of type System.Windows.Controls.Control. MDX actually created a Microsoft.DirectX.Direct3D.Device using this handle and rendered my 3D graphics. Then Wpf rendering renders over it. I have to say I don't know why this code works since the control doesn't have a real Hwnd handle.
WinForm control on the other hand does have a proper Hwnd, this has been proved by Spy++. As I already have a WinForm control that can render 3D graphics using MDX, I can just host it into WPF using ElementHost (rather than HwndHost as I don't have a Win32 window). The drawback of that is when resizing, it flickers. I suspect that the hosting WPF did its render first before ElementHost got the chance to render later.
I know that WPF uses "retained mode" rendering rather than the traditional "immediate mode" rendering. In retained mode, we just need to provide drawing data and the system will decide when to render it. But can't we remove all the drawing data, including the drawing of white background so that the system won't render anything?
I am having the same problem using an ElementHost that hosts Wpf content that flickers when resizing. Is there a way to disable the ElementHost from rendering during a resize? In the parent WinForm I can set a Control style to NOT render during resizing, but this does not probagate down the the ElementHost, and I have not been able to find an equivalent.
Any help is greatly appreciated.
PresenstationSource.FromVisual walks the visual tree to the root and returns the HWND of the window that contains the entire WPF visual tree.
To host any kind of HWND content, please use HwndHost.
Flickering occurs when two components try to render to the same pixels. WPF renders normally using DirectX, and HWNDs normally render using GDI. If WPF and the HWND both try to render to the same pixels, flickering can occur. The easiest way to elliminate the flicker is to get WPF and GDI to avoid each other. One way is to set WS_CLIPCHILDREN and WS_CLIPSIBLINGS on all windows in your app.
Thanks for your help. I added the below code to the WinForm that hosts the WPF controls and it works great now.
For those who want to know how to set WS_CLIPCHILDREN and WS_CLIPSIBLINGS, on a WinForm, here is how I did it:
private const int WS_CLIPCHILDREN = 0x02000000;
private const int WS_CLIPSIBLINGS = 0x04000000;
protected override CreateParams CreateParams
CreateParams cp = base.CreateParams;
cp.Style |= WS_CLIPCHILDREN;
cp.Style |= WS_CLIPSIBLINGS;