Locating binding errors - wpf

I'm dealing with a large WPF application that is outputting a large number of binding errors. A typical error looks like this:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')
Problem is I don't know where in the app this is coming from. Searching the entire solution for AncestorType={x:Type ItemsControl} doesn't necessary help since I still don't know which result is the culprit. I've tried setting PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.All;
but the extra information doesn't help locate the problematic bindings. File names and line numbers is really what I need. Is there anyway to get this information? The only other solution I can think of is to assign names to the canidates then narrow it down from there. In that vein, is there a way to automatically assign a unique x:Name to all namable elements throughout the solution?

I generally set a breakpoint on the code that actually writes the error message. When the breakpoint is hit I inspect the visual tree of the object that had the binding error using a Visual Studio visualizer. This almost always tells me exactly where in my code to find the binding and fix it. (You can figure out where to set the breakpoint by installing a custom trace listener and breaking in it, then checking out the call stack.)
I also design my application to minimize the number of "false positives" by making sure bindings will always be valid when the source is present at all.

When do you see these binding errors? Only during startup (or loading of a new AddIn, or new View, etc.).
In those cases, I've found that these errors are often "false positives," in that they are thrown before the object being bound to is initialized. It's annoying, for sure, but if everything in your application seems to be bound correctly (here, for instance, your menus seem to have a proper HorizontalContentAlignment), then I wouldn't worry too much.

Sounds like this Xceed column chooser bug:
http://xceed.com/CS/forums/thread/25140.aspx
http://xceed.com/CS/forums/ShowThread.aspx?PostID=26315&PermaPostID=26029
I'm having the same problem, although the workarounds mentioned in this post aren't working for me. Maybe they'll work for you.

Related

How to find from where a XamlObjectWriterException is coming?

I have a resource dictionary with 12.000 lines.
If I activate First Chance Exceptions I get some XamlObjectWriterException with an inner of type NotSupportedException claiming that it cannot create a DependencyProperty from text 'Padding' or 'Foreground'.
Line number and position are set to 0 so I don't know where the error is coming. The exceptions are coming from the loading of the resource dictionary on app startup, before using the styles anywhere.
Is there a way to find what style is (are) the offending ones?
Is there a way to find what style is (are) the offending ones?
I am afraid the XAML processor doesn't give this detailed information. But at least it gives you a clue.
Search for all places where you set the Foreground property and comment them out one by one and compile and run until you have narrowed down the issue. I am afraid there is no easier way unless you are able to guess in which resource the error may be.

XAML: Can I overload binding resolution?

Y: The Question
A binding is "merely" a set of name-string pairs which are interpreted at runtime. When this produces unexpected results, can the binding resolution be intercepted? This could reveal issues such as timing problems (improper initialization order, race conditions) and typos, or eliminate them so the debugging focus can be moved.
I'm hoping for a way to intercept the call to Binding.ProvideValue, or similar, but with all the relevant information (Path, DataItem, etc.) available. I want to know how the Binding class understands my instructions, and when.
I tried using an IValueConverter, but it's not called before the error (below) occurs.
I tried writing a MarkupExtension, with a private Binding instance, but it didn't help me out by retrieving the relevant information for free. Specifically, it didn't determine the appropriate DataItem inherited via DataContext. (I'm guessing it acquires the information through internal communications with the containing XAML element, since static code wouldn't be prejudiced against me.)
X: The Problem
I'm working with this binding, which happens to be on an actipro property grid item (and several otherwise identical bindings work just fine):
(edited because I initially copied the wrong binding)
Value="{Binding VMLeftPLaneOneHoleHoleOneSlugCylinderLen,
Mode=OneWay,
StringFormat=F3}"
I can't shake the following runtime error. The property exists on the mentioned class, and no spelling error is involved (reasonable guess due to the absurdly long name). It is available publicly (other properties weren't, this is my last one). The property only provides a getter, hence Mode=OneWay.
System.Windows.Data Error: 40 : BindingExpression path error: 'VMLeftPLaneOneHoleHoleOneSlugCylinderLen' property not found on 'object' ''LegacyViewModel' (HashCode=3273904)'. BindingExpression:Path=VMLeftPLaneOneHoleHoleOneSlugCylinderLen; DataItem='LegacyViewModel' (HashCode=3273904); target element is 'PropertyGridPropertyItem' (Name=''); target property is 'Value' (type 'Object')
I've been staring at the code, and I'm in that mood where I'm sure I've checked everything and totally implausible explanations are popping into my head - like the XAML interpreter having a different LegacyViewModel class, one which lacks this specific property. And after typing that I went ahead and hit Clean+Rebuild just to make sure.
I don't have a minimal test case, mostly because this project is gargantuan and unmaintainable in multiple ways. But I'm not asking for a solution to the actual problem, only a technique to help me solve it.
Did I make a blatantly obvious mistake? Is there something I haven't checked? What can I do to measure this fairly deep part of the XAML system?

How can I Improve performance of RelativeSource FindAncestor?

Is FindAncestor searches an element in whole Visual tree of Window?
If yes, then how can I improve on it ??
Is binding data error thrown if we access property of object by finding an element with Find Ancestor & no such a element exist?
If yes, then how can I resolve such a error.
In my case binding error is throwing on output window. To solve this error, I tried with setting FallbackValue,but now it gives me warning instead of error that is the only difference. Everything else is same as error.
Can someone tell me How exactly FindAncestor works??
If you want to know how FindAncestor works internally, you should read the internal code. http://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Data/ObjectRef.cs,6a2d9d6630cad93d
You should try and not use FindAncestor that much. It can be slow, plus the children shouldn't rely on the knownledge of "there exist somewhere a parent who has what I need".
That said, FindAncestor itself can be also your friend at times.
It depends on your case, but for example, it's common to have a DataGridRow which uses FindAncestor in order to find information about DataGrid or some other parent element.
The problem with that is: IT'S SUPER SLOW. Say you have 1000 DataGridRows, and each row uses FindAncestor, plus each row has 7 columns, which itself has to traverse through ~200 elements in logical tree. It does not have to be slow, DataGridRow has always the same parent DataGrid, it can be easily cached. Perhaps "One-time cached relativeSources" would be the new concept.
The concept can be like this: write your own relativeSource binding as you've done. Once the binding is done first time, use visual tree helper to find a parent of specific type. If that is done, you can store the found parent IN the direct parent attachewd property, as so:
var dic = myElementThatUsesRelativeSourceBinding.Parent.
GetCurrentValue(MyCachedRelativeSourceParentsProperty)
as Dictionary<Type, UIElement>;
dic[foundType] = actualValue;
Later, you use this cache information in the search of relative source later. Instead of taking O(n), it will take O(1) for the same element / children of parent.
If you know that the parent always exists, you should create the binding in code-behind, for each element that tries to use FindAncestor. This way you avoid traversing the tree.
You could also create a hybrid solution which tracks the changes of visual tree, and mainains "cache". If a DataGridRow asks for "find me relative source off type DataGrid", there is no reason that you need to do it all the time: you could cache it. There's OnVisualChildrenChanged - just an idea, not even 100% sure if it can be done nicely, but this will require extra memory, and dictionary.
This can get very complex, needless to say :-), but would be cool for "side project".
On another side; you should also flatten visual tree, it would gain you a speed.
When using the FindAncestor value of the RelativeSourceMode Enumeration for the RelativeSource.Mode Property, you can also set the level of ancestor to look for using the RelativeSource.AncestorLevel Property. From the last linked page:
Use [a value of] 1 to indicate the one nearest to the binding target element.
There is not much to tell about "Find Ancestor". It works simple which is why its fast. It works like this: The type of the parent of an element is always being asked. If the type does not match with one you need. The parent becomes actual element and the process is being repeated again. Which is why "Find Ancestor" always works the visual tree up but never down :)
The only possible reason where I think you might feel some performance issues with RelativeSource bindings is when you in ListBox and you have really a nasty item template defined with a bunch of RelativeSource bindings inside. ListBox tends to virtualize stuff that means it keeps track of data items but recreates their containers. To sum up, you start scrolling and the faster you scroll the more often are those visual containers gonna be recreated. In the end everytime a container gets recreated the relative source binding will try seek for given ancestor type. That is the only case that I can think of right now where you will end up lagging few milliseconds. But that is not bad..
Are you experiencing some kind of issue like this? Tell us more about your issue please
Like Sheridan I would let those erros just be :) however if you hate them that much, you could work with bridges
A Bridge is something you will need to implement yourself.
Take a look at this link: http://social.technet.microsoft.com/wiki/contents/articles/12355.wpfhowto-avoid-binding-error-when-removing-a-datagrid-row-with-relativesource-static-bridgerelay.aspx
Basically you put that bridge element somewhere in your Xaml as a resource and when you need RelativeSource you use StaticResource extension instead like this:
Binding="{Binding MyPath, Source={StaticResource MyBridge}}"
Try it out

WPF Binding Failure performance hit vs Exception

when we bind to heterogeneous collection of objects, not all objects have the same set of properties. in the output window we get a message like:
System.Windows.Data Error: 39 :
BindingExpression path error:
'RoundingFactor' property not found on
'object' ''MultiLineTextMarkingScheme'
(HashCode=7262386)'.
BindingExpression:Path=RoundingFactor;..........
This doesn't appear to be an exception, but we are concerned it has a performance impact.
Should we be concerned and create a view model that has all the properties we wish to bind to (and have the properties that dont exist on the underlying element return null) or can we just leave it.
This situation often occurs in a grid scenario where there might be large numbers of these binding failures.
I haven't tested this myself but a blog post from the Visual Studio team says that binding errors indeed impact performance:
WPF tries several different ways to resolve path errors, including searching for attached properties and this is quite expensive.
You're only seeing that output because you're running inside Visual Studio. Normally those trace statements go nowhere because there is no trace listener. Either way, the performance implications are completely negligible.
Exceptions, on the other hand, would be a very costly way of reporting binding failures, particularly because - as you note - there are often bindings that work against some objects but not others.

Setting Silverlight DataGrid to just throw an exception when binding field does not exist

I just wasted invested a good chunk of time trying to determine why a specific datagrid among many was showing shrunken rows with no text. After many trial and errors attempts to figure out what made this grid special, I finally found that the class used for the row items was marked private.
That is a perfectly good reason, but I would have prefered to have been able to narrow it down to a binding issue (and if possible a "field is not accessable due to protection level" type message) much sooner then it took to sysmatically disassemble the entire convoluted process it took to get data into and configure that grid. Ideally I shouldn't have had to see the wrong behavoir in the first place, an error should have occured immediately when a column attempted to read from a field that it could not.
All my datagrids inherit from a custom base class in order for some global standards to be applied - if there anything I can do in my CustomDataGrid class to cause an exception to be thrown whenever a columns binding expression fails, such as if the class/property is private or the property name has been mispelled in the binding expression? (This is different from binding validation).
I always keep an eye out on debug output window when dealing with SL/WPF databinding. The framework(s) are actually pretty good at generating messages about databinding problems that include specific details about what fields it failed to bind on or what have you.
This doesn't exactly answer your original question, but it helped me sort through binding issues quite a bit once I realized there was good info being thrown into there.

Resources