Browse Source

Merge branch 'master' into calendar-control

Steven Kirk 8 years ago
parent
commit
2bc31fce7d

+ 1 - 1
build/MonoMac.props

@@ -1,5 +1,5 @@
 <Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
   <ItemGroup>
-    <PackageReference Include="MonoMac.NetStandard" Version="0.0.3" />
+    <PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
   </ItemGroup>
 </Project>

+ 9 - 1
samples/ControlCatalog/Pages/CarouselPage.xaml

@@ -9,7 +9,7 @@
       </Button>
       <Carousel Name="carousel">
         <Carousel.Transition>
-          <PageSlide Duration="0.25"/>
+          <PageSlide Duration="0.25" Orientation="Vertical" />
         </Carousel.Transition>
         <Image Source="resm:ControlCatalog.Assets.delicate-arch-896885_640.jpg"/>
         <Image Source="resm:ControlCatalog.Assets.hirsch-899118_640.jpg"/>
@@ -28,6 +28,14 @@
         <DropDownItem>Crossfade</DropDownItem>
       </DropDown>
     </StackPanel>
+
+    <StackPanel Orientation="Horizontal" Gap="4">
+      <TextBlock VerticalAlignment="Center">Orientation</TextBlock>
+      <DropDown Name="orientation" SelectedIndex="1" VerticalAlignment="Center">
+        <DropDownItem>Horizontal</DropDownItem>
+        <DropDownItem>Vertical</DropDownItem>
+      </DropDown>
+    </StackPanel>
     
   </StackPanel>
 </UserControl>

+ 4 - 1
samples/ControlCatalog/Pages/CarouselPage.xaml.cs

@@ -11,6 +11,7 @@ namespace ControlCatalog.Pages
         private Button _left;
         private Button _right;
         private DropDown _transition;
+        private DropDown _orientation;
 
         public CarouselPage()
         {
@@ -18,6 +19,7 @@ namespace ControlCatalog.Pages
             _left.Click += (s, e) => _carousel.Previous();
             _right.Click += (s, e) => _carousel.Next();
             _transition.SelectionChanged += TransitionChanged;
+            _orientation.SelectionChanged += TransitionChanged;
         }
 
         private void InitializeComponent()
@@ -27,6 +29,7 @@ namespace ControlCatalog.Pages
             _left = this.FindControl<Button>("left");
             _right = this.FindControl<Button>("right");
             _transition = this.FindControl<DropDown>("transition");
+            _orientation = this.FindControl<DropDown>("orientation");
         }
 
         private void TransitionChanged(object sender, SelectionChangedEventArgs e)
@@ -37,7 +40,7 @@ namespace ControlCatalog.Pages
                     _carousel.Transition = null;
                     break;
                 case 1:
-                    _carousel.Transition = new PageSlide(TimeSpan.FromSeconds(0.25));
+                    _carousel.Transition = new PageSlide(TimeSpan.FromSeconds(0.25), _orientation.SelectedIndex == 0 ? PageSlide.SlideAxis.Horizontal : PageSlide.SlideAxis.Vertical);
                     break;
                 case 2:
                     _carousel.Transition = new CrossFade(TimeSpan.FromSeconds(0.25));

+ 19 - 6
samples/ControlCatalog/Pages/CheckBoxPage.xaml

@@ -1,15 +1,28 @@
-<UserControl xmlns="https://github.com/avaloniaui">
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <StackPanel Orientation="Vertical" Gap="4">
     <TextBlock Classes="h1">CheckBox</TextBlock>
     <TextBlock Classes="h2">A check box control</TextBlock>
 
-    <StackPanel Orientation="Vertical"
+    <StackPanel Orientation="Horizontal"
                 Margin="0,16,0,0"
                 HorizontalAlignment="Center"
                 Gap="16">
