{"id":40800,"date":"2022-07-14T09:43:36","date_gmt":"2022-07-14T16:43:36","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=40800"},"modified":"2022-07-25T17:14:07","modified_gmt":"2022-07-26T00:14:07","slug":"customizing-dotnet-maui-controls","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/customizing-dotnet-maui-controls\/","title":{"rendered":"Customizing Controls in .NET MAUI"},"content":{"rendered":"<blockquote><p><strong>Note:<\/strong> This is a Guest Blog Post by Microsoft MVP, <a href=\"https:\/\/twitter.com\/pj_souz\">Pedro Jesus<\/a>. Pedro works as a Software Engineer at <a href=\"https:\/\/www.nareia.com.uy\/\">Nareia<\/a> and is a core maintainer of the <a href=\"https:\/\/github.com\/CommunityToolkit\/Maui\">.NET MAUI Community Toolkit<\/a><\/p><\/blockquote>\n<p>Today, I want to talk about and show you the ways that you can completely customize controls in <a href=\"https:\/\/dot.net\/maui\" target=\"_blank\" rel=\"noopener\">.NET MAUI<\/a>. Before looking at .NET MAUI let&#8217;s move back a couple years, back to the <a href=\"https:\/\/docs.microsoft.com\/xamarin\/xamarin-forms\/?WT.mc_id=dotnet-0000-bramin\">Xamarin.Forms<\/a> era. Back then, we had a couple of ways to customize controls: We had <a href=\"https:\/\/docs.microsoft.com\/xamarin\/xamarin-forms\/app-fundamentals\/behaviors\/?WT.mc_id=dotnet-0000-bramin\"><code>Behaviors<\/code><\/a> that are used when you don&#8217;t need to access the platform-specific APIs in order to customize controls; and we had <a href=\"https:\/\/docs.microsoft.com\/xamarin\/xamarin-forms\/app-fundamentals\/effects\/introduction?WT.mc_id=dotnet-0000-bramin\"><code>Effects<\/code><\/a> if you need to access the platform-specific APIs.<\/p>\n<p>Let&#8217;s focus a little bit on the <a href=\"https:\/\/docs.microsoft.com\/xamarin\/xamarin-forms\/app-fundamentals\/effects\/introduction?WT.mc_id=dotnet-0000-bramin\"><code>Effects<\/code><\/a> API. It was created due to Xamarin&#8217;s lack of multi-target architecture. That means we can&#8217;t access platform-specific code at the shared level (in the .NET Standard <code>csproj<\/code>). It worked pretty well and can save you from creating <a href=\"https:\/\/docs.microsoft.com\/xamarin\/xamarin-forms\/app-fundamentals\/custom-renderer\/?WT.mc_id=dotnet-0000-bramin\">Custom Renderers<\/a>.<\/p>\n<p>Today, in .NET MAUI, we can leverage the power of the multi-target architecture and access the platform-specific APIs in our shared project. So do we still need <code>Effects<\/code>? No, because we have access to all code and APIs from all platforms that we target.<\/p>\n<p>So let&#8217;s talk about all the possibilities to customize a control in .NET MAUI and some dragons that you may found in the way. For this, we&#8217;ll be customizing the <code>Image<\/code> control adding the ability to tint the image presented.<\/p>\n<blockquote><p><strong>Note:<\/strong> .NET MAUI still supports <code>Effects<\/code> if you want to use it, however it is not recommended<\/p><\/blockquote>\n<p>Source code reference comes from .NET MAUI Community Toolkit&#8217;s <a href=\"https:\/\/github.com\/CommunityToolkit\/Maui\/tree\/main\/src\/CommunityToolkit.Maui\/Behaviors\/PlatformBehaviors\/IconTintColor\">IconTintColor<\/a>.<\/p>\n<h2>Customizing an Existing Control<\/h2>\n<p>To add additional features to an existing control, we extend it and add the features that we need.<\/p>\n<p>Let&#8217;s create a new control, <code>class ImageTintColor : Image<\/code> and add a new <code>BindableProperty<\/code> that we will leverage to change the tint color of the <code>Image<\/code>.<\/p>\n<pre><code class=\"language-csharp\">public class ImageTintColor : Image\r\n{\r\n    public static readonly BindableProperty TintColorProperty =\r\n        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(ImageTintColor), propertyChanged: OnTintColorChanged);\r\n\r\n    public Color? TintColor\r\n    {\r\n        get =&gt; (Color?)GetValue(TintColorProperty);\r\n        set =&gt; SetValue(TintColorProperty, value);\r\n    }\r\n\r\n    static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue)\r\n    {\r\n        \/\/ ...\r\n    }\r\n}<\/code><\/pre>\n<p>Folks familiar with Xamarin.Forms will recognize this; it&#8217;s pretty much the same code that you will write in a Xamarin.Forms application.<\/p>\n<p>The .NET MAUI platform-specific API work will happen on the <code>OnTintColorChanged<\/code> delegate. Let&#8217;s take a look at it.<\/p>\n<pre><code class=\"language-csharp\">public class ImageTintColor : Image\r\n{\r\n    public static readonly BindableProperty TintColorProperty =\r\n        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(ImageTintColor), propertyChanged: OnTintColorChanged);\r\n\r\n    public Color? TintColor\r\n    {\r\n        get =&gt; (Color?)GetValue(TintColorProperty);\r\n        set =&gt; SetValue(TintColorProperty, value);\r\n    }\r\n\r\n    static void OnTintColorChanged(BindableObject bindable, object oldValue, object newValue)\r\n    {\r\n        var control = (ImageTintColor)bindable;\r\n        var tintColor = control.TintColor;\r\n\r\n        if (control.Handler is null || control.Handler.PlatformView is null)\r\n        {\r\n            \/\/ Workaround for when this executes the Handler and PlatformView is null\r\n            control.HandlerChanged += OnHandlerChanged;\r\n            return;\r\n        }\r\n\r\n        if (tintColor is not null)\r\n        {\r\n#if ANDROID\r\n            \/\/ Note the use of Android.Widget.ImageView which is an Android-specific API\r\n            \/\/ You can find the Android implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L9-L12\r\n            ImageExtensions.ApplyColor((Android.Widget.ImageView)control.Handler.PlatformView, tintColor);\r\n#elif IOS\r\n            \/\/ Note the use of UIKit.UIImage which is an iOS-specific API\r\n            \/\/ You can find the iOS implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L7-L11\r\n            ImageExtensions.ApplyColor((UIKit.UIImageView)control.Handler.PlatformView, tintColor);\r\n#endif\r\n        }\r\n        else\r\n        {\r\n#if ANDROID\r\n            \/\/ Note the use of Android.Widget.ImageView which is an Android-specific API\r\n            \/\/ You can find the Android implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L14-L17\r\n            ImageExtensions.ClearColor((Android.Widget.ImageView)control.Handler.PlatformView);\r\n#elif IOS\r\n            \/\/ Note the use of UIKit.UIImage which is an iOS-specific API\r\n            \/\/ You can find the iOS implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L13-L16\r\n            ImageExtensions.ClearColor((UIKit.UIImageView)control.Handler.PlatformView);\r\n#endif\r\n        }\r\n\r\n        void OnHandlerChanged(object s, EventArgs e)\r\n        {\r\n            OnTintColorChanged(control, oldValue, newValue);\r\n            control.HandlerChanged -= OnHandlerChanged;\r\n        }\r\n    }\r\n}<\/code><\/pre>\n<p>Because .NET MAUI uses multi-targeting, we can access the platform specifics and customize the control the way that we want. The <code>ImageExtensions.ApplyColor<\/code> and <code>ImageExtensions.ClearColor<\/code> methods are helper methods that will add or remove the tint from the image.<\/p>\n<p>One thing that you maybe noticed is the <code>null<\/code> check for <code>Handler<\/code> and <code>PlatformView<\/code>. This is the first dragon that you may find on your way. When the <code>Image<\/code> control is created and instantiated and the <code>PropertyChanged<\/code> delegate of the <code>BindableProperty<\/code> is called, the <code>Handler<\/code> can be <code>null<\/code>. So, without that null check, the code will throw a <code>NullReferenceException<\/code>. This may sound like a bug, but it&#8217;s actually a feature! This allows the .NET MAUI engineering team to keep the same lifecycle that controls have on Xamarin.Forms, avoiding some breaking changes for applications that will migrate from Forms to .NET MAUI.<\/p>\n<p>Now that we have everything set up, we can use our control in our <code>ContentPage<\/code>. In the snippet below you can see how to use it in XAML:<\/p>\n<pre><code class=\"language-xml\">&lt;ContentPage x:Class=\"MyMauiApp.ImageControl\"\r\n             xmlns=\"http:\/\/schemas.microsoft.com\/dotnet\/2021\/maui\"\r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2009\/xaml\"\r\n             xmlns:local=\"clr-namespace:MyMauiApp\"\r\n             Title=\"ImageControl\"\r\n             BackgroundColor=\"White\"&gt;\r\n\r\n            &lt;local:ImageTintColor x:Name=\"ImageTintColorControl\"\r\n                                  Source=\"shield.png\"\r\n                                  TintColor=\"Orange\" \/&gt;\r\n&lt;\/ContentPage&gt;<\/code><\/pre>\n<h2>Using Attached Property and PropertyMapper<\/h2>\n<p>Another way to customize a control is using <code>AttachedProperties<\/code>, it&#8217;s a flavor of <code>BindableProperty<\/code> when you don&#8217;t need to have it tied to a specific custom control.<\/p>\n<p>Here&#8217;s how we can create an AttachedProperty for TintColor:<\/p>\n<pre><code class=\"language-csharp\">public static class TintColorMapper\r\n{\r\n    public static readonly BindableProperty TintColorProperty = BindableProperty.CreateAttached(\"TintColor\", typeof(Color), typeof(Image), null);\r\n\r\n    public static Color GetTintColor(BindableObject view) =&gt; (Color)view.GetValue(TintColorProperty);\r\n\r\n    public static void SetTintColor(BindableObject view, Color? value) =&gt; view.SetValue(TintColorProperty, value);\r\n\r\n    public static void ApplyTintColor()\r\n    {\r\n        \/\/ ...\r\n    }\r\n}<\/code><\/pre>\n<p>Again we have the boilerplate that we have on Xamarin.Forms for the <code>AttachedProperty<\/code>, but as you can see we don&#8217;t have the <code>PropertyChanged<\/code> delegate. In order to handle the property change, we will use the <code>Mapper<\/code> in the <code>ImageHandler<\/code>. You add the Mapper at any level, since the members are <code>static<\/code>. I choose to do it inside the <code>TintColorMapper<\/code> class, as you can see below.<\/p>\n<pre><code class=\"language-csharp\">public static class TintColorMapper\r\n{\r\n     public static readonly BindableProperty TintColorProperty = BindableProperty.CreateAttached(\"TintColor\", typeof(Color), typeof(Image), null);\r\n\r\n    public static Color GetTintColor(BindableObject view) =&gt; (Color)view.GetValue(TintColorProperty);\r\n\r\n    public static void SetTintColor(BindableObject view, Color? value) =&gt; view.SetValue(TintColorProperty, value);\r\n\r\n    public static void ApplyTintColor()\r\n    {\r\n        ImageHandler.Mapper.Add(\"TintColor\", (handler, view) =&gt;\r\n        {\r\n            var tintColor = GetTintColor((Image)handler.VirtualView);\r\n\r\n            if (tintColor is not null)\r\n            {\r\n#if ANDROID\r\n                \/\/ Note the use of Android.Widget.ImageView which is an Android-specific API\r\n                \/\/ You can find the Android implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L9-L12\r\n                ImageExtensions.ApplyColor((Android.Widget.ImageView)control.Handler.PlatformView, tintColor);\r\n#elif IOS\r\n                \/\/ Note the use of UIKit.UIImage which is an iOS-specific API\r\n                \/\/ You can find the iOS implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L7-L11\r\n                ImageExtensions.ApplyColor((UIKit.UIImageView)handler.PlatformView, tintColor);\r\n#endif\r\n            }\r\n            else\r\n            {\r\n#if ANDROID\r\n                \/\/ Note the use of Android.Widget.ImageView which is an Android-specific API\r\n                \/\/ You can find the Android implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L14-L17\r\n                ImageExtensions.ClearColor((Android.Widget.ImageView)handler.PlatformView);\r\n#elif IOS\r\n                \/\/ Note the use of UIKit.UIImage which is an iOS-specific API\r\n                \/\/ You can find the iOS implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L13-L16\r\n                ImageExtensions.ClearColor((UIKit.UIImageView)handler.PlatformView);\r\n#endif\r\n            }\r\n        });\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>The code is pretty much the same as showed before, just implemented using another API, in this case the <code>AppendToMapping<\/code> method. If you don&#8217;t want this behavior, use the <code>CommandMapper<\/code> instead, it will be triggered just when a property changed or an action happens.<\/p>\n<p>Be aware that when we handle with <code>Mapper<\/code> and <code>CommandMapper<\/code>, we&#8217;re adding this behavior for all controls that use that handler in the project. In this case all <code>Image<\/code> controls will trigger this code. In some cases this isn&#8217;t what you want, if you something more specific the next way, using <code>PlatformBehavior<\/code> will fit perfectly.<\/p>\n<p>So, now that we have everything set up, we can use our control in our page, at the snippet below you can see how to use it in XAML.<\/p>\n<pre><code class=\"language-xml\">&lt;ContentPage x:Class=\"MyMauiApp.ImageControl\"\r\n             xmlns=\"http:\/\/schemas.microsoft.com\/dotnet\/2021\/maui\"\r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2009\/xaml\"\r\n             xmlns:local=\"clr-namespace:MyMauiApp\"\r\n             Title=\"ImageControl\"\r\n             BackgroundColor=\"White\"&gt;\r\n\r\n            &lt;Image x:Name=\"Image\"\r\n                   local:TintColorMapper.TintColor=\"Fuchsia\"\r\n                   Source=\"shield.png\" \/&gt;\r\n&lt;\/ContentPage&gt;<\/code><\/pre>\n<h2>Using PlatformBehavior<\/h2>\n<p><code>PlatformBehavior<\/code> is a new API created on .NET MAUI to make easier the task to customize controls when you need to access the platform-specifics APIs in safe way (safe because it ensures that the <code>Handler<\/code> and <code>PlatformView<\/code> aren&#8217;t <code>null<\/code>). It has two methods to <code>override<\/code>: <code>OnAttachedTo<\/code> and <code>OnDetachedFrom<\/code>. This API exists to replace the <code>Effect<\/code> API from Xamarin.Forms and to take advantage of the multi-target architecture.<\/p>\n<p>In this example, we will use <code>partial class<\/code> to implement the platform-specific APIs:<\/p>\n<pre><code class=\"language-csharp\">\/\/FileName : ImageTintColorBehavior.cs\r\n\r\npublic partial class IconTintColorBehavior \r\n{\r\n    public static readonly BindableProperty TintColorProperty =\r\n        BindableProperty.Create(nameof(TintColor), typeof(Color), typeof(IconTintColorBehavior), propertyChanged: OnTintColorChanged);\r\n\r\n    public Color? TintColor\r\n    {\r\n        get =&gt; (Color?)GetValue(TintColorProperty);\r\n        set =&gt; SetValue(TintColorProperty, value);\r\n    }\r\n}<\/code><\/pre>\n<p>The above code will be compiled by all platforms that we target.<\/p>\n<p>Now let&#8217;s see the code for the <code>Android<\/code> platform:<\/p>\n<pre><code class=\"language-csharp\">\/\/FileName: ImageTintColorBehavior.android.cs\r\n\r\npublic partial class IconTintColorBehavior : PlatformBehavior&lt;Image, ImageView&gt; \/\/ Note the use of ImageView which is an Android-specific API\r\n{\r\n    protected override void OnAttachedTo(Image bindable, ImageView platformView) =&gt;\r\n        ImageExtensions.ApplyColor(bindable, platformView); \/\/ You can find the Android implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L9-L12\r\n\r\n    protected override void OnDetachedFrom(Image bindable, ImageView platformView) =&gt;\r\n        ImageExtensions.ClearColor(platformView); \/\/ You can find the Android implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.android.cs#L14-L17\r\n}<\/code><\/pre>\n<p>And here&#8217;s the code for the <code>iOS<\/code> platform:<\/p>\n<pre><code class=\"language-csharp\">\/\/FileName: ImageTintColorBehavior.ios.cs\r\n\r\npublic partial class IconTintColorBehavior : PlatformBehavior&lt;Image, UIImageView&gt; \/\/ Note the use of UIImageView which is an iOS-specific API\r\n{\r\n    protected override void OnAttachedTo(Image bindable, UIImageView platformView) =&gt; \r\n        ImageExtensions.ApplyColor(bindable, platformView); \/\/ You can find the iOS implementation of `ApplyColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L7-L11\r\n\r\n    protected override void OnDetachedFrom(Image bindable, UIImageView platformView) =&gt; \r\n        ImageExtensions.ClearColor(platformView); \/\/ You can find the iOS implementation of `ClearColor` here: https:\/\/github.com\/pictos\/MFCC\/blob\/1ef490e507385e050b0cfb6e4f5d68f0cb0b2f60\/MFCC\/TintColorExtension.ios.cs#L13-L16\r\n}<\/code><\/pre>\n<p>As you can see, we don&#8217;t need to care about if the <code>Handler<\/code> is <code>null<\/code>, because that&#8217;s handled for us by <code>PlatformBehavior&lt;T, U&gt;<\/code>.<\/p>\n<p>We can specify the type of platform-specific API that this Behavior covers. If you want to apply the control for more than one type, you don&#8217;t need to specify the type of the platform view (e.g. use <code>PlatformBehavior&lt;T&gt;<\/code>); you probably want to apply your <code>Behavior<\/code> in more than one control, in that case the platformView will be an <code>PlatformBehavior&lt;View&gt;<\/code> on <code>Android<\/code> and an <code>PlatformBehavior&lt;UIView&gt;<\/code> on <code>iOS<\/code>.<\/p>\n<p>And the usage is even better, you just need to call the <code>Behavior<\/code>:<\/p>\n<pre><code class=\"language-XML\">&lt;ContentPage x:Class=\"MyMauiApp.ImageControl\"\r\n             xmlns=\"http:\/\/schemas.microsoft.com\/dotnet\/2021\/maui\"\r\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2009\/xaml\"\r\n             xmlns:local=\"clr-namespace:MyMauiApp\"\r\n             Title=\"ImageControl\"\r\n             BackgroundColor=\"White\"&gt;\r\n\r\n            &lt;Image x:Name=\"Image\"\r\n                   Source=\"shield.png\"&gt;\r\n                &lt;Image.Behaviors&gt;\r\n                    &lt;local:IconTintColorBehavior TintColor=\"Fuchsia\"&gt;\r\n                &lt;\/Image.Behaviors&gt;\r\n            &lt;\/Image&gt;\r\n&lt;\/ContentPage&gt;<\/code><\/pre>\n<blockquote><p><strong>Note:<\/strong> The <code>PlatformBehavior<\/code> will call the <code>OnDetachedFrom<\/code> when the <code>Handler<\/code> disconnect from the <code>VirtualView<\/code>, in other words, when the <code>Unloaded<\/code> event is fired. The <code>Behavior<\/code> API doesn&#8217;t call the <code>OnDetachedFrom<\/code> method automatically, you as a developer needs to handle it by yourself.<\/p><\/blockquote>\n<h2>Conclusion<\/h2>\n<p>In this blog post we discussed various ways to customize your controls and interact with the platform-specific APIs. There&#8217;s no <code>right<\/code> or <code>wrong<\/code> way, all those are valid solutions, you just need to see which will suit better to your case. I would say that for most cases you want to use the <code>PlatformBehavior<\/code> since it&#8217;s designed to work with the multi-target approach and makes sure to clean-up the resources when the control is not used anymore. To learn more, check out the <a href=\"https:\/\/docs.microsoft.com\/dotnet\/maui\/user-interface\/handlers\/customize\">documentation on custom controls<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let&#8217;s look at how to customize .NET MAUI controls.<\/p>\n","protected":false},"author":94871,"featured_media":40801,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233],"tags":[7238,7359,7652,7548,7653],"class_list":["post-40800","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","tag-net-maui","tag-controls","tag-customization","tag-ui","tag-user-interface"],"acf":[],"blog_post_summary":"<p>Let&#8217;s look at how to customize .NET MAUI controls.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/40800","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/94871"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=40800"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/40800\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/40801"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=40800"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=40800"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=40800"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}