question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Bindings Don't Work within Flyout within ControlTemplate

See original GitHub issue

Describe the bug

While writing the ColorPicker it was discovered that TemplateBinding was not working in the control template. Even switching to a standard Binding with RelativeSource set to TemplatedParent doesn’t seem to work.

~This issue appears to be because the Flyout, once opened, is not added to the logical tree (@maxkatz6 pointed this out and ran across a similar issue with the SplitView).~

There are two issues here:

  1. The binding is not properly created with a TemplateBinding or Binding with RelativeSource=TemplatedParent. The parent is never set and/or the binding contexts are invalid.
  2. Working-around this issue with Binding $parent[control].property syntax reveals another issue. When the Flyout is closed and destroyed, that triggers a binding update with the default/empty values back to the parent (for TwoWay bindings). This means whatever changes done when the Flyout is open are immediately lost when the Flyout closes. If issue 1 is fixed, this issue will still likely persist.

Both of these were not an issue in WPF/UWP.

To Reproduce

It is best just to test this in the ColorPicker PR #8215

<ControlTemplate>
        <DropDownButton CornerRadius="{TemplateBinding CornerRadius}"
                        Height="{TemplateBinding Height}"
                        Width="{TemplateBinding Width}"
                        HorizontalContentAlignment="Stretch"
                        VerticalContentAlignment="Stretch"
                        Padding="0,0,10,0"
                        UseLayoutRounding="False">
          <DropDownButton.Styles>
            <Style Selector="FlyoutPresenter.NoPadding">
              <Setter Property="Padding" Value="0" />
            </Style>
          </DropDownButton.Styles>
          <DropDownButton.Flyout>
            <Flyout FlyoutPresenterClasses="NoPadding">
              <ColorView x:Name="FlyoutColorView"
                         Color="{Binding Color, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                         ColorModel="{Binding ColorModel, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
                         HsvColor="{Binding HsvColor, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
            </Flyout>
          </DropDownButton.Flyout>
        </DropDownButton>
      </ControlTemplate>

Expected behavior

TemplateBinding should work within a Flyout just like UWP.

Screenshots

N/A

Desktop (please complete the following information):

  • Windows 10 Pro
  • Current master as of this writing

Additional context

  • This might be an issue with the Flyout or with Button (which DropDownButton derives from)
  • A partial work-around is to use Binding $parent[control].property syntax

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
maxkatz6commented, Jun 29, 2022

TemplatedParent is applied only on these logical children which were in the tree at a time, when template was applied. Which makes sense.

And while Flyout’s content and ToolTip are part of the logical tree as they should. The problem is they both are added to the logical tree only after being opened. I.e., after template was created. For popups it was solved like forever ago https://github.com/AvaloniaUI/Avalonia/commit/7b192505d7b5dcc0eb9cb7afe675c161b62ae10f#diff-d949e9adb33714546ba0ea5e06af710cd80f33f7a446085b746577a334fb8637R216

1reaction
amwxcommented, Jun 21, 2022

This issue appears to be because the Flyout, once opened, is not added to the logical tree (@maxkatz6 pointed this out and ran across a similar issue with the SplitView).

Flyouts themselves aren’t added to any tree, but the underlying popup is when opened (otherwise Styling wouldn’t work). It’s using the indirect method instead of adding it to the actual LogicalChildren collection: https://github.com/AvaloniaUI/Avalonia/blob/99b4530e455cf64f9c5a392dbeb5a95974e0c792/src/Avalonia.Controls/Flyouts/FlyoutBase.cs#L225

Printing the logical parent hierarchy shows everything is connected all the way up to the main window:

[Button inside flyout within control template]
Avalonia.Controls.Grid
Avalonia.Controls.FlyoutPresenter
Avalonia.Controls.Primitives.Popup
Avalonia.Controls.Button
AvaloniaApplication2.TestControl
Avalonia.Controls.Grid
AvaloniaApplication2.MainWindow

However inspecting that button (and everything from the Popup down) shows it’s TemplatedParent property is null, and I believe that’s set by the Xaml compiler when it parses the template. So I *think* this is a Xaml compiler thing. I don’t really understand how that works, so someone who does may have better insight but my guess is either A) it sees the Flyout as not a styleable object and seems to lose its scope when parsing the Flyout part of the template, or B) because those items aren’t connected to the logical/visual tree at parsing, it keeps the TemplatedParent property null by ignoring them. (or even possibly a little of both).

Read more comments on GitHub >

github_iconTop Results From Across the Web

UWP Derived Button With Flyout: Binding within the Style
It seems that the only way for the flyout content to obtain information from it's attached element is through DataContext inheritance. I could ......
Read more >
WPF FlyoutControl - Cannot focus control within flyout from ...
I have a DataTemplate which contains a TextEdit. The DataTemplate is bound to the ContentTemplate property of a Style for the DevExpress ...
Read more >
TemplateBinding markup extension - UWP applications
Attempting to use a TemplateBinding outside of a ControlTemplate definition in XAML will result in a parser error. You can use TemplateBinding ...
Read more >
Wpf context menu. PlacementTarget = rectangle; contextMenu ...
I've read that the ContextMenu is not under the main Visual tree so i can't bind it directly, but any method i try...
Read more >
Xamarin.Forms 5: Dual Screens, Dark Modes, Designing ...
You just need to assign a custom template to the control's template property; described in C# or XAML, it doesn't matter. Supplying a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found