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.
Related
The WPF designer has a tough job to do. In order to show you a life view of your screen or component it has to execute code but, since you do not control the designer, it has to do this without producing any side effects.
So how does it do that? What are the rules around execution?
What if the view's code-behind code does logging to a file or a service?
What if the code-behind calls MessageBox.Show?
What if the code-behind doesn't have an empty default constructor?
I've hit situations before where I had a default constructor that was checking GetIsInDesignMode and creating and assigning a DataContext if false, and still the designer wasn't rendering correctly. Is there some sort of stack-depth limit?
What are the limitations?
it has to do this without producing any side effects
No, the designer is not that smart. If IsDesignTimeCreatable is specified, it will execute all code in a public parameterless constructor and in properties accessed by bindings. Specifically, it will popup message boxes, write to files, etc -- or throw exceptions trying (just try it yourself).
If you don't have a public parameterless constructor, it can't create an instance, so no code will run.
Regarding your question about "stack depth limit", I know of no such limitation. If you have a specific case where it's not working, I suggest you ask a specific question about that case.
In most cases where the designer fails it is because of an exception or other non-data-related problems (such as missing design-time resources). You should definitely guard code you don't want called during design-time using DesignerProperties.GetIsInDesignMode (I usually add a property IsInDesignMode to the base view model).
This is not exactly answering your question, but to be honest 'how does it work' is not a very specific question.
However rather than dropping this check in to your code-behind, are you aware that you can add something like this to your Xaml?
d:DataContext="{Binding Source={d:DesignInstance Type=namespace:className, IsDesignTimeCreatable=True}}"
This means that you can make a design-time version of your class, e.g. CalculatorDesign :
ICalculator, reference that in the Xaml, and each time you change and compile the design-time class the view will update within VS without running any code or having complicated logic in code-behind.
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?
We have some derived control classes which have specific data. And these controls also set the data error info and binding to some specific property. For example, if the property IsNew (providing it exists) is true then the background is highlighted.
Now I want to know, what if I use these controls and bind to some objects which do not expose such property as IsNew? Will it affect the performance for Release version?
The error in itself will not cause any additional performance issues, but the constant Binding checks will and do cause some very minor (practically unnoticeable) performance issues. This is one of the many reasons why WPF performs less well than many other languages. However, these checks will go on whether you have errors or not.
The only time that having errors will actually slow down your program is when your are using the PresentationTraceSources to output information into the Output Window of Visual Studio or worse still, into an external trace file. However, even in these cases, it is unlikely that you will find a noticeable drop in performance, unless you have set the WPF Trace Settings to the most verbose setting of Verbose.
I've read a lot of questions on SOF and links (for example http://www.beacosta.com/blog/?p=52)
But is there easy way to know what exact file I should look into when Binding fails?
If we have one Application and a lot of forms, it can be difficult too.
Have you tried checking "Thrown" for the exception in question in the Debug->Exceptions menu.
E.g. if you get
System.Windows.Data Error: 35 : BindingExpression path error ...
Then you can tell the debugger to break on it by checking "Thrown" under Common Language Runtime Exceptions -> System.Data -> System.DataException. This is however, only useful if the exception originally occurs in your code. Other exceptions, such as binding to non-existing properties and so on will silently fail and only print in the Output window. There is some discussion on http://visualstudio.uservoice.com for improving XAML debugging
I just found the most WONDERFUL post when looking for this. It is a listener that listens for binding errors and throws up a message box with details. It only works when running from within Visual Studio, so you won't show it to your users. Two steps - copy the class into your project, and set the listener in your main window.
http://tech.pro/tutorial/940/wpf-snippet-detecting-binding-errors
You can use Snoop for this: http://snoopwpf.codeplex.com/
Just use Snoop to point to your application and then you can sort on Binding Errors. All Bindings Errors will be highlighted in RED, and show the property of the control.
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.