-      <CheckBox>Unchecked</CheckBox>
-      <CheckBox IsChecked="True">Checked</CheckBox>
-      <CheckBox IsChecked="True" IsEnabled="False">Disabled</CheckBox>
-    </StackPanel>    
+      <StackPanel Orientation="Vertical"
+                  Gap="16">
+        <CheckBox>Unchecked</CheckBox>
+        <CheckBox IsChecked="True">Checked</CheckBox>
+        <CheckBox IsChecked="{x:Null}">Indeterminate</CheckBox>
+        <CheckBox IsChecked="True" IsEnabled="False">Disabled</CheckBox>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  HorizontalAlignment="Center"
+                  Gap="16">
+        <CheckBox IsChecked="False" IsThreeState="True">Three State: Unchecked</CheckBox>
+        <CheckBox IsChecked="True" IsThreeState="True">Three State: Checked</CheckBox>
+        <CheckBox IsChecked="{x:Null}" IsThreeState="True">Three State: Indeterminate</CheckBox>
+        <CheckBox IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Three State: Disabled</CheckBox>
+      </StackPanel>
+    </StackPanel>
   </StackPanel>
 </UserControl>

+ 1 - 1
samples/ControlCatalog/Pages/DialogsPage.xaml.cs

@@ -36,7 +36,7 @@ namespace ControlCatalog.Pages
             };
         }
 
-        Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked ? (Window)this.VisualRoot : null;
+        Window GetWindow() => this.FindControl<CheckBox>("IsModal").IsChecked.Value ? (Window)this.VisualRoot : null;
 
         private void InitializeComponent()
         {

+ 18 - 6
samples/ControlCatalog/Pages/RadioButtonPage.xaml

@@ -1,15 +1,27 @@
-<UserControl xmlns="https://github.com/avaloniaui">
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
   <StackPanel Orientation="Vertical" Gap="4">
     <TextBlock Classes="h1">RadioButton</TextBlock>
     <TextBlock Classes="h2">Allows the selection of a single option of many</TextBlock>
 
-    <StackPanel Orientation="Vertical"
+    <StackPanel Orientation="Horizontal"
                 Margin="0,16,0,0"
                 HorizontalAlignment="Center"
                 Gap="16">
-      <RadioButton IsChecked="True">Option 1</RadioButton>
-      <RadioButton>Option 2</RadioButton>
-      <RadioButton IsEnabled="False">Disabled</RadioButton>
-    </StackPanel>    
+      <StackPanel Orientation="Vertical"
+                  Gap="16">
+        <RadioButton IsChecked="True">Option 1</RadioButton>
+        <RadioButton>Option 2</RadioButton>
+        <RadioButton IsChecked="{x:Null}">Option 3</RadioButton>
+        <RadioButton IsEnabled="False">Disabled</RadioButton>
+      </StackPanel>
+      <StackPanel Orientation="Vertical"
+                  Gap="16">
+        <RadioButton IsChecked="True" IsThreeState="True">Three States: Option 1</RadioButton>
+        <RadioButton IsChecked="False" IsThreeState="True">Three States: Option 2</RadioButton>
+        <RadioButton IsChecked="{x:Null}" IsThreeState="True">Three States: Option 3</RadioButton>
+        <RadioButton IsChecked="{x:Null}" IsThreeState="True" IsEnabled="False">Disabled</RadioButton>
+      </StackPanel>
+    </StackPanel>
   </StackPanel>
 </UserControl>

+ 1 - 1
src/Avalonia.Controls/Classes.cs

@@ -179,7 +179,7 @@ namespace Avalonia.Controls
             {
                 ThrowIfPseudoclass(name, "removed");
 
-                if (!Contains(name))
+                if (Contains(name))
                 {
                     c.Add(name);
                 }

+ 28 - 8
src/Avalonia.Controls/Primitives/ToggleButton.cs

@@ -9,26 +9,37 @@ namespace Avalonia.Controls.Primitives
 {
     public class ToggleButton : Button
     {
-        public static readonly DirectProperty<ToggleButton, bool> IsCheckedProperty =
-            AvaloniaProperty.RegisterDirect<ToggleButton, bool>(
-                "IsChecked",
+        public static readonly DirectProperty<ToggleButton, bool?> IsCheckedProperty =
+            AvaloniaProperty.RegisterDirect<ToggleButton, bool?>(
+                nameof(IsChecked),
                 o => o.IsChecked,
-                (o,v) => o.IsChecked = v,
+                (o, v) => o.IsChecked = v,
                 defaultBindingMode: BindingMode.TwoWay);
 
-        private bool _isChecked;
+        public static readonly StyledProperty<bool> IsThreeStateProperty =
+            AvaloniaProperty.Register<ToggleButton, bool>(nameof(IsThreeState));
+
+        private bool? _isChecked = false;
 
         static ToggleButton()
         {
-            PseudoClass(IsCheckedProperty, ":checked");
+            PseudoClass(IsCheckedProperty, c => c == true, ":checked");
+            PseudoClass(IsCheckedProperty, c => c == false, ":unchecked");
+            PseudoClass(IsCheckedProperty, c => c == null, ":indeterminate");
         }
 
-        public bool IsChecked
+        public bool? IsChecked
         {
             get { return _isChecked; }
             set { SetAndRaise(IsCheckedProperty, ref _isChecked, value); }
         }
 
+        public bool IsThreeState
+        {
+            get => GetValue(IsThreeStateProperty);
+            set => SetValue(IsThreeStateProperty, value);
+        }
+
         protected override void OnClick()
         {
             Toggle();
@@ -37,7 +48,16 @@ namespace Avalonia.Controls.Primitives
 
         protected virtual void Toggle()
         {
-            IsChecked = !IsChecked;
+            if (IsChecked.HasValue)
+                if (IsChecked.Value)
+                    if (IsThreeState)
+                        IsChecked = null;
+                    else
+                        IsChecked = false;
+                else
+                    IsChecked = true;
+            else
+                IsChecked = false;
         }
     }
 }

+ 5 - 4
src/Avalonia.Controls/RadioButton.cs

@@ -17,17 +17,17 @@ namespace Avalonia.Controls
 
         protected override void Toggle()
         {
-            if (!IsChecked)
+            if (!IsChecked.GetValueOrDefault())
             {
                 IsChecked = true;
             }
         }
 
-        private void IsCheckedChanged(bool value)
+        private void IsCheckedChanged(bool? value)
         {
             var parent = this.GetVisualParent();
 
-            if (value && parent != null)
+            if (value.GetValueOrDefault() && parent != null)
             {
                 var siblings = parent
                     .GetVisualChildren()
@@ -36,7 +36,8 @@ namespace Avalonia.Controls
 
                 foreach (var sibling in siblings)
                 {
-                    sibling.IsChecked = false;
+                    if (sibling.IsChecked.GetValueOrDefault())
+                        sibling.IsChecked = false;
                 }
             }
         }

+ 1 - 2
src/Avalonia.Remote.Protocol/BsonStreamTransport.cs

@@ -64,7 +64,6 @@ namespace Avalonia.Remote.Protocol
 
         async Task Reader()
         {
-            Task.Yield();
             try
             {
                 while (true)
@@ -147,4 +146,4 @@ namespace Avalonia.Remote.Protocol
         public event Action<IAvaloniaRemoteTransportConnection, object> OnMessage;
         public event Action<IAvaloniaRemoteTransportConnection, Exception> OnException;
     }
-}
+}

+ 1 - 1
src/Avalonia.Styling/Styling/Setter.cs

@@ -174,7 +174,7 @@ namespace Avalonia.Styling
             }
             else
             {
-                return sourceInstance.WithPriority(BindingPriority.StyleTrigger);
+                return sourceInstance.WithPriority(BindingPriority.Style);
             }
         }
     }

