-
Notifications
You must be signed in to change notification settings - Fork 3.5k
RelativeSource FindAncestor binding errors #3853
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi @JorisCleVR I am perfectly fine with the solution of adding a fallback value. I will admit there are probably some other styles that could benefit from a similar change as well. |
Oke, then I will go through the styles and check where a fallback value can be applied. I will get back to you when I have a PR available for it. |
Just now created a pull request with changes for all bindings that use AncestorType for the look up: #3862 |
When looking further into the issues we are having with these bindings I found a more conclusive answer to why it goes wrong inside of a DataTemplate and wanted to place it here for completeness. For my own code I created a DataTemplateContainer class (inheriting from Decorator) that is always the root element of my DataTemplates. This resolves the issue in all cases because now the GroupBox finds the DataTemplateContainer as the ancestor. |
Bug explanation
I am currently having a lot of binding errors. For example:
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.FrameworkElement', AncestorLevel='1''. BindingExpression:Path=(0); DataItem=null; target element is 'GroupBox' (Name=''); target property is 'Foreground' (type 'Brush')
Some context
Earlier I had them in some occasions, but was not able to find the root cause of them. But since I now enabled virtualization on all of my ListBoxes I am getting them more cinsitently. And it became even more reproducable now that I am introducing a LazyLoadContentControl.
For the completeness: What the LazyLoadContentControl does is it first loads a more leightweight placeholder control (defined in a DataTemplate). Then when the GUI has time (using the GuiDispatcher with DispatcherPriority.Background) it renders the (complex) actual control (also defined in a DataTemplate). The results of this control are great and it feels the same as most web applications do with loading their contents.
Reference code example (simplified)
The following example is a simplified version of the code. Note it can not actually be run, but is meant as a reference to get a more clear understanding of how the MaterialDesignCardGroupBox style causing the error is used
Error cause
As for what I found on this topic is that in some cases (e.g. when Virtualization is enabled on a ListBox) the items are temporarily removed from the Visual Tree but still kept alive because of the VirtualizationMode.Recycling. Since it has no parent anymore it will not have an Ancestor of type FrameworkElement an therefore resulting in the given binding error.
Fix proposal
What I found to prevent this is to define a FallbackValue. So in this case the binding in MaterialDesignCardGroupBox would change from:
to:
Of course this fix needs to be applied in other styles using RelativeSource and AncestorType as well.
Wrap up
Please let me know what you think of defining a FallbackValue for the cases where we do a RelativeSource lookup by defining an AncestorType. If this is an acceptable solution I will create a PR that implements this in the places necessary.
Furthermore if you have any other toughs on the issue please let me know.
Version
Master branch
The text was updated successfully, but these errors were encountered: