Browse Source

Merge branch 'master' into micro-com

pull/4971/head
Nikita Tsukanov 6 years ago
committed by GitHub
parent
commit
902c9e179a
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      build/XUnit.props
  2. 2
      samples/ControlCatalog/MainView.xaml
  3. 11
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  4. 11
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
  5. 13
      samples/ControlCatalog/Pages/ComboBoxPage.xaml
  6. 20
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml
  7. 6
      samples/ControlCatalog/Pages/LabelsPage.axaml
  8. 10
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  9. 16
      samples/ControlCatalog/Pages/RelativePanelPage.axaml
  10. 10
      samples/ControlCatalog/Pages/SliderPage.xaml
  11. 11
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  12. 4
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  13. 1
      src/Avalonia.Controls/Label.cs
  14. 1
      src/Avalonia.Controls/Primitives/Popup.cs
  15. 12
      src/Avalonia.Controls/RelativePanel.AttachedProperties.cs
  16. 6
      src/Avalonia.Controls/ResolveByNameAttribute.cs
  17. 7
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs
  18. 6
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
  19. 8
      src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs
  20. 3
      src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml
  21. 3
      src/Avalonia.Native/WindowImplBase.cs
  22. 18
      src/Avalonia.ReactiveUI/ReactiveUserControl.cs
  23. 18
      src/Avalonia.ReactiveUI/ReactiveWindow.cs
  24. 99
      src/Avalonia.Themes.Fluent/ButtonSpinner.xaml
  25. 201
      src/Avalonia.Themes.Fluent/ComboBox.xaml
  26. 48
      src/Avalonia.Themes.Fluent/DataValidationErrors.xaml
  27. 143
      src/Avalonia.Themes.Fluent/DatePicker.xaml
  28. 2
      src/Avalonia.Themes.Fluent/NumericUpDown.xaml
  29. 204
      src/Avalonia.Themes.Fluent/Slider.xaml
  30. 20
      src/Avalonia.Themes.Fluent/TextBox.xaml
  31. 164
      src/Avalonia.Themes.Fluent/TimePicker.xaml
  32. 55
      src/Avalonia.Visuals/Media/ConicGradientBrush.cs
  33. 19
      src/Avalonia.Visuals/Media/IConicGradientBrush.cs
  34. 47
      src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs
  35. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
  36. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs
  37. 17
      src/Skia/Avalonia.Skia/DrawingContextImpl.cs
  38. 6
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  39. 17
      src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs
  40. 32
      src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs
  41. 6
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  42. 10
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  43. 18
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  44. 34
      tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs
  45. 79
      tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs
  46. 87
      tests/Avalonia.ReactiveUI.UnitTests/ReactiveWindowTest.cs
  47. 178
      tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs
  48. 2
      tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj
  49. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue.expected.png
  50. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center.expected.png
  51. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center_and_Rotation.expected.png
  52. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Rotation.expected.png
  53. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_SoftEdge.expected.png
  54. BIN
      tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_Umbrella.expected.png
  55. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue.expected.png
  56. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center.expected.png
  57. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center_and_Rotation.expected.png
  58. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Rotation.expected.png
  59. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_SoftEdge.expected.png
  60. BIN
      tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_Umbrella.expected.png

2
build/XUnit.props

@ -13,6 +13,6 @@
</ItemGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>True</SignAssembly>
<SignAssembly>False</SignAssembly>
</PropertyGroup>
</Project>

2
samples/ControlCatalog/MainView.xaml

@ -14,7 +14,6 @@
<TabItem Header="Acrylic"><pages:AcrylicPage/></TabItem>
<TabItem Header="AutoCompleteBox"><pages:AutoCompleteBoxPage/></TabItem>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Label"><pages:LabelsPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="ButtonSpinner"><pages:ButtonSpinnerPage/></TabItem>
<TabItem Header="Calendar"><pages:CalendarPage/></TabItem>
@ -45,6 +44,7 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<pages:ItemsRepeaterPage/>
</TabItem>
<TabItem Header="Label"><pages:LabelsPage/></TabItem>
<TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
<TabItem Header="ListBox"
ScrollViewer.VerticalScrollBarVisibility="Disabled">

11
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="ControlCatalog.Pages.AutoCompleteBoxPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">AutoCompleteBox</TextBlock>
@ -56,6 +57,16 @@
Width="200"
Margin="0,0,0,8"
FilterMode="None"/>
<TextBlock Text="With Validation Errors"/>
<AutoCompleteBox Name="ValidationErrors"
Width="200"
Margin="0,0,0,8"
FilterMode="None">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</AutoCompleteBox>
</StackPanel>
</StackPanel>
</StackPanel>

11
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ButtonSpinnerPage">
x:Class="ControlCatalog.Pages.ButtonSpinnerPage"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ButtonSpinner</TextBlock>
@ -19,6 +20,14 @@
ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
</ButtonSpinner>
<ButtonSpinner MinHeight="30" Spin="OnSpin" ButtonSpinnerLocation="Left"
AllowSpin="{Binding #allowSpinCheck.IsChecked}"
ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
</ButtonSpinner>
</StackPanel>
</StackPanel>

13
samples/ControlCatalog/Pages/ComboBoxPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.ComboBoxPage">
x:Class="ControlCatalog.Pages.ComboBoxPage"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ComboBox</TextBlock>
<TextBlock Classes="h2">A drop-down list.</TextBlock>
@ -35,6 +36,16 @@
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<ComboBox PlaceholderText="Pick an Item">
<ComboBoxItem>Inline Items</ComboBoxItem>
<ComboBoxItem>Inline Item 2</ComboBoxItem>
<ComboBoxItem>Inline Item 3</ComboBoxItem>
<ComboBoxItem>Inline Item 4</ComboBoxItem>
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</ComboBox>
</StackPanel>
</StackPanel>

20
samples/ControlCatalog/Pages/DateTimePickerPage.xaml

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sys="clr-namespace:System;assembly=netstandard"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ControlCatalog.Pages.DateTimePickerPage">
<StackPanel Orientation="Vertical" Spacing="4" HorizontalAlignment="Stretch">
@ -30,6 +31,16 @@
</Panel>
</StackPanel>
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<DatePicker Header="Pick a date">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</DatePicker>
</Border>
<TextBlock FontSize="18">A DatePicker with day formatted and year hidden.</TextBlock>
<StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
@ -66,6 +77,15 @@
</TextBlock>
</Panel>
</StackPanel>
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
BorderThickness="1" Padding="15">
<TimePicker Header="Pick a time">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</TimePicker>
</Border>
<TextBlock FontSize="18">A TimePicker with a header and minute increments specified.</TextBlock>
<StackPanel Orientation="Vertical">

6
samples/ControlCatalog/Pages/LabelsPage.axaml

@ -25,11 +25,11 @@
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Hidden">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" RowDefinitions="Auto,Auto,Auto,Auto,Auto,*" ColumnDefinitions="Auto,6,*" Width="246">
<Label Target="{Binding #firstNameEdit}" Grid.Row="0" Grid.Column="0">_First name</Label>
<Label Target="firstNameEdit" Grid.Row="0" Grid.Column="0">_First name</Label>
<TextBox Name="firstNameEdit" Grid.Column="2" Grid.Row="0" Text="{Binding FirstName}"></TextBox>
<Label Target="{Binding #lastNameEdit}" Grid.Row="1" Grid.Column="0">_Last name</Label>
<Label Target="lastNameEdit" Grid.Row="1" Grid.Column="0">_Last name</Label>
<TextBox Name="lastNameEdit" Grid.Column="2" Grid.Row="1" Text="{Binding LastName}"></TextBox>
<Label Target="{Binding #bannedCheck}" Grid.Row="2" Grid.Column="0">_Banned</Label>
<Label Target="bannedCheck" Grid.Row="2" Grid.Column="0">_Banned</Label>
<CheckBox Name="bannedCheck" Grid.Column="2" Grid.Row="2" IsChecked="{Binding IsBanned}"></CheckBox>
<GridSplitter Grid.Column="1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Grid.RowSpan="3" >
</GridSplitter>

10
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="ControlCatalog.Pages.NumericUpDownPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Margin="2" Classes="h1">Numeric up-down control</TextBlock>
@ -75,6 +76,15 @@
<NumericUpDown Name="upDown" Minimum="0" Maximum="10" Increment="0.5"
CultureInfo="en-US" VerticalAlignment="Center"
Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}"/>
<TextBlock FontSize="14" FontWeight="Bold" VerticalAlignment="Center">NumericUpDown with Validation Errors:</TextBlock>
<NumericUpDown Minimum="0" Maximum="10" Increment="0.5"
CultureInfo="en-US" VerticalAlignment="Center"
Watermark="Enter text" FormatString="{Binding SelectedFormat.Value}">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</NumericUpDown>
</StackPanel>
</StackPanel>

16
samples/ControlCatalog/Pages/RelativePanelPage.axaml

@ -23,16 +23,16 @@
<Border Name="Rect6" Background="Green" Height="50" Width="50" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<TextBlock Text="Rect6" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect7" Background="Blue" Height="50" RelativePanel.RightOf="{Binding ElementName=Rect1}">
<Border Name="Rect7" Background="Blue" Height="50" RelativePanel.RightOf="Rect1">
<TextBlock Text="Rect7 (RightOf Rect1)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect8" Background="Green" Height="50" RelativePanel.Below="{Binding ElementName=Rect7}">
<Border Name="Rect8" Background="Green" Height="50" RelativePanel.Below="Rect7">
<TextBlock Text="Rect8 (Below Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect9" Background="Blue" Height="140" Width="460" RelativePanel.AlignHorizontalCenterWithPanel="True" RelativePanel.AlignVerticalCenterWithPanel="True">
<TextBlock Text="Rect9" Padding="10" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Border>
<Border Name="Rect10" Background="Red" Width="50" RelativePanel.RightOf="{Binding ElementName=Rect9}" RelativePanel.AlignVerticalCenterWith="{Binding ElementName=Rect9}">
<Border Name="Rect10" Background="Red" Width="50" RelativePanel.RightOf="Rect9" RelativePanel.AlignVerticalCenterWith="Rect9">
<TextBlock Text="Rect14 (RightOf Rect9, AlignVerticalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.RenderTransform>
<TransformGroup>
@ -41,19 +41,19 @@
</TextBlock.RenderTransform>
</TextBlock>
</Border>
<Border Name="Rect11" Background="Red" Height="50" RelativePanel.AlignBottomWith="{Binding ElementName=Rect9}" RelativePanel.AlignHorizontalCenterWith="{Binding ElementName=Rect9}">
<Border Name="Rect11" Background="Red" Height="50" RelativePanel.AlignBottomWith="Rect9" RelativePanel.AlignHorizontalCenterWith="Rect9">
<TextBlock Text="Rect11 (AlignBottomWith Rect9, AlignHorizontalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect12" Background="Red" Height="50" RelativePanel.Below="{Binding ElementName=Rect8}" RelativePanel.AlignLeftWith="{Binding ElementName=Rect7}">
<Border Name="Rect12" Background="Red" Height="50" RelativePanel.Below="Rect8" RelativePanel.AlignLeftWith="Rect7">
<TextBlock Text="Rect12 (Below Rect8, AlignLeftWith Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect13" Background="Blue" Height="50" RelativePanel.Below="{Binding ElementName=Rect12}" RelativePanel.AlignRightWith="{Binding ElementName=Rect12}">
<Border Name="Rect13" Background="Blue" Height="50" RelativePanel.Below="Rect12" RelativePanel.AlignRightWith="Rect12">
<TextBlock Text="Rect13 (Below Rect12, AlignRightWith Rect12)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect14" Background="Green" Height="50" RelativePanel.Above="{Binding ElementName=Rect9}" RelativePanel.AlignRightWith="{Binding ElementName=Rect9}">
<Border Name="Rect14" Background="Green" Height="50" RelativePanel.Above="Rect9" RelativePanel.AlignRightWith="Rect9">
<TextBlock Text="Rect14 (Above Rect9, AlignRightWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<Border Name="Rect15" Background="Red" Height="50" RelativePanel.LeftOf="{Binding ElementName=Rect2}" RelativePanel.AlignTopWith="{Binding ElementName=Rect9}">
<Border Name="Rect15" Background="Red" Height="50" RelativePanel.LeftOf="Rect2" RelativePanel.AlignTopWith="Rect9">
<TextBlock Text="Rect15 (LeftOf Rect2, AlignTopWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</RelativePanel>

10
samples/ControlCatalog/Pages/SliderPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="ControlCatalog.Pages.SliderPage">
<StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">Slider</TextBlock>
@ -21,6 +22,15 @@
IsSnapToTickEnabled="True"
Ticks="0,20,25,40,75,100"
Width="300" />
<Slider Value="0"
Minimum="0"
Maximum="100"
TickFrequency="10"
Width="300">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</Slider>
</StackPanel>
<Slider Value="0"
Minimum="0"

11
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.TextBoxPage">
x:Class="ControlCatalog.Pages.TextBoxPage"
xmlns:sys="clr-namespace:System;assembly=netstandard">
<StackPanel Orientation="Vertical" Spacing="4">
<Label Classes="h1">TextBox</Label>
<Label Classes="h2">A control into which the user can input text</Label>
@ -11,12 +12,18 @@
Spacing="16">
<StackPanel Orientation="Vertical" Spacing="8">
<TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" />
<TextBox Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
<TextBox Width="200" Watermark="ReadOnly" IsReadOnly="True" Text="This is read only"/>
<TextBox Width="200" Watermark="Watermark" />
<TextBox Width="200"
Watermark="Floating Watermark"
UseFloatingWatermark="True"
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBox Width="200" Text="Validation Error">
<DataValidationErrors.Error>
<sys:Exception />
</DataValidationErrors.Error>
</TextBox>
<TextBox Width="200"
Watermark="Password Box"

4
src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs

@ -486,9 +486,9 @@ namespace Avalonia.Controls.Primitives
switch (panelType)
{
case DateTimePickerPanelType.Year:
return new DateTime(value, FormatDate.Month, FormatDate.Day).ToString(ItemFormat);
return new DateTime(value, 1, 1).ToString(ItemFormat);
case DateTimePickerPanelType.Month:
return new DateTime(FormatDate.Year, value, FormatDate.Day).ToString(ItemFormat);
return new DateTime(FormatDate.Year, value, 1).ToString(ItemFormat);
case DateTimePickerPanelType.Day:
return new DateTime(FormatDate.Year, FormatDate.Month, value).ToString(ItemFormat);
case DateTimePickerPanelType.Hour:

1
src/Avalonia.Controls/Label.cs

@ -29,6 +29,7 @@ namespace Avalonia.Controls
/// <summary>
/// Label focus Target
/// </summary>
[ResolveByName]
public IInputElement Target
{
get => _target;

1
src/Avalonia.Controls/Primitives/Popup.cs

@ -265,6 +265,7 @@ namespace Avalonia.Controls.Primitives
/// <summary>
/// Gets or sets the control that is used to determine the popup's position.
/// </summary>
[ResolveByName]
public Control? PlacementTarget
{
get { return GetValue(PlacementTargetProperty); }

12
src/Avalonia.Controls/RelativePanel.AttachedProperties.cs

@ -55,6 +55,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to position this element above.)</param>
[ResolveByName]
public static void SetAbove(AvaloniaObject obj, object value)
{
obj.SetValue(AboveProperty, value);
@ -121,6 +122,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's bottom edge with.)</param>
[ResolveByName]
public static void SetAlignBottomWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignBottomWithProperty, value);
@ -185,6 +187,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's horizontal center with.)</param>
[ResolveByName]
public static void SetAlignHorizontalCenterWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignHorizontalCenterWithProperty, value);
@ -250,6 +253,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's left edge with.)</param>
[ResolveByName]
public static void SetAlignLeftWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignLeftWithProperty, value);
@ -315,6 +319,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's right edge with.)</param>
[ResolveByName]
public static void SetAlignRightWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignRightWithProperty, value);
@ -376,6 +381,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's top edge with.)</param>
[ResolveByName]
public static void SetAlignTopWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignTopWithProperty, value);
@ -437,7 +443,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to align this element's horizontal center with.)</param>
[ResolveByName]
public static void SetAlignVerticalCenterWith(AvaloniaObject obj, object value)
{
obj.SetValue(AlignVerticalCenterWithProperty, value);
@ -468,7 +474,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to position this element below.)</param>
[ResolveByName]
public static void SetBelow(AvaloniaObject obj, object value)
{
obj.SetValue(BelowProperty, value);
@ -500,6 +506,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to position this element to the left of.)</param>
[ResolveByName]
public static void SetLeftOf(AvaloniaObject obj, object value)
{
obj.SetValue(LeftOfProperty, value);
@ -531,6 +538,7 @@ namespace Avalonia.Controls
/// </summary>
/// <param name="obj">The object to which the property value is written.</param>
/// <param name="value">The value to set. (The element to position this element to the right of.)</param>
[ResolveByName]
public static void SetRightOf(AvaloniaObject obj, object value)
{
obj.SetValue(RightOfProperty, value);

6
src/Avalonia.Controls/ResolveByNameAttribute.cs

@ -2,8 +2,12 @@
namespace Avalonia.Controls
{
/// <summary>
/// Indicates that the property resolves an element by Name or x:Name.
/// When applying this to attached properties, ensure to put on both
/// the Getter and Setter methods.
/// </summary>
public class ResolveByNameAttribute : Attribute
{
}
}

7
src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs

@ -23,6 +23,8 @@ namespace Avalonia.Diagnostics.ViewModels
if (visual is IControl control)
{
ElementName = control.Name;
var removed = Observable.FromEventPattern<LogicalTreeAttachmentEventArgs>(
x => control.DetachedFromLogicalTree += x,
x => control.DetachedFromLogicalTree -= x);
@ -61,6 +63,11 @@ namespace Avalonia.Diagnostics.ViewModels
private set { RaiseAndSetIfChanged(ref _classes, value); }
}
public string ElementName
{
get;
}
public IVisual Visual
{
get;

6
src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml

@ -26,6 +26,12 @@
<DataGridTextColumn Header="Type" Binding="{Binding Type}" />
<DataGridTextColumn Header="Priority" Binding="{Binding Priority}" IsReadOnly="True" />
</DataGrid.Columns>
<DataGrid.Styles>
<Style Selector="DataGridRow TextBox">
<Setter Property="SelectionBrush" Value="LightBlue"/>
</Style>
</DataGrid.Styles>
</DataGrid>
</Grid>

8
src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs

@ -76,7 +76,13 @@ namespace Avalonia.Diagnostics.Views
if (e.Modifiers == modifiers)
{
var point = (Root as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default;
var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible))
var control = Root.GetVisualsAt(point, x =>
{
if (x is AdornerLayer || !x.IsVisible) return false;
if (!(x is IInputElement ie)) return true;
return ie.IsHitTestVisible;
})
.FirstOrDefault();
if (control != null)

3
src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml

@ -2,7 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels"
x:Class="Avalonia.Diagnostics.Views.TreePageView">
<Grid ColumnDefinitions="*,4,3*">
<Grid ColumnDefinitions="0.8*,4,*">
<TreeView Name="tree"
BorderThickness="0"
Items="{Binding Nodes}"
@ -13,6 +13,7 @@
<StackPanel Orientation="Horizontal" Spacing="8">
<TextBlock Text="{Binding Type}"/>
<TextBlock Text="{Binding Classes}"/>
<TextBlock Foreground="Gray" Text="{Binding ElementName}"/>
</StackPanel>
</TreeDataTemplate>
</TreeView.DataTemplates>

3
src/Avalonia.Native/WindowImplBase.cs

@ -341,8 +341,7 @@ namespace Avalonia.Native
public void Invalidate(Rect rect)
{
if (!_deferredRendering && _native != null)
_native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y });
_native?.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y });
}
public void SetInputRoot(IInputRoot inputRoot)

18
src/Avalonia.ReactiveUI/ReactiveUserControl.cs

@ -1,3 +1,6 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.VisualTree;
using Avalonia.Controls;
@ -6,8 +9,10 @@ using ReactiveUI;
namespace Avalonia.ReactiveUI
{
/// <summary>
/// A ReactiveUI UserControl that implements <see cref="IViewFor{TViewModel}"/>
/// and will activate your ViewModel automatically if it supports activation.
/// A ReactiveUI <see cref="UserControl"/> that implements the <see cref="IViewFor{TViewModel}"/> interface and
/// will activate your ViewModel automatically if the view model implements <see cref="IActivatableViewModel"/>.
/// When the DataContext property changes, this class will update the ViewModel property with the new DataContext
/// value, and vice versa.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveUserControl<TViewModel> : UserControl, IViewFor<TViewModel> where TViewModel : class
@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI
/// </summary>
public ReactiveUserControl()
{
DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel;
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.ObservableForProperty(x => x.ViewModel, false, true)
.Subscribe(args => DataContext = args.Value);
this.ObservableForProperty(x => x.DataContext, false, true)
.Subscribe(args => ViewModel = args.Value as TViewModel);
}
/// <summary>

18
src/Avalonia.ReactiveUI/ReactiveWindow.cs

@ -1,3 +1,6 @@
using System;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using Avalonia;
using Avalonia.VisualTree;
using Avalonia.Controls;
@ -6,8 +9,10 @@ using ReactiveUI;
namespace Avalonia.ReactiveUI
{
/// <summary>
/// A ReactiveUI Window that implements <see cref="IViewFor{TViewModel}"/>
/// and will activate your ViewModel automatically if it supports activation.
/// A ReactiveUI <see cref="Window"/> that implements the <see cref="IViewFor{TViewModel}"/> interface and will
/// activate your ViewModel automatically if the view model implements <see cref="IActivatableViewModel"/>. When
/// the DataContext property changes, this class will update the ViewModel property with the new DataContext value,
/// and vice versa.
/// </summary>
/// <typeparam name="TViewModel">ViewModel type.</typeparam>
public class ReactiveWindow<TViewModel> : Window, IViewFor<TViewModel> where TViewModel : class
@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI
/// </summary>
public ReactiveWindow()
{
DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel;
// This WhenActivated block calls ViewModel's WhenActivated
// block if the ViewModel implements IActivatableViewModel.
this.WhenActivated(disposables => { });
this.ObservableForProperty(x => x.ViewModel, false, true)
.Subscribe(args => DataContext = args.Value);
this.ObservableForProperty(x => x.DataContext, false, true)
.Subscribe(args => ViewModel = args.Value as TViewModel);
}
/// <summary>

99
src/Avalonia.Themes.Fluent/ButtonSpinner.xaml

@ -65,56 +65,59 @@
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid ColumnDefinitions="Auto,*,Auto">
<ContentPresenter Name="PART_ContentPresenter"
Grid.Column="1"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
<DataValidationErrors>
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}"
MinHeight="{TemplateBinding MinHeight}">
<Grid ColumnDefinitions="Auto,*,Auto">
<ContentPresenter Name="PART_ContentPresenter"
Grid.Column="1"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Padding="{TemplateBinding Padding}" />
<StackPanel Name="PART_SpinnerPanel"
Orientation="Horizontal"
IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Name="PART_IncreaseButton"
Classes="ButtonSpinnerRepeatButton"
VerticalContentAlignment="Center"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerIncreaseButtonIcon}" />
</RepeatButton>
<StackPanel Name="PART_SpinnerPanel"
Orientation="Horizontal"
IsVisible="{TemplateBinding ShowButtonSpinner}">
<RepeatButton Name="PART_IncreaseButton"
Classes="ButtonSpinnerRepeatButton"
VerticalContentAlignment="Center"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerIncreaseButtonIcon}" />
</RepeatButton>
<RepeatButton Name="PART_DecreaseButton"
Classes="ButtonSpinnerRepeatButton"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
VerticalContentAlignment="Center"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerDecreaseButtonIcon}" />
</RepeatButton>
</StackPanel>
</Grid>
</Border>
<RepeatButton Name="PART_DecreaseButton"
Classes="ButtonSpinnerRepeatButton"
Foreground="{TemplateBinding Foreground}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
VerticalContentAlignment="Center"
FontSize="{TemplateBinding FontSize}">
<Path Fill="{TemplateBinding Foreground}"
Width="16"
Height="8"
Stretch="Uniform"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Data="{StaticResource ButtonSpinnerDecreaseButtonIcon}" />
</RepeatButton>
</StackPanel>
</Grid>
</Border>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>

201
src/Avalonia.Themes.Fluent/ComboBox.xaml

@ -44,105 +44,107 @@
<Setter Property="PlaceholderForeground" Value="{DynamicResource ComboBoxPlaceHolderForeground}" />
<Setter Property="Template">
<ControlTemplate>
<Grid RowDefinitions="Auto, *, Auto"
ColumnDefinitions="*,32">
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
<DataValidationErrors>
<Grid RowDefinitions="Auto, *, Auto"
ColumnDefinitions="*,32">
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
IsVisible="False"
TextBlock.FontWeight="{DynamicResource ComboBoxHeaderThemeFontWeight}"
Margin="{DynamicResource ComboBoxTopHeaderMargin}"
VerticalAlignment="Top" />
<Border x:Name="Background"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinWidth="{DynamicResource ComboBoxThemeMinWidth}" />
<Border x:Name="HighlightBackground"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="{DynamicResource ComboBoxBackgroundUnfocused}"
BorderBrush="{DynamicResource ComboBoxBackgroundBorderBrushUnfocused}"
BorderThickness="{TemplateBinding BorderThickness}" />
<TextBlock x:Name="PlaceholderTextBlock"
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
Text="{TemplateBinding PlaceholderText}"
Foreground="{TemplateBinding PlaceholderForeground}"
IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}" />
<ContentControl x:Name="ContentPresenter"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding ItemTemplate}"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
IsVisible="False"
TextBlock.FontWeight="{DynamicResource ComboBoxHeaderThemeFontWeight}"
Margin="{DynamicResource ComboBoxTopHeaderMargin}"
VerticalAlignment="Top" />
<Border x:Name="Background"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
MinWidth="{DynamicResource ComboBoxThemeMinWidth}" />
<Border x:Name="HighlightBackground"
Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="2"
Background="{DynamicResource ComboBoxBackgroundUnfocused}"
BorderBrush="{DynamicResource ComboBoxBackgroundBorderBrushUnfocused}"
BorderThickness="{TemplateBinding BorderThickness}" />
<TextBlock x:Name="PlaceholderTextBlock"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
<Border x:Name="DropDownOverlay"
Grid.Row="1"
Grid.Column="1"
Background="Transparent"
Margin="0,1,1,1"
Width="30"
IsVisible="False"
HorizontalAlignment="Right" />
<Viewbox UseLayoutRounding="False"
MinHeight="{DynamicResource ComboBoxMinHeight}"
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="{TemplateBinding Padding}"
Text="{TemplateBinding PlaceholderText}"
Foreground="{TemplateBinding PlaceholderForeground}"
IsVisible="{TemplateBinding SelectionBoxItem, Converter={x:Static ObjectConverters.IsNull}}" />
<ContentControl x:Name="ContentPresenter"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding ItemTemplate}"
Grid.Row="1"
Grid.Column="0"
Margin="{TemplateBinding Padding}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" />
<Border x:Name="DropDownOverlay"
Grid.Row="1"
Grid.Column="1"
Background="Transparent"
Margin="0,1,1,1"
Width="30"
IsVisible="False"
HorizontalAlignment="Right" />
<Viewbox UseLayoutRounding="False"
MinHeight="{DynamicResource ComboBoxMinHeight}"
Grid.Row="1"
Grid.Column="1"
IsHitTestVisible="False"
Margin="0,0,10,0"
Height="12"
Width="12"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<Panel>
<Panel Height="12"
Width="12" />
<Path x:Name="DropDownGlyph"
Stretch="Uniform"
VerticalAlignment="Center"
Data="M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z" />
</Panel>
</Viewbox>
<Popup Name="PART_Popup"
WindowManagerAddShadowHint="False"
IsOpen="{TemplateBinding IsDropDownOpen, Mode=TwoWay}"
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
PlacementTarget="{TemplateBinding}"
IsLightDismissEnabled="True">
<Border x:Name="PopupBorder"
Background="{DynamicResource ComboBoxDropDownBackground}"
BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}"
BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}"
Margin="0,-1,0,-1"
Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
Margin="{DynamicResource ComboBoxDropdownContentMargin}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
VirtualizationMode="{TemplateBinding VirtualizationMode}" />
</ScrollViewer>
</Border>
</Popup>
</Grid>
Grid.Column="1"
IsHitTestVisible="False"
Margin="0,0,10,0"
Height="12"
Width="12"
HorizontalAlignment="Right"
VerticalAlignment="Center">
<Panel>
<Panel Height="12"
Width="12" />
<Path x:Name="DropDownGlyph"
Stretch="Uniform"
VerticalAlignment="Center"
Data="M1939 486L2029 576L1024 1581L19 576L109 486L1024 1401L1939 486Z" />
</Panel>
</Viewbox>
<Popup Name="PART_Popup"
WindowManagerAddShadowHint="False"
IsOpen="{TemplateBinding IsDropDownOpen, Mode=TwoWay}"
MinWidth="{Binding Bounds.Width, RelativeSource={RelativeSource TemplatedParent}}"
MaxHeight="{TemplateBinding MaxDropDownHeight}"
PlacementTarget="Background"
IsLightDismissEnabled="True">
<Border x:Name="PopupBorder"
Background="{DynamicResource ComboBoxDropDownBackground}"
BorderBrush="{DynamicResource ComboBoxDropDownBorderBrush}"
BorderThickness="{DynamicResource ComboBoxDropdownBorderThickness}"
Margin="0,-1,0,-1"
Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
Margin="{DynamicResource ComboBoxDropdownContentMargin}"
ItemsPanel="{TemplateBinding ItemsPanel}"
ItemTemplate="{TemplateBinding ItemTemplate}"
VirtualizationMode="{TemplateBinding VirtualizationMode}" />
</ScrollViewer>
</Border>
</Popup>
</Grid>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
@ -232,4 +234,9 @@
<Style Selector="ComboBox /template/ Border#HighlightBackground">
<Setter Property="CornerRadius" Value="{DynamicResource ControlCornerRadius}" />
</Style>
<!-- Error State -->
<Style Selector="ComboBox:error /template/ Border#Background">
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlErrorTextForegroundBrush}"/>
</Style>
</Styles>

48
src/Avalonia.Themes.Fluent/DataValidationErrors.xaml

@ -14,39 +14,31 @@
<Setter Property="Template">
<ControlTemplate>
<DockPanel LastChildFill="True">
<ContentControl DockPanel.Dock="Right"
ContentTemplate="{TemplateBinding ErrorTemplate}"
DataContext="{TemplateBinding Owner}"
Content="{Binding (DataValidationErrors.Errors)}"
IsVisible="{Binding (DataValidationErrors.HasErrors)}"/>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
<ContentControl Margin="0 4 0 0"
DockPanel.Dock="Bottom"
ContentTemplate="{TemplateBinding ErrorTemplate}"
DataContext="{TemplateBinding Owner}"
Content="{Binding (DataValidationErrors.Errors)}"
IsVisible="{Binding (DataValidationErrors.HasErrors)}" />
<ContentPresenter
Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}" />
</DockPanel>
</ControlTemplate>
</Setter>
<Setter Property="ErrorTemplate">
<DataTemplate>
<Canvas Name="PART_ErrorTemplateCanvas"
Width="14" Height="14" Margin="4 0 1 0"
Background="Transparent">
<Canvas.Styles>
<Style Selector="Canvas#PART_ErrorTemplateCanvas ToolTip">
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlErrorTextForegroundBrush}"/>
</Style>
<Style Selector="Canvas#PART_ErrorTemplateCanvas ToolTip TextBlock">
<Setter Property="TextWrapping" Value="Wrap" />
</Style>
</Canvas.Styles>
<ToolTip.Tip>
<ItemsControl Items="{Binding}"/>
</ToolTip.Tip>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2" Stroke="{DynamicResource SystemControlErrorTextForegroundBrush}" StrokeThickness="2"/>
</Canvas>
<ItemsControl Items="{Binding}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Message}" Foreground="{DynamicResource SystemControlErrorTextForegroundBrush}" TextWrapping="Wrap" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</Setter>
</Style>

143
src/Avalonia.Themes.Fluent/DatePicker.xaml

