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.

Generate properties for templates using TemplatePartAttribute

See original GitHub issue

There is a new attribute ported from WPF. It will be useful to have optional code generation for “parts” of templates. As an example, user code:

[TemplatePart("PART_TextPresenter", typeof(TextPresenter))]
public partial class TextBox
{
    protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
    {
        base.OnAttachedToVisualTree(e);
            
        if (IsFocused)
        {
            TextPresenter?.ShowCaret(); // TextPresenter is generated
        }
    }
}

Additional generated code, adds new property and sets value to it:

#nullable enable
public partial class TextBox
{
    private TextPresenter? TextPresenter { get; set; }

    static TextBox()
    {
         TemplateAppliedEvent.AddClassHandler<TextBox>((control, args) =>
         {
             control.TextPresenter = args.NameScope.Get<TextPresenter>("PART_TextPresenter");
         });
    }
}

Problems:

  1. Only one static ctor can be created for class, if we want to handle TemplateAppliedEvent to fill these properties.
  2. Only one override of OnTemplateApplied method is possible, if we want to use it to fill these properties.

Which means, we most likely will need to modify Avalonia to add yet another way to read namescope after template was applied.

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:3
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
robloocommented, Nov 11, 2022

There was a lot of further discussion in https://github.com/AvaloniaUI/Avalonia/issues/9093 related to how to define the string constants and then enforce them statically in XAML. I think that discussion isn’t fully closed yet and it may influence what is done here. Feel free to jump into that conversation as well. That said, the TemplatePart attribute isn’t going to change so however the string name gets into the attribute is irrelevant for you.

Concerning the code generation:

  1. I would consider using .Find instead of .Get to fail gracefully if control authors don’t do what they need to do. However, that would require nullable types so maybe isn’t worth it. We definitely need good exception handling and build outputs here to say which template part isn’t found though.
  2. Technically instead of TextPresenter the control should be named just Text. Not all template parts currently have good names…

Edit:

  1. The implementation you have seems ok to me. However, it also isn’t using any of the partial class ideas. Using a partial class shared with an internal implementation in Control would allow InitializeTemplateParts to be automatically called. Otherwise we are all going to have to remember to call it inside an OnApplyTemplate override-- which I don’t mind since it’s clearly opt-in.
1reaction
worldbeatercommented, Mar 23, 2022

Regarding the implementation details of the new generator, I guess it is worth introducing a new class similar to AvaloniaNameGenerator named e.g. TemplatePartGenerator, then adding a new option to GeneratorOptions that would control if the new generator is enabled, and then invoking the generator in the composition root.

The code that scans the assembly and finds all classes annotated with the TemplatePart attribute can be found here https://github.com/reactivemarbles/ObservableEvents/blob/main/src/ReactiveMarbles.ObservableEvents.SourceGenerator/SyntaxReceiver.cs#L17 Most likely we’ll need to implement ISyntaxReceiver that receives all relevant classes with TemplatePart attributes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use the TemplatePart attribute on a custom control?
It seems that the TemplatePart attribute is not required to use the template part in code (using the GetTemplateChild() method), I can get...
Read more >
Add TemplatePartAttribute for Controls · Issue #7432
Named parts in control templates are not always clear to control ... Generate properties for templates using TemplatePartAttribute #11934.
Read more >
Further TemplatePart Cleanup in Code-Behind and XAML
Mentioned here: Generate properties for templates using TemplatePartAttribute #11934. Describe alternatives you've considered.
Read more >
PART Control Template and TemplatePartAttribute
The only thing we have to do it get the custom attributes of type TemplatePartAttribute. Here is simple code of it. Code Snippet....
Read more >
TemplatePartAttribute Class (System.Windows)
Represents an attribute that is applied to the class definition to identify the types of the named parts that are used for templating....
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