Panel is flickering when switching from one winform to another - c#

I render my image on the panel.
using Microsoft.DirectX.Direct3D;
Device device;
this.device = new Device(0, DeviceType.Hardware, this.panel2,
CreateFlags.HardwareVertexProcessing, presentationParameters);
As a result, the panel is flickering when I try to switch the winform from one to another.
I know it is hard to describe the scenario. Hence I hereby upload a video clip (.swf) to my google drive, you guys may download it and open it with window media player to watch the video.
Below is the shared link:
https://drive.google.com/file/d/0B6wTfkJvzke_aVJwanVkaU1iSVU/edit?usp=sharing
Inside the video, I am running my application at debug mode, then I click on the 'chrome browser' tab in task bar to access the 'chrome browser', when the minimized 'chrome browser' pop out, the panel will be flickered. Then when I minimize the 'chrome browser' again, the panel flickered again.
The problem occur when there is some other winform being placed above the panel on screen.
Any comment on the above matter? Help is needed.

I ran into the same flicker issues when using DirectX with Panel. It turned out that the OS draw events were colliding my own. To fix this, you need to disable OS drawing on your Panel by creating a custom panel. Something as simple as this should suffice.
class Direct3DPanel : Panel
{
public Direct3DPanel()
{
this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.Opaque, true);
}
}
The SetStyle method call tells the OS that only you should draw in Direct3DPanel. Note that once you do this, you will be responsible for all drawing. You may need to handle the Paint event and call your draw logic depending on your current architecture.
You can get more information about the different ControlStyles here
http://msdn.microsoft.com/en-us/library/system.windows.forms.controlstyles(v=vs.110).aspx

Related

CustomControl "disappears" when dragged in panel/form with backgroundimage

I am writting a pin-up board in C# where I need to be able to drag around pieces of paper (notes) on the board. I have made the notes as customcontrols since I needed to be able to write on them as well. The background of the customcontrol (a note) is an image of a piece of paper. When I don't use a backgroundimage, for the board itself, everything works as intended. I am able to drag around the notes (customcontrols with a backgroundimage) just fine - no flickering. When I use a backgroundimage on the board (which I want to do, since a plain color background doesn't cut it for me), I am not able to drag the notes around smoothly anymore. When I start dragging the note disappears and is first redrawn when I stop moving the mouse.
I am using the following code on the panel (in its constructor) where I drag around notes, but it has only sorted out my initial screen flickering issue.
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer | ControlStyles.ResizeRedraw | ControlStyles.UserPaint, true);
The image file used for the background is imported into the projects resources. I have tried to load the image file into a bitmap object and used this object as the backgroundimage of the panel, but that didn't change anything.
Below a link to an image of how a note should look when being dragged:
http://i.stack.imgur.com/9LnKj.jpg
Below an image of how the note actually looks when I start dragging it around:
http://i.stack.imgur.com/x0Lf1.png
Please ask if you need more details to be able to help me solve my issue. Any help and suggestions on what the problem might be is very appreciated! Thanks in advance.
Edit: The size of the note on the second image is dependent on how far I drag it from its initial point. I am able to get the note to disappear completely when I drag it further than the size of it. It gets redrawn when I stop moving the mouse.
Edit: I use the following code for moving around the notes:
private void NoteControl_MouseMove(object sender, MouseEventArgs e)
{
if (_dragme)
{
System.Drawing.Point newLocation = e.Location - mouseOffset;
this.Left += newLocation.X;
this.Top += newLocation.Y;
}
}
Since I have not been able to solve my issue with the custom control disappearing when getting dragged on an imaged background I have decided to create an asp.net version of my project rather than a windows form application. This also prevent the issue with cross platform compatibility. The dragging is now accomplished using jQuery

Drawing to screen directly on top of all window [duplicate]

I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.

rectangle drawn on desktop is not persistent in c# [duplicate]

I want to draw directly on the desktop in C#. From searching a bit, I ended up using a Graphics object from the Desktop HDC (null). Then, I painted normally using this Graphics object.
The problem is that my shapes get lost when any part of the screen is redrawn. I tried a While loop, but it actually ends up drawing as fast as the application can, which is not the update rate of the desktop.
Normally, I would need to put my drawing code in a "OnPaint" event, but such thing does not exist for the desktop.
How would I do it?
Example code: https://stackoverflow.com/questions/1536141/how-to-draw-directly-on-the-windows-desktop-c
I posted two solutions for a similar requirement here
Basically you have two options.
1- Get a graphics object for the desktop and start drawing to it. The problem is if you need to start clearing what you have previously drawn etc.
Point pt = Cursor.Position; // Get the mouse cursor in screen coordinates
using (Graphics g = Graphics.FromHwnd(IntPtr.Zero))
{
g.DrawEllipse(Pens.Black, pt.X - 10, pt.Y - 10, 20, 20);
}
2- The second option that I provide in the link above is to create a transparent top-most window and do all your drawing in that window. This basically provides a transparent overlay for the desktop which you can draw on. One possible downside to this, as I mention in the original answer, is that other windows which are also top-most and are created after your app starts will obscure your top most window. This can be solved if it is a problem though.
For option 2, making the form transparent is as simple as using a transparency key, this allows mouse clicks etc. to fall through to the underlying desktop.
BackColor = Color.LightGreen;
TransparencyKey = Color.LightGreen;
When you draw to HDC(NULL) you draw to the screen, in an unmanaged way. As you've discovered, as soon as windows refreshes that part of the screen, your changes are overwritten.
There are a couple of options, depending upon what you want to achieve:
create a borderless, possibly
non-rectangular window. (Use
SetWindowRgn to make a window
non-rectangular.) You can make this a child of the desktop window.
subclass the desktop window. This is not straightforward, and involves
injecting a DLL into the
Explorer.exe process.
To get an OnPaint for the desktop you would need to subclass the desktop window and use your drawing logic when it receives a WM_PAINT/WM_ERASEBKGND message.
As the thread you linked to says, you can only intercept messages sent to a window of an external process using a hook (SetWindowsHookEx from a DLL).
As mentioned a transparent window is another way to do it, or (depending on the update frequency) copying, drawing and setting a temporary wallpaper (as bginfo does).
This is difficult to do correctly.
It will be far easier, and more reliable, to make your own borderless form instead.

