Scheduling UI tasks for after the visual tree has settled down - wpf

In XAML-based apps, quite often I need to manipulate on-screen elements, resize or move stuff around. The situation arises usually for very custom UI controls.
The timing of stuff loading and data-binding etc. can give rise to irritating timing issues.
Traditionally, my colleagues and I have worked around these problems by 're-dispatching' work to the UI thread so it runs later, when dependent properties are in the 'final' states.
Is there a better way to do this? What strategies have you found that work?
The LayoutUpdated event can be very noisy, fine-grained, and deregistering requires forgoing a Lambda for a method and thus not being able to access enclosed variables from the outer logic - its a bit of a 'mare.
Edit
I'll give a tangible example. A custom control draws an outline around a face when doing facial recognition, so we're talking totally custom stuff here, nothing XAML does out the box.
The image needs to be scaled and sized and the paths and geometries scaled and sized so its all in alignment.
When programmatically changing the heights and widths of elements, the impact is not immediate, its only once the UI thread is relinquished back to the XAML framework does the rendering subsystems rearrange everything.
Thus, logic that depends upon the changed values needs to run after the framework has rearranged everything, and so this work needs scheduling to occur later on the UI thread, hence resorting to dispatching. It smells.
Many events and virtuals are called at times when requisite data is not yet available. Sometimes, work needs to be done upon data arrival (i.e. property change notification) which is does not typically trigger the XAML layout events. In this case, we resort to dispatcher hacks.

What about using the Loaded event?:
Loaded += LoadedHandler;
...
private void LoadedHandler(object sender, RoutedEventArgs e)
{
// Do something here when controls have loaded
}

I discovered that in WPF, this dependency property metadata argument exists to help with the problems I'm talking about.
FrameworkPropertyMetadataOptions.AffectsRender
The enum doesn't exist in Windows Store applications, presumably since its designers think the InvalidateArrange method is a suitable alternative.
Possibly, we should be a) invalidating the arrangement within our DP change handlers b) making these arrangements over multiple passes c) tolerating incorrect layout in-between passes.
Still, the using lambdas with the dispatcher is nice since variables used in calculations can be referenced from inside the closure.

Related

WPF optimization: Insert/Delete child from StackPanel

I often insert/delete 20-30 very complicated UserControls into StackPanel.
All UserControls already created and cached for reusing. Before reusing control I clean old parent and remember control.
Operations like StackPanel.Children.Remove, StackPanel.Children.Add take a lot of time in my scenarios.
How can I optimize these operations? E.g. insert all controls in StackPanel at a time or freeze notifications during collection's modifications or else?
May who known useful articles regrading wpf optimization (except MSDN)?
You could override the OnCollectionChanged() event handler of your ObservableCollection, to either disable event handling all together, or to queue the events to handle later.
See the post here, the answer could help you - https://stackoverflow.com/a/5491534/903056
I assume you need to look into virtualized UI or data loading ( if any) strategies.
In this specific case, use controls like VirtualizingStackPanel to make the UI draw fewer things. You can have more information on this blog.

WPF performance problem with CommandManager

We've created a new, quite complex, WPF application from the ground up and have run into a performance problem as the number of commands registered with the CommandManager increase. We're using simple lightweight commands in our MVVM implementation, however the third party controls we're using (Infragistics) do not, and call CommandManager.RegisterClassCommandBinding liberally to add RoutedCommands. The performance problem manifests itself as a perceived sluggishness in the UI when responding to user input, for example tabbing between controls is slow, text input is 'jerky' and popup animation is 'clunky'. When the app is first fired up the UI is snappy. As more screens containing Infragistics grids are opened the performance deteriorates.
Internally, the CommandManager has a private field named _requerySuggestedHandlers, which is a List< WeakReference>. I've used reflection to get a reference to this collection, and I've noticed that when I call .Clear(), the responsiveness of the UI improves back to its initial state. Obviously I don't want to go round clearing collections that I know little about, especially using reflection (!) but I did it to see if it would cure the performance problems, and voila it did.
Normally, this situation would clean itself up after a certain amount of time passes. However, the collection of WeakReferences (_requerySuggestedHandlers) will only get trimmed once a garbage collection is initiated, which is non-deterministic. Because of this, when we close down windows containing grids (Infragistics XamDataGrid), the CanExecute property for 'dead' grid commands continue to be evaluated unnecessarily, long after the window is closed. This also means that if we close down a number of windows, the performance is still sluggish until a garbage collect is initiated. I understand that this can happen on allocation, and I've seen that myself because if I open a further window this causes the initial memory (from the disposed Windows) to be collected and performance returns to normal.
So, given the above, here are my questions:
How, and from where, does CommandManager.InvalidateRequerySuggested() get called? I haven't found any documentation on MSDN that explains this in any great detail. I hooked up to the CommandManager.RequerySuggested event and it looks like it's being called whenever controls lose focus.
Is is possible to suppress CommandManager.InvalidateRequerySuggested() being called in response to user input?
Has anyone else run into this issue, and if so, how have you avoided it?
Thanks!
This sounds like one of the rare cases where deterministically calling GC.Collect() is the right thing to do. The ordinary argument against it is that the garbage collector is smarter than you are. But when you're dealing with WeakReference objects, you enter territory where you may know something that the garbage collector doesn't. Kicking off garbage collection is certainly better than clearing _requerySuggestedHandlers - among other things, it won't do anything to the WeakReference objects that point to controls that are still alive.
I'd choose this over trying to figure out how to suppress RequerySuggested, since that would screw up the behavior of those commands that you still care about.