+ 23 - 8
src/Avalonia.Themes.Default/CheckBox.xaml

@@ -12,14 +12,23 @@
                   Width="18"
                   Height="18"
                   VerticalAlignment="Center">
-            <Path Name="checkMark"
-                  Fill="{DynamicResource HighlightBrush}"
-                  Width="11"
-                  Height="10"
-                  Stretch="Uniform"
-                  HorizontalAlignment="Center"
-                  VerticalAlignment="Center"
-                  Data="M 1145.607177734375,430 C1145.607177734375,430 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1138,434.5538330078125 1138,434.5538330078125 1138,434.5538330078125 1141.482177734375,438 1141.482177734375,438 1141.482177734375,438 1141.96875,437.9375 1141.96875,437.9375 1141.96875,437.9375 1147,431.34619140625 1147,431.34619140625 1147,431.34619140625 1145.607177734375,430 1145.607177734375,430 z"/>
+            <Panel>
+              <Path Name="checkMark"
+                    Fill="{DynamicResource HighlightBrush}"
+                    Width="11"
+                    Height="10"
+                    Stretch="Uniform"
+                    HorizontalAlignment="Center"
+                    VerticalAlignment="Center"
+                    Data="M 1145.607177734375,430 C1145.607177734375,430 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1141.449951171875,435.0772705078125 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1139.232177734375,433.0999755859375 1138,434.5538330078125 1138,434.5538330078125 1138,434.5538330078125 1141.482177734375,438 1141.482177734375,438 1141.482177734375,438 1141.96875,437.9375 1141.96875,437.9375 1141.96875,437.9375 1147,431.34619140625 1147,431.34619140625 1147,431.34619140625 1145.607177734375,430 1145.607177734375,430 z"/>
+              <Rectangle Name="indeterminateMark"
+                         Fill="{DynamicResource HighlightBrush}"
+                         Width="10"
+                         Height="10"
+                         Stretch="Uniform"
+                         HorizontalAlignment="Center"
+                         VerticalAlignment="Center"/>
+            </Panel>
           </Border>
           <ContentPresenter Name="PART_ContentPresenter"
                             Content="{TemplateBinding Content}"