@ -125,77 +125,79 @@
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter Name="HeaderContentPresenter" Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource DatePickerTopHeaderMargin}"
MaxWidth="{DynamicResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"/>
<DataValidationErrors>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter Name="HeaderContentPresenter" Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource DatePickerTopHeaderMargin}"
MaxWidth="{DynamicResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top"/>
<Button Name="FlyoutButton" Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{StaticResource DatePickerThemeMinWidth}"
MaxWidth="{StaticResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
TemplatedControl.IsTemplateFocusTarget="True">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CornerRadius="{DynamicResource ControlCornerRadius}"/>
</ControlTemplate>
</Button.Template>
<Grid Name="ButtonContentGrid" ColumnDefinitions="78*,Auto,132*,Auto,78*">
<TextBlock Name="DayText" Text="day" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="MonthText" Text="month" TextAlignment="Left"
Padding="{DynamicResource DatePickerHostMonthPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="YearText" Text="year" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<Rectangle x:Name="FirstSpacer"
Fill="{DynamicResource DatePickerSpacerFill}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="1" />
<Rectangle x:Name="SecondSpacer"
Fill="{DynamicResource DatePickerSpacerFill}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="3" />
</Grid>
</Button>
<Button Name="FlyoutButton" Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{StaticResource DatePickerThemeMinWidth}"
MaxWidth="{StaticResource DatePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
TemplatedControl.IsTemplateFocusTarget="True">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CornerRadius="{DynamicResource ControlCornerRadius}"/>
</ControlTemplate>
</Button.Template>
<Grid Name="ButtonContentGrid" ColumnDefinitions="78*,Auto,132*,Auto,78*">
<TextBlock Name="DayText" Text="day" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="MonthText" Text="month" TextAlignment="Left"
Padding="{DynamicResource DatePickerHostMonthPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<TextBlock Name="YearText" Text="year" HorizontalAlignment="Center"
Padding="{DynamicResource DatePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
<Rectangle x:Name="FirstSpacer"
Fill="{DynamicResource DatePickerSpacerFill}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="1" />
<Rectangle x:Name="SecondSpacer"
Fill="{DynamicResource DatePickerSpacerFill}"
HorizontalAlignment="Center"
Width="1"
Grid.Column="3" />
</Grid>
</Button>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<DatePickerPresenter Name="PickerPresenter" />
</Popup>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<DatePickerPresenter Name="PickerPresenter" />
</Popup>
</Grid>
</Grid>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
@ -228,6 +230,11 @@
<Style Selector="DatePicker:hasnodate /template/ Button#FlyoutButton TextBlock">
<Setter Property="Foreground" Value="{DynamicResource TextControlPlaceholderForeground}"/>
</Style>
<Style Selector="DatePicker:error /template/ Button#FlyoutButton /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlErrorTextForegroundBrush}"/>
</Style>
<!--WinUI: DatePickerFlyoutPresenter-->
<Style Selector="DatePickerPresenter">

2
src/Avalonia.Themes.Fluent/NumericUpDown.xaml

@ -39,6 +39,7 @@
VerticalContentAlignment="Stretch"
AllowSpin="{TemplateBinding AllowSpin}"
ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}">
<TextBox Name="PART_TextBox"
Background="Transparent"
@ -46,7 +47,6 @@
Margin="-1"
Padding="{TemplateBinding Padding}"
Watermark="{TemplateBinding Watermark}"
DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}"
IsReadOnly="{TemplateBinding IsReadOnly}"
Text="{TemplateBinding Text}"
AcceptsReturn="False"

204
src/Avalonia.Themes.Fluent/Slider.xaml

@ -42,56 +42,58 @@
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
</Grid.RowDefinitions>
<TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
<TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
<Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="thumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderHorizontalThumbHeight}" Width="{DynamicResource SliderHorizontalThumbWidth}" />
</Track>
<DataValidationErrors>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="HorizontalTemplate" ColumnDefinitions="Auto,Auto,*" MinHeight="{DynamicResource SliderHorizontalHeight}">
<Grid.RowDefinitions>
<RowDefinition Height="{DynamicResource SliderPreContentMargin}" />
<RowDefinition Height="Auto" />
<RowDefinition Height="{DynamicResource SliderPostContentMargin}" />
</Grid.RowDefinitions>
<TickBar Name="TopTickBar" Placement="Top" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Bottom" Margin="0,0,0,4" Grid.ColumnSpan="3" />
<!-- <TickBar Name="HorizontalInlineTickBar" Placement="Top" Fill="{DynamicResource SliderInlineTickBarFill}" Height="{DynamicResource SliderTrackThemeHeight}" Grid.Row="1" Grid.ColumnSpan="3" /> -->
<TickBar Name="BottomTickBar" Placement="Bottom" Height="{DynamicResource SliderOutsideTickBarThemeHeight}" VerticalAlignment="Top" Margin="0,4,0,0" Grid.Row="2" Grid.ColumnSpan="3" />
<Track Name="PART_Track" Grid.Row="1" Grid.ColumnSpan="3" Orientation="Horizontal">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Height="{DynamicResource SliderTrackThemeHeight}" VerticalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="thumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderHorizontalThumbHeight}" Width="{DynamicResource SliderHorizontalThumbWidth}" />
</Track>
</Grid>
</Grid>
</Grid>
</Grid>
</Border>
</Border>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
@ -102,56 +104,58 @@
<Setter Property="FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
<Setter Property="Template">
<ControlTemplate>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
</Grid.ColumnDefinitions>
<TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
<TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
<Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="SliderThumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderVerticalThumbHeight}" Width="{DynamicResource SliderVerticalThumbWidth}" />
</Track>
<DataValidationErrors>
<Border BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" CornerRadius="{DynamicResource ControlCornerRadius}">
<Grid Name="grid" Margin="{TemplateBinding Padding}" RowDefinitions="Auto, *">
<ContentPresenter x:Name="HeaderContentPresenter" Grid.Row="0" TextBlock.FontWeight="{DynamicResource SliderHeaderThemeFontWeight}" TextBlock.Foreground="{DynamicResource SliderHeaderForeground}"
Margin="{DynamicResource SliderTopHeaderMargin}" />
<Grid x:Name="SliderContainer" Grid.Row="1">
<Grid.Styles>
<Style Selector="TickBar">
<Setter Property="ReservedSpace" Value="{Binding #PART_Track.Thumb.Bounds}" />
</Style>
</Grid.Styles>
<Grid x:Name="VerticalTemplate" RowDefinitions="*,Auto,Auto" MinWidth="{DynamicResource SliderVerticalWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{DynamicResource SliderPreContentMargin}" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="{DynamicResource SliderPostContentMargin}" />
</Grid.ColumnDefinitions>
<TickBar Name="LeftTickBar" Placement="Left" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Right" Margin="0,0,4,0" Grid.RowSpan="3" />
<!-- <TickBar Name="VerticalInlineTickBar" Placement="Inline" Fill="{DynamicResource SliderInlineTickBarFill}" Width="{DynamicResource SliderTrackThemeHeight}" Grid.Column="1" Grid.RowSpan="3" /> -->
<TickBar Name="RightTickBar" Placement="Right" Width="{DynamicResource SliderOutsideTickBarThemeHeight}" HorizontalAlignment="Left" Margin="4,0,0,0" Grid.Column="2" Grid.RowSpan="3" />
<Track Name="PART_Track" Grid.Column="1" Grid.ColumnSpan="1" Grid.RowSpan="3" Orientation="Vertical">
<Track.DecreaseButton>
<RepeatButton Name="PART_DecreaseButton" Background="{TemplateBinding Foreground}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.DecreaseButton>
<Track.IncreaseButton>
<RepeatButton Name="PART_IncreaseButton" Background="{TemplateBinding Background}" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<RepeatButton.Template>
<ControlTemplate>
<Grid>
<Border Name="FocusTarget" Background="Transparent" Margin="0,-10" />
<Border Name="TrackBackground" Background="{TemplateBinding Background}" CornerRadius="{DynamicResource ControlCornerRadius}" Width="{DynamicResource SliderTrackThemeHeight}" HorizontalAlignment="Center" />
</Grid>
</ControlTemplate>
</RepeatButton.Template>
</RepeatButton>
</Track.IncreaseButton>
<Thumb Classes="SliderThumbStyle" Name="SliderThumb" Margin="0" Padding="0" DataContext="{TemplateBinding Value}" Height="{DynamicResource SliderVerticalThumbHeight}" Width="{DynamicResource SliderVerticalThumbWidth}" />
</Track>
</Grid>
</Grid>
</Grid>
</Grid>
</Border>
</Border>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
@ -260,4 +264,12 @@
<Style Selector="Slider:pointerover /template/ RepeatButton#PART_DecreaseButton">
<Setter Property="Background" Value="{DynamicResource SliderTrackValueFillPressed}" />
</Style>
<Style Selector="Slider:error /template/ Thumb.SliderThumbStyle">
<Setter Property="Background" Value="{DynamicResource SystemControlErrorTextForegroundBrush}" />
</Style>
<Style Selector="Slider:error">
<Setter Property="Foreground" Value="{DynamicResource SystemControlErrorTextForegroundBrush}" />
</Style>
</Styles>

20
src/Avalonia.Themes.Fluent/TextBox.xaml

@ -36,16 +36,7 @@
<Setter Property="ContextMenu" Value="{StaticResource DefaultTextBoxContextMenu}" />
<Setter Property="Template">
<ControlTemplate>
<DockPanel>
<!-- TODO bind Content -> Header and ContentTemplate -> HeaderTemplate -->
<ContentPresenter x:Name="PART_HeaderContentPresenter"
DockPanel.Dock="Top"
TextBlock.FontWeight="Normal"
TextBlock.Foreground="{DynamicResource TextControlHeaderForeground}"
IsVisible="False"
Margin="{DynamicResource TextBoxTopHeaderMargin}" />
<DataValidationErrors>
<Panel>
<Border
Name="PART_BorderElement"
@ -66,10 +57,8 @@
FontSize="{TemplateBinding FontSize}"
Text="{TemplateBinding Watermark}"
DockPanel.Dock="Top" />
<DataValidationErrors>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<Panel>
<TextBlock Name="PART_Watermark"
Opacity="0.5"
@ -97,13 +86,12 @@
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
</Panel>
</ScrollViewer>
</DataValidationErrors>
</DockPanel>
<ContentPresenter Grid.Column="2" Grid.ColumnSpan="1" Content="{TemplateBinding InnerRightContent}"/>
</Grid>
</Border>
</Panel>
</DockPanel>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>

164
src/Avalonia.Themes.Fluent/TimePicker.xaml

@ -41,94 +41,96 @@
<Setter Property="VerticalAlignment" Value="Center" />
<Setter Property="Template">
<ControlTemplate>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource TimePickerTopHeaderMargin}"
MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
TextBlock.Foreground="{DynamicResource TimePickerHeaderForeground}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top" />
<DataValidationErrors>
<Grid Name="LayoutRoot" Margin="{TemplateBinding Padding}" RowDefinitions="Auto,*">
<ContentPresenter x:Name="HeaderContentPresenter"
Grid.Row="0"
Content="{TemplateBinding Header}"
ContentTemplate="{TemplateBinding HeaderTemplate}"
Margin="{DynamicResource TimePickerTopHeaderMargin}"
MaxWidth="{DynamicResource TimePickerThemeMaxWidth}"
TextBlock.Foreground="{DynamicResource TimePickerHeaderForeground}"
HorizontalAlignment="Stretch"
VerticalAlignment="Top" />
<Button x:Name="FlyoutButton"
Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{StaticResource TimePickerThemeMinWidth}"
MaxWidth="{StaticResource TimePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Top"
VerticalContentAlignment="Stretch">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CornerRadius="{DynamicResource ControlCornerRadius}" />
</ControlTemplate>
</Button.Template>
<Button x:Name="FlyoutButton"
Grid.Row="1"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
IsEnabled="{TemplateBinding IsEnabled}"
MinWidth="{StaticResource TimePickerThemeMinWidth}"
MaxWidth="{StaticResource TimePickerThemeMaxWidth}"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"
VerticalAlignment="Top"
VerticalContentAlignment="Stretch">
<Button.Template>
<ControlTemplate>
<ContentPresenter Name="ContentPresenter"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}"
Content="{TemplateBinding Content}"
TextBlock.Foreground="{TemplateBinding Foreground}"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
CornerRadius="{DynamicResource ControlCornerRadius}" />
</ControlTemplate>
</Button.Template>
<Grid Name="FlyoutButtonContentGrid">
<!--Ignore col defs here, set in code-->
<Border x:Name="FirstPickerHost" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="HourTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
<Grid Name="FlyoutButtonContentGrid">
<!--Ignore col defs here, set in code-->
<Border x:Name="FirstPickerHost" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="HourTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
<Rectangle Name="FirstColumnDivider"
Fill="{DynamicResource TimePickerSpacerFill}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="1" />
<Border x:Name="SecondPickerHost" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="MinuteTextBlock"
<Rectangle Name="FirstColumnDivider"
Fill="{DynamicResource TimePickerSpacerFill}"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="1" />
<Rectangle Name="SecondColumnDivider"
Fill="{DynamicResource TimePickerSpacerFill}"
HorizontalAlignment="Center"
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="3" />
<Border x:Name="SecondPickerHost" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="MinuteTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}"/>
</Border>
<Border x:Name="ThirdPickerHost" Grid.Column="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="PeriodTextBlock"
<Rectangle Name="SecondColumnDivider"
Fill="{DynamicResource TimePickerSpacerFill}"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
</Grid>
</Button>
Width="{DynamicResource TimePickerSpacerThemeWidth}"
Grid.Column="3" />
<Border x:Name="ThirdPickerHost" Grid.Column="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<TextBlock x:Name="PeriodTextBlock"
HorizontalAlignment="Center"
Padding="{DynamicResource TimePickerHostPadding}"
FontFamily="{TemplateBinding FontFamily}"
FontWeight="{TemplateBinding FontWeight}"
FontSize="{TemplateBinding FontSize}" />
</Border>
</Grid>
</Button>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<TimePickerPresenter Name="PickerPresenter" />
</Popup>
<Popup Name="Popup" WindowManagerAddShadowHint="False"
IsLightDismissEnabled="True" PlacementTarget="{TemplateBinding}"
PlacementMode="Bottom">
<TimePickerPresenter Name="PickerPresenter" />
</Popup>
</Grid>
</Grid>
</DataValidationErrors>
</ControlTemplate>
</Setter>
</Style>
@ -161,6 +163,10 @@
<Style Selector="TimePicker:hasnotime /template/ Button#FlyoutButton TextBlock">
<Setter Property="Foreground" Value="{DynamicResource TextControlPlaceholderForeground}"/>
</Style>
<Style Selector="TimePicker:error /template/ Button#FlyoutButton /template/ ContentPresenter">
<Setter Property="BorderBrush" Value="{DynamicResource SystemControlErrorTextForegroundBrush}"/>
</Style>
<Style Selector="TimePickerPresenter">
<Setter Property="Width" Value="242" />

55
src/Avalonia.Visuals/Media/ConicGradientBrush.cs

@ -0,0 +1,55 @@
using Avalonia.Media.Immutable;
namespace Avalonia.Media
{
/// <summary>
/// Paints an area with a swept circular gradient.
/// </summary>
public sealed class ConicGradientBrush : GradientBrush, IConicGradientBrush
{
/// <summary>
/// Defines the <see cref="Center"/> property.
/// </summary>
public static readonly StyledProperty<RelativePoint> CenterProperty =
AvaloniaProperty.Register<RadialGradientBrush, RelativePoint>(
nameof(Center),
RelativePoint.Center);
/// <summary>
/// Defines the <see cref="Angle"/> property.
/// </summary>
public static readonly StyledProperty<double> AngleProperty =
AvaloniaProperty.Register<RadialGradientBrush, double>(
nameof(Angle),
0);
static ConicGradientBrush()
{
AffectsRender<ConicGradientBrush>(CenterProperty, AngleProperty);
}
/// <summary>
/// Gets or sets the center point of the gradient.
/// </summary>
public RelativePoint Center
{
get { return GetValue(CenterProperty); }
set { SetValue(CenterProperty, value); }
}
/// <summary>
/// Gets or sets the angle of the start and end of the sweep, measured from above the center point.
/// </summary>
public double Angle
{
get { return GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
/// <inheritdoc/>
public override IBrush ToImmutable()
{
return new ImmutableConicGradientBrush(this);
}
}
}

19
src/Avalonia.Visuals/Media/IConicGradientBrush.cs

@ -0,0 +1,19 @@
namespace Avalonia.Media
{
/// <summary>
/// Paints an area with a conic gradient.
/// </summary>
public interface IConicGradientBrush : IGradientBrush
{
/// <summary>
/// Gets the center point for the gradient.
/// </summary>
RelativePoint Center { get; }
/// <summary>
/// Gets the starting angle for the gradient in degrees, measured from
/// the point above the center point.
/// </summary>
double Angle { get; }
}
}

47
src/Avalonia.Visuals/Media/Immutable/ImmutableConicGradientBrush.cs

@ -0,0 +1,47 @@
using System.Collections.Generic;
namespace Avalonia.Media.Immutable
{
/// <summary>
/// A brush that draws with a sweep gradient.
/// </summary>
public class ImmutableConicGradientBrush : ImmutableGradientBrush, IConicGradientBrush
{
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableConicGradientBrush"/> class.
/// </summary>
/// <param name="gradientStops">The gradient stops.</param>
/// <param name="opacity">The opacity of the brush.</param>
/// <param name="spreadMethod">The spread method.</param>
/// <param name="center">The center point for the gradient.</param>
/// <param name="angle">The starting angle for the gradient.</param>
public ImmutableConicGradientBrush(
IReadOnlyList<ImmutableGradientStop> gradientStops,
double opacity = 1,
GradientSpreadMethod spreadMethod = GradientSpreadMethod.Pad,
RelativePoint? center = null,
double angle = 0)
: base(gradientStops, opacity, spreadMethod)
{
Center = center ?? RelativePoint.Center;
Angle = angle;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImmutableConicGradientBrush"/> class.
/// </summary>
/// <param name="source">The brush from which this brush's properties should be copied.</param>
public ImmutableConicGradientBrush(ConicGradientBrush source)
: base(source)
{
Center = source.Center;
Angle = source.Angle;
}
/// <inheritdoc/>
public RelativePoint Center { get; }
/// <inheritdoc/>
public double Angle { get; }
}
}

2
src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github

@ -1 +1 @@
Subproject commit 7d15a9227461cf4d62bc2ed251fcc25c96b28aaf
Subproject commit 5420df861ce6f2be5ead9efa078fe7242ce88f18

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/ResolveByNameExtension.cs

@ -30,7 +30,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
if (provideValueTarget.TargetProperty is IPropertyInfo property)
value.OnCompleted(() => property.Set(target, value.GetResult()));
return null;
return AvaloniaProperty.UnsetValue;
}
}
}