MVVM: commands vs eventhandlers

I know this has been done to death, but most answers are along the lines of "yeah, you can use eventhandlers in place of commands if you like". This still doesn't solve the problem of whether writing complicated commands is warranted vs just wiring up eventhandlers in code behind to call testable methods in your view model.
I don't like commands because they produce a lot of boilerplate code and don't give me any benefit over normal methods, plus some of them (such as drag & drop) are a pain to implement.
What's wrong with writing:
codebehind:
private void Button_Click(object sender, RoutedEventArgs e)
{
viewModel.LoadData();
}
viewmodel:
public void LoadData()
{
//....
}
This is equally testable (if not more) as any command is. IMO, as long as UI specific stuff isn't leaking into your business logic, there's really no need to waste time on complicated patterns like that. Thoughts?
What's wrong with writing
Nothing - for the most part.
There is nothing wrong with using code behind, if you are careful to keep the business logic out of the code behind file. This is delegating this directly to the ViewModel, which is reasonable.
That being said, there are a couple of potential downfalls here in terms of long term maintainability:
By doing this, you're coupling the View to the ViewModel more tightly. While this is a reasonable thing to do (the View, in reality, always knows about the ViewModel), it does prevent potential reuse of View components in some scenarios, as using an ICommand allows you to have the same View be used with potentially different ViewModels. (This is rare in practice, however.)
This starts a slippery slope - by adding "any" code into code behind, you're opening up the potential that another developer will add "just one more line" in there. Over time, this can lead to a mess.
It's adding code into another place that has to be maintained. Now you'll have to maintain the ViewModel .cs file, your .xaml file, and the code behind file.
You're hard-wiring this logic into a Button. If you decide to change controls, use a gesture, etc., you'll have to remember to rework this logic.
I was in your boat at first, I even asked basically the same question here. But I came around and came to really like commands.
Some commands really are complex enough in and of themselves to warrant testing. They are just as testable as anything else on your viewmodel.
ICommand also includes CanExecute and CanExecuteChanged, which enables your view to intelligently enable/disable itself pretty much for free. This is fantastic in complex views.
Commands make it easier to change your view around, most controls have a Command property you can bind to, and simply moving the binding around is easier than mucking with event handlers. This is especially true if you have designers working on the XAML.
You can pretty much write the entire logic of the view without the view even existing. It leads to a nice flow of build the meat all at once, then throw the interface on top all at once.
Keeping your code in one place leads to longer term maintainability.
To me a very important argument against events is forcing the UI Designer to write code to be able to test a View. And worse: every time he redesigns the View he has to rewire the events.
Commands and the behaviors in Blend make render this process obsolete and much easier.
Another problem might arise when actually using the event arguments when writing the event handler. When you want to switch to another control or another event you might have become very dependent on the event arguments making it hard to switch because the other control/event does not support the same event arguments.

Performance of DrawingVisual vs Canvas.OnRender for lots of constantly changing shapes

