diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index efb8ea4cc5..5c2d228e62 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -34,6 +34,7 @@
+
diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
new file mode 100644
index 0000000000..45fece49e5
--- /dev/null
+++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/DynamicResourceExtension.cs
@@ -0,0 +1,41 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using Avalonia.Controls;
+using Avalonia.Data;
+using Portable.Xaml.Markup;
+
+namespace Avalonia.Markup.Xaml.MarkupExtensions
+{
+ public class DynamicResourceExtension : MarkupExtension, IBinding
+ {
+ public DynamicResourceExtension()
+ {
+ }
+
+ public DynamicResourceExtension(string resourceKey)
+ {
+ ResourceKey = resourceKey;
+ }
+
+ public string ResourceKey { get; set; }
+
+ public override object ProvideValue(IServiceProvider serviceProvider) => this;
+
+ InstancedBinding IBinding.Initiate(
+ IAvaloniaObject target,
+ AvaloniaProperty targetProperty,
+ object anchor,
+ bool enableDataValidation)
+ {
+ if (target is IControl control)
+ {
+ var resource = control.FindResource(ResourceKey);
+ return new InstancedBinding(resource);
+ }
+
+ return null;
+ }
+ }
+}
diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceTests.cs
new file mode 100644
index 0000000000..70c45c3e7f
--- /dev/null
+++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/DynamicResourceTests.cs
@@ -0,0 +1,285 @@
+// Copyright (c) The Avalonia Project. All rights reserved.
+// Licensed under the MIT license. See licence.md file in the project root for full license information.
+
+using System;
+using System.Linq;
+using Avalonia.Controls;
+using Avalonia.Controls.Presenters;
+using Avalonia.Controls.Templates;
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.Media;
+using Avalonia.Styling;
+using Avalonia.UnitTests;
+using Avalonia.VisualTree;
+using Xunit;
+
+namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
+{
+ public class DynamicResourceTests
+ {
+ [Fact]
+ public void DynamicResource_Can_Be_Assigned_To_Property()
+ {
+ var xaml = @"
+
+
+ #ff506070
+
+
+
+";
+
+ var loader = new AvaloniaXamlLoader();
+ var userControl = (UserControl)loader.Load(xaml);
+ var border = userControl.FindControl("border");
+
+ DelayedBinding.ApplyBindings(border);
+
+ var brush = (SolidColorBrush)border.Background;
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
+
+ [Fact]
+ public void DynamicResource_From_Style_Can_Be_Assigned_To_Property()
+ {
+ var xaml = @"
+
+
+
+
+
+
+";
+
+ var loader = new AvaloniaXamlLoader();
+ var userControl = (UserControl)loader.Load(xaml);
+ var border = userControl.FindControl("border");
+
+ DelayedBinding.ApplyBindings(border);
+
+ var brush = (SolidColorBrush)border.Background;
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
+
+ [Fact]
+ public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_Window()
+ {
+ using (StyledWindow())
+ {
+ Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
+
+ var xaml = @"
+
+
+";
+
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var border = window.FindControl("border");
+
+ var brush = (SolidColorBrush)border.Background;
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
+ }
+
+ [Fact]
+ public void DynamicResource_From_Application_Can_Be_Assigned_To_Property_In_UserControl()
+ {
+ using (UnitTestApplication.Start(TestServices.StyledWindow))
+ {
+ Application.Current.Resources.Add("brush", new SolidColorBrush(0xff506070));
+
+ var xaml = @"
+
+
+";
+
+ var loader = new AvaloniaXamlLoader();
+ var userControl = (UserControl)loader.Load(xaml);
+ var border = userControl.FindControl("border");
+
+ // We don't actually know where the global styles are until we attach the control
+ // to a window, as Window has StylingParent set to Application.
+ var window = new Window { Content = userControl };
+ window.Show();
+
+ var brush = (SolidColorBrush)border.Background;
+ Assert.Equal(0xff506070, brush.Color.ToUint32());
+ }
+ }
+
+ [Fact]
+ public void DynamicResource_Can_Be_Assigned_To_Setter()
+ {
+ using (StyledWindow())
+ {
+ var xaml = @"
+
+
+ #ff506070
+
+
+
+
+
+";
+
+ var loader = new AvaloniaXamlLoader();
+ var window = (Window)loader.Load(xaml);
+ var button = window.FindControl