diff --git a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
index c04b08de4d..88321ee1a3 100644
--- a/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/FuncTemplate`1.cs
@@ -2,6 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
+using Avalonia.Styling;
namespace Avalonia.Controls.Templates
{
@@ -34,5 +35,7 @@ namespace Avalonia.Controls.Templates
{
return _func();
}
+
+ object ITemplate.Build() => Build();
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Controls/Templates/ITemplate`1.cs b/src/Avalonia.Controls/Templates/ITemplate`1.cs
index 79c6ae47ba..2bf4b5a285 100644
--- a/src/Avalonia.Controls/Templates/ITemplate`1.cs
+++ b/src/Avalonia.Controls/Templates/ITemplate`1.cs
@@ -1,13 +1,15 @@
// 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 Avalonia.Styling;
+
namespace Avalonia.Controls
{
///
/// Creates a control.
///
/// The type of control.
- public interface ITemplate where TControl : IControl
+ public interface ITemplate : ITemplate where TControl : IControl
{
///
/// Creates the control.
@@ -15,6 +17,6 @@ namespace Avalonia.Controls
///
/// The created control.
///
- TControl Build();
+ new TControl Build();
}
}
\ No newline at end of file
diff --git a/src/Avalonia.Styling/Avalonia.Styling.csproj b/src/Avalonia.Styling/Avalonia.Styling.csproj
index d40627a16e..6a32441ad6 100644
--- a/src/Avalonia.Styling/Avalonia.Styling.csproj
+++ b/src/Avalonia.Styling/Avalonia.Styling.csproj
@@ -1,4 +1,4 @@
-
+
@@ -49,6 +49,7 @@
+
diff --git a/src/Avalonia.Styling/Styling/ITemplate.cs b/src/Avalonia.Styling/Styling/ITemplate.cs
new file mode 100644
index 0000000000..1593326e37
--- /dev/null
+++ b/src/Avalonia.Styling/Styling/ITemplate.cs
@@ -0,0 +1,10 @@
+// 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.
+
+namespace Avalonia.Styling
+{
+ public interface ITemplate
+ {
+ object Build();
+ }
+}
diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs
index 09faf37360..1d45f22b65 100644
--- a/src/Avalonia.Styling/Styling/Setter.cs
+++ b/src/Avalonia.Styling/Styling/Setter.cs
@@ -19,6 +19,8 @@ namespace Avalonia.Styling
///
public class Setter : ISetter
{
+ private object _value;
+
///
/// Initializes a new instance of the class.
///
@@ -54,8 +56,22 @@ namespace Avalonia.Styling
[DependsOn(nameof(Property))]
public object Value
{
- get;
- set;
+ get
+ {
+ return _value;
+ }
+
+ set
+ {
+ if (value is IStyleable)
+ {
+ throw new ArgumentException(
+ "Cannot assign a control to Style.Value. Wrap the control in a .",
+ "value");
+ }
+
+ _value = value;
+ }
}
///
@@ -75,17 +91,25 @@ namespace Avalonia.Styling
throw new InvalidOperationException("Setter.Property must be set.");
}
- var binding = Value as IBinding;
+ var value = Value;
+ var binding = value as IBinding;
if (binding == null)
{
+ var template = value as ITemplate;
+
+ if (template != null)
+ {
+ value = template.Build();
+ }
+
if (activator == null)
{
- return control.Bind(Property, ObservableEx.SingleValue(Value), BindingPriority.Style);
+ return control.Bind(Property, ObservableEx.SingleValue(value), BindingPriority.Style);
}
else
{
- var activated = new ActivatedValue(activator, Value, description);
+ var activated = new ActivatedValue(activator, value, description);
return control.Bind(Property, activated, BindingPriority.StyleTrigger);
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs
index a59e4231de..48309570cf 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/FocusAdornerTemplate.cs
@@ -3,17 +3,11 @@
using Avalonia.Controls;
using Avalonia.Metadata;
+using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.Templates
{
- public class FocusAdornerTemplate : ITemplate
+ public class FocusAdornerTemplate : Template
{
- [Content]
- public TemplateContent Content { get; set; }
-
- public IControl Build()
- {
- return Content.Load();
- }
}
}
\ No newline at end of file
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs
index d5811924f2..c4d19e5a6e 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs
@@ -1,11 +1,9 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
+// 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 Avalonia.Controls;
using Avalonia.Metadata;
+using Avalonia.Styling;
namespace Avalonia.Markup.Xaml.Templates
{
@@ -18,5 +16,7 @@ namespace Avalonia.Markup.Xaml.Templates
{
return (IPanel)Content.Load();
}
+
+ object ITemplate.Build() => Build();
}
}
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs
index 53edea6ce4..a34093037f 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs
@@ -1,10 +1,19 @@
// 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 Avalonia.Controls;
+using Avalonia.Metadata;
+using Avalonia.Styling;
+
namespace Avalonia.Markup.Xaml.Templates
{
- public class Template
+ public class Template : ITemplate
{
+ [Content]
public TemplateContent Content { get; set; }
+
+ public IControl Build() => Content.Load();
+
+ object ITemplate.Build() => Build();
}
}
\ No newline at end of file
diff --git a/tests/Avalonia.Styling.UnitTests/SetterTests.cs b/tests/Avalonia.Styling.UnitTests/SetterTests.cs
index 708be0a0a5..e6af3b2c0c 100644
--- a/tests/Avalonia.Styling.UnitTests/SetterTests.cs
+++ b/tests/Avalonia.Styling.UnitTests/SetterTests.cs
@@ -6,11 +6,21 @@ using Moq;
using Avalonia.Controls;
using Avalonia.Data;
using Xunit;
+using System;
+using Avalonia.Controls.Templates;
namespace Avalonia.Styling.UnitTests
{
public class SetterTests
{
+ [Fact]
+ public void Cannot_Assign_Control_To_Value()
+ {
+ var target = new Setter();
+
+ Assert.Throws(() => target.Value = new Border());
+ }
+
[Fact]
public void Setter_Should_Apply_Binding_To_Property()
{
@@ -25,5 +35,18 @@ namespace Avalonia.Styling.UnitTests
Assert.Equal("foo", control.Text);
}
+
+ [Fact]
+ public void Setter_Should_Materialize_Template_To_Property()
+ {
+ var control = new Decorator();
+ var template = new FuncTemplate