Background: I have a little video playing app with a UI inspired by the venerable Sasami2k, just updated to use VMR9 (i.e. Direct3D9 with DirectShow) and be less unstable. Currently, it's a C++ app using raw Win32, through necessity: none of the various toolkits are worth a damn. WPF, in particular, was not possible, due to its airspace restrictions.
OK, so, now that D3DImage exists it might be viable to mix and match D3D/VMR9/DirectShow and WPF. Given past frustrations with Win32's inextensibility, this seems like a good thing.
But y'know, I'm falling at the first hurdle here.
With Win32 I have created (very easily) a borderless window that's resizable, resizes proportionately, snaps to the screen edges, and takes up the whole screen (including taskbar area) when maximized. It's a video app, so these are all pretty desirable properties.
OK, so, how to do the same with WPF?
In Win32, I use:
WM_GETMINMAXINFO to control the maximize behaviour
WM_NCHITTEST to control the resize borders
WM_MOVING to control the snap-to-screen-edges
WM_SIZING to control the resize aspect ratio
However, looking at WPF it seems that the various events arrive too late, unless I'm misunderstanding the documentation?
For example, I don't know when I'm mid-move, as LocationChanged says it fires only once the window has moved (which is too late).
Similarly, it appears that StateChanged only fires once the window has been restored/maximized (when I need the information prior to the maximize, to tell the system the correct maximize size).
And I seem to be completely overlooking where the system tells me about resizes. Likewise the hit testing.
So, uh, am I missing something here, or do I have no choice but to drop back to hooking the wndproc of this thing anyway? Can I do what I want without hooking the WndProc?
If I have to use the WndProc I might as well stick with my existing codebase; I want to have simpler, cleaner UI code, and moving away from the WndProc is fundamental to this.
If I do have to hook the WndProc, I have to wonder--why? Win32 has got the sizing/sized, moving/moved, poschanging/poschanged window messages, and they're all useful. Why wouldn't WPF replicate the same set of events? It seems like an unnecessary gap in functionality.
Plus, it means that WPF is tied to a specific USER32-dependent implementation. This means that MS can't (in Windows 7 or 8, say) invert the display layer to make WPF "native" and emulate HWNDs and WndProcs for legacy apps--even though this is precisely what MS should be doing.
OK, to answer my own question, I was missing Adorners (never came back in any of the searches I did, so it doesn't seem that they're as widely known as they perhaps should be).
They seem rather more complex than the WndProc overrides, unfortunately, but I think it should be possible to manhandle them into doing what I want.
And I seem to be completely overlooking where the system tells me about resizes. Likewise the hit testing.
For the resizing you're indeed missing the SizeChanged event.
AFAIK there is sadly no OnSizeChanging, OnLocationChanging and OnStateChanging event on a Window in .NET
I saw that one, but as far as I can tell it only fires after the size has changed, whereas I need the event to fire during the resize. Unless I'm misreading the docs and it
actually fires continuously?
It does not fire continuously but you can probably use the ResizeBegin and ResizeEnd events and be able to do that.
Aren't they WinForms events?
Hmm, you're right.
In code you can set the WindowStyle property to "None" and WindowsState to "Maximized"
Im not sure what the Xaml would look like.
Can you perhaps override the ArrangeOverride and/or MeasureOverride to make up for those missing resize events? Measure is the first pass, and occurs when a layout needs to adjust for a new size, so it's kind of like a size changing event.
Related
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?
I have inherited a large MFC application which contains a CComboBox subclass that overrides OnPaint. Currently it does all its drawing by hand (with lines and rectangles), and renders a combo box that looks decidedly Windows 98-style. However, it otherwise works great and provides a lot of useful custom functionality that we rely on, and rewriting the entire control is probably not an option.
I would like to modernize it so that the OnPaint draws in Aero style where available (falling back to the old code when modern theming is unavailable). I've done this with some other custom controls we have, like buttons, and it works great for our purposes. I know there are some tiny behaviors that it won't get right, like gentle highlights on mouse-hover, but that's not a big deal for this app.
I have access to the CVisualStylesXP ckass, so I've already got the infrastructure to make calls like OpenThemeData, GetThemeColor or DrawThemeBackground pretty easily (via LoadLibrary so we don't force Vista as a min-system). Unfortunately, I don't know the proper sequence of calls to get a nice looking combo box with the theme-appropriate border and drop-down button.
Anyone know what to do here?
Honestly, I don't know why they originally tried to override OnPaint. Is there a good reason? I'm thinking that at least 99% of the time you are just going to want to override the drawing of the items in the ComboBox. For that, you can override DrawItem, MeasureItem, and CompareItem in a derived combo box to get the functionality you want. In that case, the OS will draw the non-user content specific to each OS correctly.
I think you best shot without diving in the depth of xp theming and various system metrics is take a look at this project: http://www.codeproject.com/Articles/2584/AdvComboBox-Version-2-1
Check the OnPaint of the CAdvComboBox class - there is a full implementation of the control repainting including xp theme related issues.
Not sure if it's the same situation - but when I faced this problem (in my case with subclassed CButtons), solving it only required changing the control declaration to a pointer and creating the control dynamically.
Let's assume that your subclassed control is called CComboBoxExt.
Where you had
CComboBoxExt m_cComboBoxExt;
You'll now have
CComboBoxExt* m_pcComboBoxExt;
And on the OnInitDialog of the window where the control is placed, you create it using
m_pcComboBoxExt = new CComboBoxExt();
m_pcComboBoxExt->Create(...)
Since this is now a pointer, don't forget to call DestroyWindow() and delete the pointer on termination.
This solved my particular problem - if your control is declared in the same way, consider giving it a try.
A custom control I am creating needs to draw many "items" in its client space. A call to Invalidate() would trigger a new paint cycle wherein all items would be redrawn.
Now when there are many items and a lot of navigation happens within the control, things need to be optimized; so I need to trigger a paint cycle where only one or two items are drawn. I store references to these items so that the paint method (OnPaint) knows it's a "quicky".
The difficulty is that when OnPaint is executed, it is hard to know if other Invalidate() calls have been made in the meantime. In that case it should do a "normal", complete paint.
I do make use of the clip rectangle. Of course I could check if the clip rectangle in OnPaint has become the whole of the client rectangle, a sign that Invalidate() was called, but this is not 100% safe. I thought of other similar solutions but they seem hacky.
What is the way this problem is usually, or best, solved?
The solution here would be to employ a double buffering approach with the BufferedGraphics class. This way you won't have so much tricky stuff going on in your OnPaint and you'll be able to paint whenever, whatever.
MSDN: Double Buffered Graphics (under "Manually Managing Buffered Graphics")
Here's a useful example:
Custom Drawing Controls in C# – Manual Double Buffering
Let me explain about my problem:
I have a wpf form with few controls. some of these control over-writing template. for example a textblock with an effect will be trigger on Mouse-Enter event and change color of foreground to something else.
But after running program when mouse enter on textBloc, it takes a few Milli-seconds until Mouse-enter event triggers. also all control or better say all control which use mouse-events have this problem.
How solve this problem???
this problem depends on two things:
1) system configuration (CPU, RAM , VGA) also depends on power of these parts
2) Windows Version (XP,Seven) seven Much faster than Xp, xp too slow
Tip:
also you must know using wpf in windows xp two thing make this problem:
1) using effects(or bitmap-effect) on window
2) using allow transparency with none-border style for window
these effect make your window slow to occure any events and trigger!
otherwise if You not use these effect, you have a good wpf app with good speed in triggering events(also on Minimal systerm ).
Good Luck
I have been getting more involved with WPF for about a year now. A lot of things are new and sometimes it is hard to get my head wrapped around it.
At the same time I am rereading the GOF Design Patterns book.
A few times I would stop in the middle because I would realize that a certain pattern is the very one used in some WPF functionality. Whenever such a realization hits me, I feel like my understanding of the related WPF principle just took a big leap. It's kind of like an aha-effect.
I also realized that I had a much easier time understanding Prism for example because the documentation does such a great job at explaining the patterns involved.
So here is my "question" (more like an effort):
In order to help us all to understand
WPF better it would be great if anyone
who also "spotted" a design pattern in
WPF could give a short explanation.
One pretty obvious example that I found is the Routed Event:
If an event is detected by a child
control and no handler has been
specified, it passes it along to its
parent and so on until it is finally
handled or no parent is found anymore.
Lets say we have an image on a button
that is inside a StackPanel that is
inside a window. If the user clicks
the image, the event will either be
handled by it (if handling code has
been specified) or "bubble" up until
one of the controls handles it. So
each control will get a chance to
react in this order.
Image
Button
StackPanel
Window
Once a control handles it, the
bubbling will stop.
This is the short explanation, for a
more precise one consult the WPF
literature.
This kind of functionality represents
the "Chain of Responsibility
Design Pattern" which states, that if
their is a request, it gets passed
along a responsibility chain to give
each object in it a chance to handle
it. The sender of the request has no
idea who will handle it which ensures
decoupling. For a more thorough
explanation follow the link.
The purpose here is merely to show how this (seemingly old 10+ years) idea found its way into our current technology and to offer another way of looking at it.
I think this is enough for a start and hope more parallels will be collected here.
Cheers, Thorsten
I don't think it is specific for WPF but the observer design pattern seems to be the foundation on which all event handling in .Net and WPF is based.
The observer design pattern is described as "Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.". In .Net with the += operator you subscribe to such a change in state. Subsequently you unsubscribe with the -= operator.
I'd say CommandBindings are pretty important and fundamental to the way I develop.
WPF Tutorial - Command Bindings and Custom Commands
MSDN Overview