What of the following TextBlocks' Bindings costs more performance:
<Window
x:Name="Me"
x:Class="MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication1"
Title="MainWindow">
<StackPanel>
<TextBlock Text="{Binding Title, ElementName=Me}"/>
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType={x:Type src:MainWindow}}}"/>
</StackPanel>
</Window>
I am sure my question might take different when the TextBlocks are in a high nesting level having many siblings and ancestors.
Considerations
(based on personal thoughts only, I might be wrong in each particular one!):
开发者_如何学CElementName
:- Might search and compare current element to more control, thru all its children, siblings, uncles and great uncles including ancestors (maybe there is a HashTable of all the registered names?)
- Getting a
Name
property of a control should cost less performance than callingGetType
. - Comparing a string is cheaper than comparing types, especially when you know that most of the controls don't even have their
Name
set.
FindAncestor
:- Will only iterate thru ancestors, not siblingls 'uncles', 'cousins' etc.
- Most likely uses
GetType
to determine ancestor type; GetType costs more performance then a simpleName
property getter (maybe DPs are different?)
It's usually a terrible idea to try to answer this sort of thing by arguing about which you think will be faster. Far better to construct an experiment to measure it.
I modified your setup a little - I put the relevant Xaml into a UserControl, and bound to the Name
property since UserControl
doesn't have a Title
property. I then wrote some code to create a new instance of the control and add it to the UI, and used the Stopwatch
to measure the time taken to construct and load it. (I start the timing just before constructing the user control, and I stop just after the user control raises its Loaded
event.)
I run this code from a DispatcherTimer
20 times a second so I can take lots of measurements in the hope of reducing experimental error. To minimize distortions due to debugging and diagnostic code, I'm running in a Release build, and I only calculate and print the average after 2000 iterations have completed.
After 2000 iterations, the ElementName
approach averages 887us.
After 2000 iterations, the RelativeSource
approach averages 959us.
So ElementName
is, in this particular experiment, slightly quicker than RelativeSource
. Loading a trivial UserControl
with just a Grid
and one TextBlock
where there's only one named element, the ElementName
approach looks to take 92% of the time to load that the RelativeSource
approach takes.
Of course, I'm measuring a small, artificial example here. The performance of the ElementName approach might vary based on how many named elements are in scope. And there may be other unanticipated factors that might produce completely different results in real scenarios. So I would recommend performing similar measurements in the context of a real application if you want to get a better picture.
I repeated the experiment with 10 TextBlocks instead of 1. ElementName
then averaged 2020us while the RelativeSource
approach averaged 2073us, again over 2000 iterations for both tests. Weirdly, there's a smaller difference here, not just in relative terms, but in absolute terms - the one-element examples showed a difference of 72us, where the ten-element examples showed a difference of 53us.
I'm starting to suspect that I'm causing more variability by running my tests on my main machine, rather than one carefully configured with as little stuff as possible to minimize noise.
One more variation: still with 10 bound text blocks, I added ten more empty, unbound, named text blocks to the user control. The idea here was to introduce more named things - ElementName
now has to locate a named item within 11 named things. The average for ElementName
is now 2775us. The RelativeSource
approach with these extra 10 named elements came out at 3041us.
Again, I suspect variability on my desktop machine here - it seems weird that RelativeSource
has performed significantly worse here than in the scenario that should have been more to ElementName
's advantage.
Anyway, what does seem reasonably clear is that the cost of loading here is far more sensitive to the number of elements than it is to which style of binding you use. There is apparently a small advantage to ElementName
but small enough (and with weird enough results) to cast suspicion on the validity of concluding that it is necessarily faster.
So we could construct more careful experiments to get a better picture. But in my view, if you can't conclusively demonstrate a significant difference in performance when running on an ordinary computer, then it's basically a waste of time arguing about which is quicker.
So in conclusion: performance is the wrong thing to focus on here. Pick whichever makes for more readable code.
The later of the two needs to walk the visual tree looking for a particular ancestor type, where as the prior looks directly to the window's namescope for a registered object with that name...my guess would be the later is marginally slower...that said, I don't think there will be a significant performance difference.
Hope it helps,
Aj
In general the ElementName
should be used when possible.
The given example and benchmark example is quite simple.
In real world examples the elements have a larger visual tree and the FindAncestor
binding must traverse a lot more elements in order to find the element.
I gained SECONDS by changing some FindAncestor
bindings to ElementName
bindings in a real world application.
IMHO the ElementName
binding is more readable, too.
精彩评论