diff --git a/docs/guides/custom-controls/defining-properties.md b/docs/guides/custom-controls/defining-properties.md index 6e1ce5074..76bf92562 100644 --- a/docs/guides/custom-controls/defining-properties.md +++ b/docs/guides/custom-controls/defining-properties.md @@ -20,21 +20,39 @@ On this page, you will see how to implement a property so that it can be changed ### Register a Styled Property -You register a styled property by defining a static read-only field and using the `AvaloniaProperty.Register` method. +You register a styled property by defining a `public static read-only` field of type `StyledProperty` and set it's value using the `AvaloniaProperty.Register` method. -There is a convention for the name of a property. It must follow the pattern: +:::warning +The name of this static field **MUST** be the same name as the public attribute, followed by "`Property`" at the end. +Failure to follow this naming convention may result in "*Unable to find suitable setter or adder for property*" errors during compilation. +::: -``` -[AttributeName]Property -``` +### Styled Property Register Example -This means that _Avalonia UI_ will look for an attribute in the XAML, like this: +```csharp +public static readonly StyledProperty ExampleProperty = + AvaloniaProperty.Register(nameof(Example), "Default value here"); +public string Example +{ + get => GetValue(ExampleProperty); + set => SetValue(ExampleProperty, value); +} ``` - + +:::info +Note that the getter/setter of the public property uses the special Avalonia UI `GetValue` and `SetValue` methods and should not be changed to something else nor do any extra work inside of the get/set. +::: + +Then, _Avalonia UI_ will look for an attribute in the XAML, like this: + +```xml + ``` -For example, with a styled property in place, you can control the background color of the custom control from the window styles collection: +### Styled property in a custom control example + +With a styled property in place, you can control the background color of the custom control from the window styles collection: ```xml title='MainWindow.axaml' :::info For more advanced information about how to create a custom control, see [here](../custom-controls/how-to-create-advanced-custom-controls.md). + +For info on how to bind to these properties on a user control, see [here](./how-to-create-a-user-control.md) ::: diff --git a/docs/guides/custom-controls/how-to-create-a-user-control.md b/docs/guides/custom-controls/how-to-create-a-user-control.md new file mode 100644 index 000000000..516e19164 --- /dev/null +++ b/docs/guides/custom-controls/how-to-create-a-user-control.md @@ -0,0 +1,120 @@ +--- +id: how-to-create-a-user-control +title: How To Create a User Control +--- + +import ExampleUserControlScreenshot from '/img/guides/custom-controls/how-to-uc-example.png'; + +# How To Create a User Control + +UserControls are one of the [types of controls](./types-of-control.md) available for authoring custom controls, User Controls being the simplest way to do so. This type of control is best for big "views" or "pages", but also very good for creating smaller modular controls that can be sprinkled throughout the UI. + +UserControls are authored in the same way as you would author a Window: by creating a new UserControl from a template and then adding controls to it. + +### Binding data + +Then there are two common ways to bind data on your User Control: + +For "big" User Controls that need business logic, like a full "view" for a tab, it's recommended to follow the [MVVM pattern](../../concepts/the-mvvm-pattern/index.md) and create a ViewModel for that specific User Control. + +For smaller User Controls that does not require any business logic, like a "welcome badge" for the user, a simple way to bind data is to create some custom [Styled Properties](./defining-properties.md) on the code-behind and Bind the controls attributes to it. This makes the User Control "modular" and able to bind to many different use cases as needed. + +### Example User Control + +Here's an example on how to make a small UserControl and Bind the Attributes to the Styled Properties defined on the code-behind: + +1. Create a `UserControls` folder +2. Inside of it add a new *Avalonia User Control*, call it `GreetingCard` +3. In the `GreetingCard.axaml.cs` (code-behind), define the Styled Properties needed. + +:::info +It is **NOT** recommended to put *any* business logic in here, if needed use a ViewModel instead. These should be kept as simple "data pass-through" properties. +::: + +:::info +Note that the getter/setter of the public property uses the special Avalonia UI `GetValue` and `SetValue` methods and should not be changed to something else nor do any extra work inside of the get/set. +::: + +```csharp title='UserGreetingCard.axaml.cs (Code Behind)' +using Avalonia; +using Avalonia.Controls; +using Avalonia.Media; + +namespace Example.UserControls; + +public partial class GreetingCard : UserControl +{ + public GreetingCard() + { + InitializeComponent(); + AffectsRender(UserNameProperty, UserPictureProperty); + } + + public static readonly StyledProperty UserNameProperty = + AvaloniaProperty.Register(nameof(UserName),"Unknown"); + + public string UserName + { + get => GetValue(UserNameProperty); + set => SetValue(UserNameProperty, value); + } + + public static readonly StyledProperty UserPictureProperty = + AvaloniaProperty.Register(nameof(UserPicture)); + + public IImage? UserPicture + { + get => GetValue(UserPictureProperty); + set => SetValue(UserPictureProperty, value); + } +} +``` + +4. In the `GreetingCard.axaml`, define how the User Control will look. +5. Inside the `UserControl` main tag, define a name in the `x:Name` attribute. This name will be used for the Data Binding. +6. In the controls that need access to the code-behind styled properties, Bind them using the [Data Binding Short Hand Syntax](../../basics/data/data-binding/data-binding-syntax.md#data-binding-sources) `#ParentXName.Property` + +```xml title='UserGreetingCard.axaml' + + + + + + + + + + + +``` + +8. In the `MainWindow.axaml` file, Import the User Controls [xml namespace](../../basics/user-interface/introduction-to-xaml.md#xml-namespaces) as `xmlns:uc` +9. Add the new GreetingCard User Control tag by specifying the namespace:ControlName, in this case it's `uc:GreetingCard`. +10. Now the Attributes defined previously can be set directly or be defined by a Binding. + +```xml title='MainWindow.axaml' + + + + + + +``` + +This is the result of the example: + \ No newline at end of file diff --git a/docs/guides/custom-controls/how-to-create-templated-controls.md b/docs/guides/custom-controls/how-to-create-templated-controls.md index b6f29c542..2f016d46a 100644 --- a/docs/guides/custom-controls/how-to-create-templated-controls.md +++ b/docs/guides/custom-controls/how-to-create-templated-controls.md @@ -6,6 +6,8 @@ title: How To Create Templated Controls # How To Create Templated Controls +Templated Controls are one of the [types of controls](./types-of-control.md) available for authoring custom controls.They are lookless controls, meaning that they can be restyled for different themes and applications. + ## Data Binding When you're creating a control template and you want to bind to the templated parent you can use: diff --git a/docs/guides/custom-controls/index.md b/docs/guides/custom-controls/index.md index 3f3144cc6..2f191d28c 100644 --- a/docs/guides/custom-controls/index.md +++ b/docs/guides/custom-controls/index.md @@ -14,6 +14,8 @@ Before you start to create your own control, you must decide which type of custo ### Custom Control +Basic Controls are one of the [types of controls](./types-of-control.md) available for authoring custom controls. + A custom control draws itself using the _Avalonia UI_ graphics system, using basic methods for shapes, lines, fills, text, and many others. You can define your own properties, events and pseudo classes. Some of the _Avalonia UI_ built-in controls are like this. For example, the text block control (`TextBlock` class) and the image control (`Image` class). diff --git a/docs/guides/custom-controls/types-of-control.md b/docs/guides/custom-controls/types-of-control.md index f4d8c265b..8c4dfade0 100644 --- a/docs/guides/custom-controls/types-of-control.md +++ b/docs/guides/custom-controls/types-of-control.md @@ -7,11 +7,11 @@ If you want to create your own controls, there are three main categories of cont ### User Controls -UserControls are the simplest way to author controls. This type of control is best for "views" or "pages" that are specific to an application. UserControls are authored in the same way as you would author a Window: by creating a new UserControl from a template and adding controls to it. +[UserControls](./how-to-create-a-user-control.md) are the simplest way to author controls. This type of control is best for big "views" and "pages" or smaller simple controls, like "badges" or "notifications". UserControls are authored in the same way as you would author a Window: by creating a new UserControl from a template and adding controls to it. ### Templated Controls -TemplatedControls are best used for generic controls that can be shared among various applications. They are lookless controls, meaning that they can be restyled for different themes and applications. The majority of standard controls defined by Avalonia fit into this category. +[TemplatedControls](./how-to-create-templated-controls.md) are best used for generic controls that can be shared among various applications. They are lookless controls, meaning that they can be restyled for different themes and applications. The majority of standard controls defined by Avalonia fit into this category. :::info In WPF/UWP you would inherit from the Control class to create a new templated control, but in Avalonia you should inherit from TemplatedControl. @@ -23,7 +23,7 @@ If you want to provide a Style for your TemplatedControl in a separate file, rem ### Basic Controls -Basic Controls are the foundation of user interfaces - they draw themselves using geometry by overriding the Visual.Render method. Controls such as TextBlock and Image fall into this category. +[Basic Controls](./index.md) are the foundation of user interfaces - they draw themselves using geometry by overriding the Visual.Render method. Controls such as TextBlock and Image fall into this category. :::info In WPF/UWP you would inherit from the FrameworkElement class to create a new basic control, but in Avalonia you should inherit from Control. diff --git a/sidebars.js b/sidebars.js index 0d9f424fe..d55b9a78c 100644 --- a/sidebars.js +++ b/sidebars.js @@ -326,6 +326,7 @@ const sidebars = { 'guides/custom-controls/create-a-custom-panel', 'guides/custom-controls/defining-properties', 'guides/custom-controls/draw-with-a-property', + 'guides/custom-controls/how-to-create-a-user-control', 'guides/custom-controls/how-to-create-a-custom-controls-library', 'guides/custom-controls/how-to-create-a-custom-flyout', 'guides/custom-controls/how-to-create-advanced-custom-controls', diff --git a/static/img/guides/custom-controls/how-to-uc-example.png b/static/img/guides/custom-controls/how-to-uc-example.png new file mode 100644 index 000000000..5098eb69e Binary files /dev/null and b/static/img/guides/custom-controls/how-to-uc-example.png differ