17
src/Skia/Avalonia.Skia/DrawingContextImpl.cs

@ -641,6 +641,23 @@ namespace Avalonia.Skia
}
}
break;
}
case IConicGradientBrush conicGradient:
{
var center = conicGradient.Center.ToPixels(targetSize).ToSKPoint();
// Skia's default is that angle 0 is from the right hand side of the center point
// but we are matching CSS where the vertical point above the center is 0.
var angle = (float)(conicGradient.Angle - 90);
var rotation = SKMatrix.CreateRotationDegrees(angle, center.X, center.Y);
using (var shader =
SKShader.CreateSweepGradient(center, stopColors, stopOffsets, rotation))
{
paintWrapper.Paint.Shader = shader;
}
break;
}
}

6
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -423,6 +423,7 @@ namespace Avalonia.Direct2D1.Media
var solidColorBrush = brush as ISolidColorBrush;
var linearGradientBrush = brush as ILinearGradientBrush;
var radialGradientBrush = brush as IRadialGradientBrush;
var conicGradientBrush = brush as IConicGradientBrush;
var imageBrush = brush as IImageBrush;
var visualBrush = brush as IVisualBrush;
@ -438,6 +439,11 @@ namespace Avalonia.Direct2D1.Media
{
return new RadialGradientBrushImpl(radialGradientBrush, _deviceContext, destinationSize);
}
else if (conicGradientBrush != null)
{
// there is no Direct2D implementation of Conic Gradients so use Radial as a stand-in
return new SolidColorBrushImpl(conicGradientBrush, _deviceContext);
}
else if (imageBrush?.Source != null)
{
return new ImageBrushImpl(

17
src/Windows/Avalonia.Direct2D1/Media/SolidColorBrushImpl.cs

@ -16,5 +16,22 @@ namespace Avalonia.Direct2D1.Media
}
);
}
/// <summary>
/// Direct2D has no ConicGradient implementation so fall back to a solid colour brush based on
/// the first gradient stop.
/// </summary>
public SolidColorBrushImpl(IConicGradientBrush brush, SharpDX.Direct2D1.DeviceContext target)
{
PlatformBrush = new SharpDX.Direct2D1.SolidColorBrush(
target,
brush?.GradientStops[0].Color.ToDirect2D() ?? new SharpDX.Mathematics.Interop.RawColor4(),
new SharpDX.Direct2D1.BrushProperties
{
Opacity = brush != null ? (float)brush.Opacity : 1.0f,
Transform = target.Transform
}
);
}
}
}

32
src/Windows/Avalonia.Win32/Composition/CompositionConnector.cs

@ -1,5 +1,6 @@
using System;
using System.Runtime.InteropServices;
using Avalonia.Logging;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
@ -43,6 +44,37 @@ namespace Avalonia.Win32
[DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options, out IntPtr dispatcherQueueController);
public static CompositionConnector TryCreate(EglPlatformOpenGlInterface egl)
{
const int majorRequired = 10;
const int buildRequired = 16299;
var majorInstalled = Win32Platform.WindowsVersion.Major;
var buildInstalled = Win32Platform.WindowsVersion.Build;
if (majorInstalled >= majorRequired &&
buildInstalled >= buildRequired)
{
try
{
return new CompositionConnector(egl);
}
catch (Exception e)
{
Logger.TryGet(LogEventLevel.Error, "WinUIComposition")?.Log(null, "Unable to initialize WinUI compositor: {0}", e);
return null;
}
}
var osVersionNotice = $"Windows {majorRequired} Build {buildRequired} is required. Your machine has Windows {majorInstalled} Build {buildInstalled} installed.";
Logger.TryGet(LogEventLevel.Warning, "WinUIComposition")?.Log(null,
$"Unable to initialize WinUI compositor: {osVersionNotice}");
return null;
}
public CompositionConnector(EglPlatformOpenGlInterface egl)
{
EnsureDispatcherQueue();

6
src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs

@ -1017,6 +1017,9 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool ValidateRect(IntPtr hWnd, IntPtr lpRect);
[DllImport("user32.dll")]
public static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern bool IsWindowEnabled(IntPtr hWnd);
@ -1050,6 +1053,9 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll")]
public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr GetActiveWindow();
[DllImport("user32.dll", SetLastError = true)]
public static extern IntPtr SetActiveWindow(IntPtr hWnd);

10
src/Windows/Avalonia.Win32/Win32GlManager.cs

@ -1,3 +1,4 @@
using System;
using Avalonia.OpenGL;
using Avalonia.OpenGL.Angle;
using Avalonia.OpenGL.Egl;
@ -23,11 +24,12 @@ namespace Avalonia.Win32
var egl = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
if (egl is { } &&
opts?.UseWindowsUIComposition == true &&
Win32Platform.WindowsVersion.Major >= 10 &&
Win32Platform.WindowsVersion.Build >= 16299)
opts?.UseWindowsUIComposition == true)
{
AvaloniaLocator.CurrentMutable.BindToSelf(new CompositionConnector(egl));
var compositionConnector = CompositionConnector.TryCreate(egl);
if (compositionConnector != null)
AvaloniaLocator.CurrentMutable.BindToSelf(compositionConnector);
}
return egl;

18
src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

@ -65,6 +65,24 @@ namespace Avalonia.Win32
return IntPtr.Zero;
}
// Based on https://github.com/dotnet/wpf/blob/master/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Window.cs#L4270-L4337
// We need to enable parent window before destroying child window to prevent OS from activating a random window behind us.
// This is described here: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-enablewindow#remarks
// Our window closed callback will set enabled state to a correct value after child window gets destroyed.
// We need to verify if parent is still alive (perhaps it got destroyed somehow).
if (_parent != null && IsWindow(_parent._hwnd))
{
var wasActive = GetActiveWindow() == _hwnd;
_parent.SetEnabled(true);
// We also need to activate our parent window since again OS might try to activate a window behind if it is not set.
if (wasActive)
{
SetActiveWindow(_parent._hwnd);
}
}
break;
}

34
tests/Avalonia.ReactiveUI.UnitTests/AvaloniaActivationForViewFetcherTest.cs