I'm working on a game-like app which has up to a thousand shapes (ellipses and lines) that constantly change at 60fps. Having read an excellent article on rendering many moving shapes, I implemented this using a custom Canvas descendant that overrides OnRender to do the drawing via a DrawingContext. The performance is quite reasonable, although the CPU usage stays high.
However, the article suggests that the most efficient approach for constantly moving shapes is to use lots of DrawingVisual instances instead of OnRender. Unfortunately though it doesn't explain why that should be faster for this scenario.
Changing the implementation in this way is not a small effort, so I'd like to understand the reasons and whether they are applicable to me before deciding to make the switch. Why could the DrawingVisual approach result in lower CPU usage than the OnRender approach in this scenario?
From Pro WPF in C# 2008:
The problem posed by these
applications isn't the complexity of
the art, but the sheer number of
individual graphic elements. Even if
you replace your Path elements with
lighter weight Geometry objects, the
overhead will still hamper the
application's performance. The WPF
solution for this sort of situation is
to use the lower-level visual layer
model. The basic idea is that you
define each graphical element as a
Visual object, which is an extremely
lightweight ingredient that has less
overhead than a Geometry object or a
Path object.
What it boils down to is that every single one of those ellipses and lines you're creating is a separate FrameworkElement; that means it supports not only hit testing, but also layout, input, focus, events, styles, data-binding, resources, and animation. That's a pretty heavy-weight object for what you're trying to do! The Visual object skips all of that and inherits directly from DependencyObject. It still provides support for hit-testing, coordinate transformation, and bounding-box calculations, but none of the other stuff that the shapes support. It's far more lightweight and would probably improve your performance immensely.
EDIT:
Ok, I misread your question the first time around.
In the case that you are using OnRender, it really depends how you are creating the visuals and displaying them. If you are using a DrawingContext and adding all of the visuals to a single element, this is no different than using the DrawingVisual approach. If you were creating a separate element for each Visual created, then this would be a problem. It seems to me that you are doing things the right way.
Everyone in the answers got it wrong. The question is whether rendering shapes directly in the drawing context is faster than creating DrawingVisual. The answer is obviously 'yes'. Functions such as DrawLine, DrawEllipse, DrawRectangle etc. do not create any UI Element. DrawingVisual is much slower because it does create a UI Element, although a lightweight one. The confusion in the answers is because people simply copy/paste the DrawingVisual performs better than distinct UIElement shapes statement from MSDN.
I thought Petzold explains in this paragraph;
The ScatterPlotVisual class works by
creating a DrawingVisual object for
each DataPoint. When the properties of
a DataPoint object change, the class
only needs to alter the DrawingVisual
associated with that DataPoint.
Which builds on an earlier explanation;
Whenever the ItemsSource property
changes, or the collection changes, or
a property of the DataPoint objects in
the collection changes,
ScatterPlotRender calls
InvalidateVisual. This generates a
call to OnRender, which draws the
entire scatter plot.
Is this what your asking about?
By the way, this is a fairly recent high-performance WPF tutorial, many tens of thousands of points in that plot, it is 3D rendered and animated also (even uses mouse input to drive some of the transforms).
In my tests however (panning animations), I notice no difference in speed. I would say that using a host element for many drawing visuals is a bit faster. This approach where you build your visual tree with many visuals gives you more control. Moreover, when you want to do a complex hit testing, the filtering process is faster because you can skip entire "branches" of visuals

What's the "right" way to isolate control dependencies

I've made it a personal rule to inherit every UI control before using it. In a previous life I'd always considered this one of the less useful things you could do because the justification always seemed to be "I might want to change the font on all the buttons at once"... a motivation that never paid off... once... ever.
Two recent projects have changed my mind about the practice, though. In the first, we needed a consistent "ValueChanged" event so that we could easily implement a "dirty" flag on our forms without a massive switch statement to choose between a Textbox's "TextChanged" event, or a ListBox's "SelectedIndexChanged" etc. We just wanted one consistent thing to listen for on all controls, and subclassing the built-in controls bought us that pretty easily.
In the second project, every effort was made to get by with the base controls because the UI was expected to be pretty simple, but a few months in, it became obvious that they just weren't going to cut it anymore, and we purchased the Telerik control suite. If we had inherited all the controls to begin with, then changing our derived controls to inherit from the Telerik controls would have applied the changes for us globally. Instead, we had to do some searching and replacing in all the form designers.
So here's my question: What are the relative strengths and weaknesses of
Simply adding a Class, and making it inherit from a control.
Adding a new "Custom Control" and inheriting.
Adding a new "Component" and inheriting.
All three have the same effect in the end, you get a new type of Button to put on your forms. I've seen all three used by different people, and everyone seems to think that their way is the best. I thought I should put this discussion on StackOverflow, and maybe we can nail down a concensus as a community as to which one is the "right" way.
Note: I already have my personal opinion of which is "right", but I want to see what the world thinks.
If both 1 & 2 are inheriting, then they are functionally identical, no? Should one of them be encapsulating a control? In which case you have a lot of pass-thru members to add. I wouldn't recommend it.
Peronally, I simply wouldn't add extra inheritance without a very good reason... for example, the "changed event" could perhaps have been handled with some overloads etc. With C# 3.0 this gets even cleaner thanks to extension methods - i.e. you can have things like:
public static AddChangeHandler(
this TextBox textbox, EventHandler handler) {
testbox.TextChanged += handler;
}
public static AddChangeHandler(
this SomethingElse control, EventHandler handler) {
control.Whatever += handler;
}
and just use myControl.AddChangeHandler(handler); (relying on the static type of myControl to resolve the appropriate extension method).
Of course, you could take a step back and listen to events on your own model, not the UI - let the UI update the model in a basic way, and have logic in your own object model (that has nothing to do with controls).
I use composition. I simply create a new UserControl and add the controls I need. This works fine, because:
I never use that many properties anyway, so pass-through methods are kept to a minimum.
I can start with a naive approach and refine it later.
Properties for look and feel should be set consistently across the site. Now I can set them once and for all.

Resources