How to make label & other controls transparent with background image on windows mobile?

I am developing the smart device application in C#. I am new to the windows mobile. I have added the background image to the form in my application by using the following code. I want to make label & other controls on this form transparent so that my windows form will be displayed properly.
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
Bitmap CreateCustomerImage = new Bitmap(#"/Storage Card/background.png");
e.Graphics.DrawImage(CreateCustomerImage, 0, 0);
}
how to do this ? How to solve this problem? Can you provide me any code or link through which I can solve the above issue?
Windows CE doesn't inherently support transparent controls, which tends to be a huge pain. You have to use something like ColorKey transparency, so in your OnPaint, you need to fill the background with a color (magenta is a popular one) and use SetColorKey to make that color transparent.
There are several tutorials online for colorkey transparency. Here is one that I just found with a search engine that looks reasonable but feel free to search for others as well.
The place this falls down is when you have controls in a container control, which is then on the Form. To get that to work right you have to cascade calls to clipping regions from the Form all the way down. I don't have a ready sample of this that isn't inside a shipping project, so I can't easily post it. If you run into this, though, update the question and I'll see if I can extract something.

Resizing window causes black strips

I have a form, which sets these styles in constructor:
this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
this.SetStyle(ControlStyles.UserPaint, true);
this.SetStyle(ControlStyles.ResizeRedraw, true);
this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
And I draw some rectangles in Paint event. There are no controls on the form. Hovewer, when I resize the form, there are black strips at right and bottom of the form. Is there any way to get rid of them? I've tried everything, listening for WM_ERASEBKGND in WndProc, manually drawing the form on WM_PAINT, implementing custom double buffer, etc. Is there anything else I could try?
I've found this:
https://connect.microsoft.com/VisualStudio/feedback/details/522441/custom-resizing-of-system-windows-window-flickers
and it looks like it is a bug in DWM, but I just hope I can do some workaround.
Please note that I must use double buffering, since I want to draw pretty intense graphic presentation in the Paint event. I develop in C# .NET 2.0, Win7.
Status Update 1
I've managed to get rid of most of the black stripes by implementing the resize functionality by myself. Hovewer there are still some minor glitches. Is there any way to do resize and paint operation at once? Here is a pseudo-code of what I need to do:
IntPtr hDC;
var size = new Size(250, 200);
IntPtr handle = API.PaintAndResizeBegin(this.Handle /* Form.Handle */,
size.Width, size.Height, out hDC);
using (var g = Graphics.FromHdc(hDC)) {
this.backBuffer.Render(g, size);
}
API.PaintAndResizeCommit(handle);
Is there any way to implement the above code?
The second solution could be to back-buffer whole form, including non-client area. But how to do that? I don't want to paint the non-client area by myself, as I want to keep the nice aero effect on Vista/7. Any help will be deeply appreciated.
Status Update 2
It looks like this problem is unsolvable, since it is omnipresent on Windows, in every application. We can just hope that MS will take some inspiration in Mac OS X and will provide appropriate APIs in new Windows.
I've found the function which can paint and resize window at the same time - UpdateLayeredWindow.
So now it should be possible to create resizable windows, which do not have any strips while being resized. However, you need to paint the window content yourself, so it is a little inconvenient. But I think that using WPF and UpdateLayeredWindow, there shouldn't be any problem.
Update
Found problems. :-) When using UpdateLayeredWindow, you must paint the window's border yourself. So, if you want standard window painted using UpdateLayeredWindow with nice glass effect in win7, you are screwed.
On Microsft Connect is even a thread about this problem, where Microsoft says it is a bug by design, and if it ever gets fixed, then probably in Win8 or some newer system. So there isn't much we could do about this.
I found that it is best not to do any custom rendering directly on the Form surface. Instead, put a docked PictureBox on the form, create Bitmap object that will be displayed in the PictureBox, draw everything onto that using the System.Drawing.Graphics.FromImage(Image) method.
I used that method with a game loop to make a simple shooter game (Crimsonland-style) and got pretty good performance (with anti-aliased lines), above 100 FPS.

Categories