@@ -37,9 +46,15 @@
   <Style Selector="CheckBox /template/ Path#checkMark">
     <Setter Property="IsVisible" Value="False"/>
   </Style>
+  <Style Selector="CheckBox /template/ Rectangle#indeterminateMark">
+    <Setter Property="IsVisible" Value="False"/>
+  </Style>
   <Style Selector="CheckBox:checked /template/ Path#checkMark">
     <Setter Property="IsVisible" Value="True"/>
   </Style>
+  <Style Selector="CheckBox:indeterminate /template/ Rectangle#indeterminateMark">
+    <Setter Property="IsVisible" Value="True"/>
+  </Style>
   <Style Selector="CheckBox:disabled /template/ Border#border">
     <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
   </Style>

+ 14 - 0
src/Avalonia.Themes.Default/RadioButton.xaml

@@ -20,6 +20,14 @@
                    UseLayoutRounding="False"
                    HorizontalAlignment="Center"
                    VerticalAlignment="Center"/>
+          <Ellipse Name="indeterminateMark"
+                   Fill="{DynamicResource ThemeAccentBrush}"
+                   Width="10"
+                   Height="10"
+                   Stretch="Uniform"
+                   UseLayoutRounding="False"
+                   HorizontalAlignment="Center"
+                   VerticalAlignment="Center"/>
           <ContentPresenter Name="PART_ContentPresenter"
                             Content="{TemplateBinding Content}"
                             ContentTemplate="{TemplateBinding ContentTemplate}"
@@ -36,9 +44,15 @@
   <Style Selector="RadioButton /template/ Ellipse#checkMark">
     <Setter Property="IsVisible" Value="False"/>
   </Style>
+  <Style Selector="RadioButton /template/ Ellipse#indeterminateMark">
+    <Setter Property="IsVisible" Value="False"/>
+  </Style>
   <Style Selector="RadioButton:checked /template/ Ellipse#checkMark">
     <Setter Property="IsVisible" Value="True"/>
   </Style>
+  <Style Selector="RadioButton:indeterminate /template/ Ellipse#indeterminateMark">
+    <Setter Property="IsVisible" Value="True"/>
+  </Style>
   <Style Selector="RadioButton:disabled /template/ Ellipse#border">
     <Setter Property="Opacity" Value="{DynamicResource ThemeDisabledOpacity}"/>
   </Style>

+ 21 - 4
src/Avalonia.Visuals/Animation/PageSlide.cs

