How to increase the performance of RelativeSource FindAncestor?

Is FindAncestor looking for an item in the entire Visual Window tree?

If so, how can I improve it?

Is binding data error thrown if we access the property of an object by finding an element with Find Ancestor and there is no such element?

If so, how can I resolve this error.

In my case, a binding error throws an output window. To solve this error, I tried setting FallbackValue , but now it gives me a warning instead of an error, which is the only difference. Everything else is the same as the error.

Can someone tell me how FindAncestor works?

+6
source share
3 answers

If you want to know how FindAncestor works internally, you must read the internal code. http://referencesource.microsoft.com/#PresentationFramework/Framework/MS/Internal/Data/ObjectRef.cs,6a2d9d6630cad93d

You should try and not use FindAncestor . This can be slow, plus children should not rely on the well-known words "there is somewhere a parent who has what I need."

However, FindAncestor itself may be your friend at times.

It depends on your case, but, for example, usually has a DataGridRow that uses FindAncestor to find information about a DataGrid or some other parent element.

The problem with this: IT SUPER SLOW. Let's say you have 1000 DataGridRows, and each row uses FindAncestor , plus each row has 7 columns, which themselves must go through ~ 200 elements in the logical tree. It should not be slow, DataGridRow always has the same parent DataGrid , it can be easily cached. Perhaps “one-time caching of relative sources” will become a new concept.

The concept might be this: write your own sourceSource binding, as you did. As soon as the binding is done for the first time, use the visual tree helper to find the parent of a specific type. If this is done, you can save the found parent in the direct parent attribute of attachewd like this:

 var dic = myElementThatUsesRelativeSourceBinding.Parent. GetCurrentValue(MyCachedRelativeSourceParentsProperty) as Dictionary<Type, UIElement>; dic[foundType] = actualValue; 

Later you will use this cache information in your search for a relative source later. Instead of accepting O (n), it will accept O (1) for the same parent element / s.

If you know that a parent always exists, you must create a binding in the code for each element that FindAncestor trying to use. This way you avoid crossing the tree.

You can also create a hybrid solution that tracks changes in the visual tree and the main cache. If a DataGridRow asks "find me relative source code of type DataGrid ", there is no reason why you need to do this all the time: you can cache it. There, OnVisualChildrenChanged is just an idea, not even 100% sure if it can be done beautifully, but this will require additional memory and a dictionary.

This can become very complicated, it goes without saying :-), but it would be great for a “side project”.

On the other hand; You should also smooth the visual tree, this will give you speed.

+4
source

When using the value of the FindAncestor RelativeSourceMode Enumeration for the RelativeSource.Mode Property , you can also set the parent level for the search using the RelativeSource.AncestorLevel Property . On the last linked page:

Use [value] 1 to indicate the closest to the target anchor.

+1
source

This is not the case with Find Ancestor. It works simply, so its fast. It works as follows: the parent type of the element is always requested. If the type does not match the one you need. The parent becomes the actual element, and the process repeats again. That's why "Find Ancestor" always works with the visual tree, but never drops :)

The only possible reason I think you might run into some performance problems with RelativeSource bindings is when you are in the ListBox and you have a really nasty item template defined using the RelativeSource binding inside. ListBox tends to virtualize stuff, which means it tracks data items but recreates their containers. To summarize, you start scrolling, and the faster you scroll more often, the visual containers are going to recreate. In the end, every time the container is recreated, the relative source binding will try to look for the given type of ancestor. This is the only case that I can think of right now, when you finish a lag of a few milliseconds. But this is not bad.

Are you having some kind of problem like this? Tell us more about your problem.

Like Sheridan, I would let these erros be simple :) however, if you hate them so much, you can work with bridges

A Bridge is what you 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 this bridge element somewhere in your Xaml as a resource, and when you need a RelativeSource , you use the StaticResource extension, namely:

Binding="{Binding MyPath, Source={StaticResource MyBridge}}"

Try

0
source

Source: https://habr.com/ru/post/980030/


All Articles