1
\$\begingroup\$

I am trying to make an AvaloniaUI user control. I want to be able to set a property at design time from inside my XAML files and see the result in the designer in Rider, such as the "Hello World!" text below.

enter image description here

The approach I have taken is to add a property to the control that gets and sets the Text property of a TextBlock that is defined in the XAML.

public partial class SectionHeader : UserControl
{
    public string Caption
    {
        get { return this.FindControl<TextBlock>("CaptionText").Text; }
        set { this.FindControl<TextBlock>("CaptionText").Text = value; }
    }    
    
    public SectionHeader()
    {
        InitializeComponent();
    }

    private void InitializeComponent()
    {
        AvaloniaXamlLoader.Load(this);
    }
}
<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             xmlns:viewModels="clr-namespace:BasicMvvmSample.ViewModels"
             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
             x:Class="AvTest.Controls.SectionHeader">
    
    <Design.DataContext>
        <viewModels:MyViewModel />
    </Design.DataContext>
    
    <TextBlock Background="#c71e32"
               Foreground="White"
               Padding="2,3"
               FontWeight="Bold"
               Margin="2"
               Height="25"
               Name="CaptionText"
    >
    </TextBlock>
    
</UserControl>

This approach works, but it does not use the patterns described in the documentation that rely on AvaloniaProperty. I am new to both Avalonia and XAML and wonder if my approach is sensible, or if there is a better and more "XAML way" to achieve this.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

By 'default' the preference is to use a StyledProperty, as these can be bound or styled. If you don't need that, then you get away with something simpler, but if you really don't need anything more, then perhaps consider using a TextBlock with a class (e.g. Classes="SectionHeader") and styling to go with it. Custom controls are mostly useful for providing new behaviours; if you just want to keep the styling clean, then use styles.

To set up a StyledProperty in the class (which I'd suggest doing, because binding gives you so much power (e.g. to bind to a localisable resource key for globalisation)) you'd generally add something like

public static readonly StyledProperty<string> CaptionProperty = AvaloniaProperty.Register<SectionHeader, string>(nameof(Caption));

public string Caption
{
    get => this.GetValue(CaptionProperty);
    set => this.SetValue(CaptionProperty, value);
}

as you can find in the documentation you've linked, and then bind this property in your XAML for the control (so that the above property is reflected in the control interface), for the TextBlock*:

Text="{Binding $parent[UserControl].Caption}"

and when using SectionHeader:

<controls:SectionHeader Caption="Hello, World!" />
<controls:SectionHeader Caption="{Binding Whatever.SectionCaption}" />
<controls:SectionHeader Caption="{DynamicResource LocalisedSectionCaption}" />

Again, you're not using any of the power of a UserControl, but I'd say there's nothing wrong with using one here.

When accessing named controls, consider adding a reference to XamlNameReferenceGenerator: if you're using .NET7+ it'll use a source-generator to generate fields for your named controls, so you don't have to find them by name (this makes the code cleaner, quicker to write and harder to get wrong or later break)

* $parent[UserControl] is one way to access the properties of the UserControl, rather than it's DataContext: see https://docs.avaloniaui.net/docs/data-binding/binding-to-controls for more information

\$\endgroup\$
1
  • \$\begingroup\$ Thank you very much, @VisualMelon. That makes perfect sense and has some very good extension points for my XAML/Avalonia learning path. Much appreciated! \$\endgroup\$ Feb 5, 2023 at 11:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.