@@ -15,6 +15,15 @@ namespace Avalonia.Animation
     /// </summary>
     public class PageSlide : IPageTransition
     {
+        /// <summary>
+        /// The axis on which the PageSlide should occur
+        /// </summary>
+        public enum SlideAxis
+        {
+            Horizontal,
+            Vertical
+        }
+
         /// <summary>
         /// Initializes a new instance of the <see cref="PageSlide"/> class.
         /// </summary>
@@ -26,9 +35,11 @@ namespace Avalonia.Animation
         /// Initializes a new instance of the <see cref="PageSlide"/> class.
         /// </summary>
         /// <param name="duration">The duration of the animation.</param>
-        public PageSlide(TimeSpan duration)
+        /// <param name="orientation">The axis on which the animation should occur</param>
+        public PageSlide(TimeSpan duration, SlideAxis orientation = SlideAxis.Horizontal)
         {
             Duration = duration;
+            Orientation = orientation;
         }
 
         /// <summary>
@@ -36,6 +47,11 @@ namespace Avalonia.Animation
         /// </summary>
         public TimeSpan Duration { get; set; }
 
+        /// <summary>
+        /// Gets the duration of the animation.
+        /// </summary>
+        public SlideAxis Orientation { get; set; }
+
         /// <summary>
         /// Starts the animation.
         /// </summary>
@@ -55,7 +71,8 @@ namespace Avalonia.Animation
         {
             var tasks = new List<Task>();
             var parent = GetVisualParent(from, to);
-            var distance = parent.Bounds.Width;
+            var distance = Orientation == SlideAxis.Horizontal ? parent.Bounds.Width : parent.Bounds.Height;
+            var translateProperty = Orientation == SlideAxis.Horizontal ? TranslateTransform.XProperty : TranslateTransform.YProperty;
 
             if (from != null)
             {
@@ -63,7 +80,7 @@ namespace Avalonia.Animation
                 from.RenderTransform = transform;
                 tasks.Add(Animate.Property(
                     transform,
-                    TranslateTransform.XProperty,
+                    translateProperty,
                     0.0,
                     forward ? -distance : distance,
                     LinearEasing.For<double>(),
@@ -77,7 +94,7 @@ namespace Avalonia.Animation
                 to.IsVisible = true;
                 tasks.Add(Animate.Property(
                     transform,
-                    TranslateTransform.XProperty,
+                    translateProperty,
                     forward ? distance : -distance,
                     0.0,
                     LinearEasing.For<double>(),

+ 10 - 0
tests/Avalonia.Controls.UnitTests/ClassesTests.cs

@@ -161,5 +161,15 @@ namespace Avalonia.Controls.UnitTests
 
             Assert.Equal(new[] { ":baz" }, target);
         }
+
+        [Fact]
+        public void RemoveAll_Should_Remove_Classes()
+        {
+            var target = new Classes("foo", "bar", "baz");
+
+            target.RemoveAll(new[] { "bar", "baz" });
+
+            Assert.Equal(new[] { "foo" }, target);
+        }
     }
 }

+ 57 - 0
tests/Avalonia.Controls.UnitTests/Primitives/ToggleButtonTests.cs

@@ -0,0 +1,57 @@
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.UnitTests;
+
+using Xunit;
+
+namespace Avalonia.Controls.Primitives.UnitTests
+{
+    public class ToggleButtonTests
+    {
+        private const string uncheckedClass = ":unchecked";
+        private const string checkedClass = ":checked";
+        private const string indeterminateClass = ":indeterminate";
+
+        [Theory]
+        [InlineData(false, uncheckedClass, false)]
+        [InlineData(false, uncheckedClass, true)]
+        [InlineData(true, checkedClass, false)]
+        [InlineData(true, checkedClass, true)]
+        [InlineData(null, indeterminateClass, false)]
+        [InlineData(null, indeterminateClass, true)]
+        public void ToggleButton_Has_Correct_Class_According_To_Is_Checked(bool? isChecked, string expectedClass, bool isThreeState)
+        {
+            var toggleButton = new ToggleButton();
+            toggleButton.IsThreeState = isThreeState;
+            toggleButton.IsChecked = isChecked;
+
+            Assert.Contains(expectedClass, toggleButton.Classes);
+        }
+
+        [Fact]
+        public void ToggleButton_Is_Checked_Binds_To_Bool()
+        {
+            var toggleButton = new ToggleButton();
+            var source = new Class1();
+
+            toggleButton.DataContext = source;
+            toggleButton.Bind(ToggleButton.IsCheckedProperty, new Binding("Foo"));
+
+            source.Foo = true;
+            Assert.True(toggleButton.IsChecked);
+
+            source.Foo = false;
+            Assert.False(toggleButton.IsChecked);
+        }
+
+        private class Class1 : NotifyingBase
+        {
+            private bool _foo;
+
+            public bool Foo
+            {
+                get { return _foo; }
+                set { _foo = value; RaisePropertyChanged(); }
+            }
+        }
+    }
+}

+ 36 - 0
tests/Avalonia.Controls.UnitTests/RadioButtonTests.cs

@@ -0,0 +1,36 @@
+using Avalonia.Markup.Xaml.Data;
+using Avalonia.UnitTests;
+
+using Xunit;
+
+namespace Avalonia.Controls.UnitTests
+{
+    public class RadioButtonTests
+    {
+        [Theory]
+        [InlineData(false)]
+        [InlineData(true)]
+        public void Indeterminate_RadioButton_Is_Not_Unchecked_After_Checking_Other_Radio_Button(bool isThreeState)
+        {
+            var panel = new Panel();
+
+            var radioButton1 = new RadioButton();
+            radioButton1.IsThreeState = false;
+            radioButton1.IsChecked = false;
+
+            var radioButton2 = new RadioButton();
+            radioButton2.IsThreeState = isThreeState;
+            radioButton2.IsChecked = null;
+
+            panel.Children.Add(radioButton1);
+            panel.Children.Add(radioButton2);
+
+            Assert.Null(radioButton2.IsChecked);
+
+            radioButton1.IsChecked = true;
+
+            Assert.True(radioButton1.IsChecked);
+            Assert.Null(radioButton2.IsChecked);
+        }
+    }
+}

+ 71 - 0
tests/Avalonia.Styling.UnitTests/SetterTests.cs

@@ -86,6 +86,77 @@ namespace Avalonia.Styling.UnitTests
             Assert.Null(control.Tag);
         }
 
+        [Fact]
+        public void Setter_Should_Apply_Value_Without_Activator_With_Style_Priority()
+        {
+            var control = new Mock<IStyleable>();
+            var style = Mock.Of<Style>();
+            var setter = new Setter(TextBlock.TextProperty, "foo");
+
+            setter.Apply(style, control.Object, null);
+
+            control.Verify(x => x.Bind(
+                TextBlock.TextProperty,
+                It.IsAny<IObservable<object>>(),
+                BindingPriority.Style));
+        }
+
+        [Fact]
+        public void Setter_Should_Apply_Value_With_Activator_With_StyleTrigger_Priority()
+        {
+            var control = new Mock<IStyleable>();
+            var style = Mock.Of<Style>();
+            var setter = new Setter(TextBlock.TextProperty, "foo");
+            var activator = new Subject<bool>();
+
+            setter.Apply(style, control.Object, activator);
+
+            control.Verify(x => x.Bind(
+                TextBlock.TextProperty,
+                It.IsAny<IObservable<object>>(),
+                BindingPriority.StyleTrigger));
+        }
+
+        [Fact]
+        public void Setter_Should_Apply_Binding_Without_Activator_With_Style_Priority()
+        {
+            var control = new Mock<IStyleable>();
+            var style = Mock.Of<Style>();
+            var setter = new Setter(TextBlock.TextProperty, CreateMockBinding(TextBlock.TextProperty));
+
+            setter.Apply(style, control.Object, null);
+
+            control.Verify(x => x.Bind(
+                TextBlock.TextProperty,
+                It.IsAny<IObservable<object>>(),
+                BindingPriority.Style));
+        }
+
+        [Fact]
+        public void Setter_Should_Apply_Binding_With_Activator_With_StyleTrigger_Priority()
+        {
+            var control = new Mock<IStyleable>();
+            var style = Mock.Of<Style>();
+            var setter = new Setter(TextBlock.TextProperty, CreateMockBinding(TextBlock.TextProperty));
+            var activator = new Subject<bool>();
+
+            setter.Apply(style, control.Object, activator);
+
+            control.Verify(x => x.Bind(
+                TextBlock.TextProperty,
+                It.IsAny<IObservable<object>>(),
+                BindingPriority.StyleTrigger));
+        }
+
+        private IBinding CreateMockBinding(AvaloniaProperty property)
+        {
+            var subject = new Subject<object>();
+            var descriptor = InstancedBinding.OneWay(subject);
+            var binding = Mock.Of<IBinding>(x => 
+                x.Initiate(It.IsAny<IAvaloniaObject>(), property, null, false) == descriptor);
+            return binding;
+        }
+
         private class TestConverter : IValueConverter
         {
             public object Convert(object value, Type targetType, object parameter, CultureInfo culture)