@ -74,44 +74,26 @@ namespace Avalonia.ReactiveUI.UnitTests
{
public ActivatableWindow()
{
InitializeComponent();
Assert.IsType<Border>(Content);
Content = new Border();
this.WhenActivated(disposables => { });
}
private void InitializeComponent()
{
AvaloniaRuntimeXamlLoader.Load(@"
<Window xmlns='https://github.com/avaloniaui'>
<Border/>
</Window>", null, this);
}
}
public class ActivatableUserControl : ReactiveUserControl<ActivatableViewModel>
{
public ActivatableUserControl()
{
InitializeComponent();
Assert.IsType<Border>(Content);
Content = new Border();
this.WhenActivated(disposables => { });
}
private void InitializeComponent()
{
AvaloniaRuntimeXamlLoader.Load(@"
<UserControl xmlns='https://github.com/avaloniaui'>
<Border/>
</UserControl>", null, this);
}
}
public AvaloniaActivationForViewFetcherTest()
{
Locator.CurrentMutable.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
}
public AvaloniaActivationForViewFetcherTest() =>
Locator
.CurrentMutable
.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
[Fact]
public void Visual_Element_Is_Activated_And_Deactivated()

79
tests/Avalonia.ReactiveUI.UnitTests/ReactiveUserControlTest.cs

@ -1,4 +1,4 @@
using Avalonia.Controls;
using System.Reactive.Disposables;
using Avalonia.UnitTests;
using ReactiveUI;
using Splat;
@ -8,14 +8,37 @@ namespace Avalonia.ReactiveUI.UnitTests
{
public class ReactiveUserControlTest
{
public class ExampleViewModel : ReactiveObject { }
public class ExampleViewModel : ReactiveObject, IActivatableViewModel
{
public bool IsActive { get; private set; }
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public ExampleViewModel() => this.WhenActivated(disposables =>
{
IsActive = true;
Disposable
.Create(() => IsActive = false)
.DisposeWith(disposables);
});
}
public class ExampleView : ReactiveUserControl<ExampleViewModel> { }
public ReactiveUserControlTest() =>
Locator
.CurrentMutable
.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
[Fact]
public void Data_Context_Should_Stay_In_Sync_With_Reactive_User_Control_View_Model()
{
var root = new TestRoot();
var view = new ExampleView();
root.Child = view;
var viewModel = new ExampleViewModel();
Assert.Null(view.ViewModel);
@ -26,6 +49,56 @@ namespace Avalonia.ReactiveUI.UnitTests
view.DataContext = null;
Assert.Null(view.ViewModel);
Assert.Null(view.DataContext);
view.ViewModel = viewModel;
Assert.Equal(viewModel, view.ViewModel);
Assert.Equal(viewModel, view.DataContext);
view.ViewModel = null;
Assert.Null(view.ViewModel);
Assert.Null(view.DataContext);
}
[Fact]
public void Should_Start_With_NotNull_Activated_ViewModel()
{
var root = new TestRoot();
var view = new ExampleView {ViewModel = new ExampleViewModel()};
Assert.False(view.ViewModel.IsActive);
root.Child = view;
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.True(view.ViewModel.IsActive);
root.Child = null;
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.False(view.ViewModel.IsActive);
}
[Fact]
public void Should_Start_With_NotNull_Activated_DataContext()
{
var root = new TestRoot();
var view = new ExampleView {DataContext = new ExampleViewModel()};
Assert.False(view.ViewModel.IsActive);
root.Child = view;
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.True(view.ViewModel.IsActive);
root.Child = null;
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.False(view.ViewModel.IsActive);
}
}
}
}

87
tests/Avalonia.ReactiveUI.UnitTests/ReactiveWindowTest.cs

@ -1,4 +1,4 @@
using Avalonia.Controls;
using System.Reactive.Disposables;
using Avalonia.UnitTests;
using ReactiveUI;
using Splat;
@ -8,10 +8,30 @@ namespace Avalonia.ReactiveUI.UnitTests
{
public class ReactiveWindowTest
{
public class ExampleViewModel : ReactiveObject { }
public class ExampleViewModel : ReactiveObject, IActivatableViewModel
{
public bool IsActive { get; private set; }
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public ExampleViewModel() => this.WhenActivated(disposables =>
{
IsActive = true;
Disposable
.Create(() => IsActive = false)
.DisposeWith(disposables);
});
}
public class ExampleWindow : ReactiveWindow<ExampleViewModel> { }
public ReactiveWindowTest() =>
Locator
.CurrentMutable
.RegisterConstant(
new AvaloniaActivationForViewFetcher(),
typeof(IActivationForViewFetcher));
[Fact]
public void Data_Context_Should_Stay_In_Sync_With_Reactive_Window_View_Model()
{
@ -19,16 +39,73 @@ namespace Avalonia.ReactiveUI.UnitTests
{
var view = new ExampleWindow();
var viewModel = new ExampleViewModel();
view.Show();
Assert.Null(view.ViewModel);
Assert.Null(view.DataContext);
view.DataContext = viewModel;
Assert.Equal(view.ViewModel, viewModel);
Assert.Equal(view.DataContext, viewModel);
Assert.Equal(viewModel, view.ViewModel);
Assert.Equal(viewModel, view.DataContext);
view.DataContext = null;
Assert.Null(view.ViewModel);
Assert.Null(view.DataContext);
view.ViewModel = viewModel;
Assert.Equal(viewModel, view.ViewModel);
Assert.Equal(viewModel, view.DataContext);
view.ViewModel = null;
Assert.Null(view.ViewModel);
Assert.Null(view.DataContext);
}
}
[Fact]
public void Should_Start_With_NotNull_Activated_ViewModel()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var view = new ExampleWindow { ViewModel = new ExampleViewModel() };
Assert.False(view.ViewModel.IsActive);
view.Show();
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.True(view.ViewModel.IsActive);
view.Close();
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.False(view.ViewModel.IsActive);
}
}
[Fact]
public void Should_Start_With_NotNull_Activated_DataContext()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var view = new ExampleWindow { DataContext = new ExampleViewModel() };
Assert.False(view.ViewModel.IsActive);
view.Show();
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.True(view.ViewModel.IsActive);
view.Close();
Assert.NotNull(view.ViewModel);
Assert.NotNull(view.DataContext);
Assert.False(view.ViewModel.IsActive);
}
}
}
}
}

178
tests/Avalonia.RenderTests/Media/ConicGradientBrushTests.cs

@ -0,0 +1,178 @@
using Avalonia.Controls;
using Avalonia.Media;
using System.Threading.Tasks;
using Xunit;
#if AVALONIA_SKIA
namespace Avalonia.Skia.RenderTests
#else
namespace Avalonia.Direct2D1.RenderTests.Media
#endif
{
public class ConicGradientBrushTests : TestBase
{
public ConicGradientBrushTests() : base(@"Media\ConicGradientBrush")
{
}
[Fact]
public async Task ConicGradientBrush_RedBlue()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Blue, Offset = 1 }
}
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ConicGradientBrush_RedBlue_Rotation()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Blue, Offset = 1 }
},
Angle = 90
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ConicGradientBrush_RedBlue_Center()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Blue, Offset = 1 }
},
Center = new RelativePoint(0.25, 0.25, RelativeUnit.Relative)
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ConicGradientBrush_RedBlue_Center_and_Rotation()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Blue, Offset = 1 }
},
Center = new RelativePoint(0.25, 0.25, RelativeUnit.Relative),
Angle = 90
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ConicGradientBrush_RedBlue_SoftEdge()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Blue, Offset = 0.5 },
new GradientStop { Color = Colors.Red, Offset = 1 },
}
}
}
};
await RenderToFile(target);
CompareImages();
}
[Fact]
public async Task ConicGradientBrush_Umbrella()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Child = new Border
{
Background = new ConicGradientBrush
{
GradientStops =
{
new GradientStop { Color = Colors.Red, Offset = 0 },
new GradientStop { Color = Colors.Yellow, Offset = 0.1667 },
new GradientStop { Color = Colors.Lime, Offset = 0.3333 },
new GradientStop { Color = Colors.Aqua, Offset = 0.5000 },
new GradientStop { Color = Colors.Blue, Offset = 0.6667 },
new GradientStop { Color = Colors.Magenta, Offset = 0.8333 },
new GradientStop { Color = Colors.Red, Offset = 1 },
}
}
}
};
await RenderToFile(target);
CompareImages();
}
}
}

2
tests/Avalonia.UnitTests/Avalonia.UnitTests.csproj

@ -7,7 +7,7 @@
<IsPackable>false</IsPackable>
<LangVersion>latest</LangVersion>
<AssemblyOriginatorKeyFile>..\..\build\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>True</SignAssembly>
<SignAssembly>false</SignAssembly>
</PropertyGroup>
<ItemGroup>
<EmbeddedResource Include="..\Avalonia.UnitTests\Assets\*.ttf" />

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center_and_Rotation.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Rotation.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_SoftEdge.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Direct2D1/Media/ConicGradientBrush/ConicGradientBrush_Umbrella.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 601 B

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Center_and_Rotation.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.6 KiB

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_Rotation.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_RedBlue_SoftEdge.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

BIN
tests/TestFiles/Skia/Media/ConicGradientBrush/ConicGradientBrush_Umbrella.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Loading…
Cancel
Save