Browse Source

Merge branch 'master' into feature/add_handling_input_message_previewer

pull/4418/head
Nikita Tsukanov 5 years ago
committed by GitHub
parent
commit
6e4dc871bd
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      Avalonia.sln.DotSettings
  2. 4
      azure-pipelines.yml
  3. 2
      build.ps1
  4. 2
      build/ApiDiff.props
  5. BIN
      build/Assets/Icon.png
  6. 9
      build/SharedVersion.props
  7. 4
      build/SourceLink.props
  8. 4
      build/XUnit.props
  9. BIN
      build/avalonia.snk
  10. 1
      dirs.proj
  11. 6
      native/Avalonia.Native/src/OSX/window.mm
  12. 14
      nukebuild/Build.cs
  13. 6
      nukebuild/BuildTasksPatcher.cs
  14. 2
      nukebuild/_build.csproj
  15. 3
      packages/Avalonia/AvaloniaBuildTasks.targets
  16. 2
      readme.md
  17. 20
      samples/BindingDemo/App.xaml.cs
  18. 1
      samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj
  19. 10
      samples/ControlCatalog.Desktop/Program.cs
  20. 3
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  21. 5
      samples/ControlCatalog.NetCore/Program.cs
  22. 10
      samples/ControlCatalog/App.xaml
  23. 2
      samples/ControlCatalog/App.xaml.cs
  24. 3
      samples/ControlCatalog/MainView.xaml
  25. 4
      samples/ControlCatalog/MainView.xaml.cs
  26. 16
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml
  27. 58
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  28. 11
      samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml
  29. 13
      samples/ControlCatalog/Pages/ComboBoxPage.xaml
  30. 17
      samples/ControlCatalog/Pages/DataGridPage.xaml
  31. 20
      samples/ControlCatalog/Pages/DateTimePickerPage.xaml
  32. 42
      samples/ControlCatalog/Pages/LabelsPage.axaml
  33. 43
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  34. 10
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml
  35. 1
      samples/ControlCatalog/Pages/OpenGlPage.xaml.cs
  36. 16
      samples/ControlCatalog/Pages/RelativePanelPage.axaml
  37. 10
      samples/ControlCatalog/Pages/SliderPage.xaml
  38. 4
      samples/ControlCatalog/Pages/TextBlockPage.xaml
  39. 47
      samples/ControlCatalog/Pages/TextBoxPage.xaml
  40. 10
      samples/Previewer/App.xaml.cs
  41. 15
      samples/Previewer/Program.cs
  42. 17
      samples/RenderDemo/App.xaml.cs
  43. 8
      samples/RenderDemo/MainWindow.xaml
  44. 6
      samples/RenderDemo/Pages/GlyphRunPage.xaml
  45. 10
      samples/RenderDemo/Pages/GlyphRunPage.xaml.cs
  46. 48
      samples/RenderDemo/ViewModels/MainWindowViewModel.cs
  47. 2
      samples/Sandbox/Program.cs
  48. 8
      samples/VirtualizationDemo/App.xaml.cs
  49. 20
      samples/VirtualizationDemo/Program.cs
  50. 8
      samples/interop/Direct3DInteropSample/App.paml.cs
  51. 21
      samples/interop/Direct3DInteropSample/Program.cs
  52. 3
      samples/interop/NativeEmbedSample/NativeEmbedSample.csproj
  53. 2
      src/Avalonia.Animation/KeySplineTypeConverter.cs
  54. 5
      src/Avalonia.Animation/Properties/AssemblyInfo.cs
  55. 4
      src/Avalonia.Base/ApiCompatBaseline.txt
  56. 17
      src/Avalonia.Base/AvaloniaLocator.cs
  57. 12
      src/Avalonia.Base/AvaloniaObject.cs
  58. 17
      src/Avalonia.Base/AvaloniaProperty.cs
  59. 48
      src/Avalonia.Base/AvaloniaProperty`1.cs
  60. 4
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  61. 44
      src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
  62. 17
      src/Avalonia.Base/DirectPropertyBase.cs
  63. 14
      src/Avalonia.Base/Logging/TraceLogSink.cs
  64. 39
      src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs
  65. 8
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  66. 2
      src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj
  67. 8
      src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs
  68. 26
      src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs
  69. 5
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  70. 24
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  71. 2
      src/Avalonia.Controls.DataGrid/DataGridCell.cs
  72. 34
      src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
  73. 1
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  74. 15
      src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs
  75. 39
      src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
  76. 2
      src/Avalonia.Controls.DataGrid/DataGridRow.cs
  77. 2
      src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs
  78. 2
      src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs
  79. 231
      src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
  80. 7
      src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
  81. 21
      src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
  82. 22
      src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs
  83. 8
      src/Avalonia.Controls/ApiCompatBaseline.txt
  84. 96
      src/Avalonia.Controls/AutoCompleteBox.cs
  85. 2
      src/Avalonia.Controls/Button.cs
  86. 2
      src/Avalonia.Controls/ButtonSpinner.cs
  87. 2
      src/Avalonia.Controls/Calendar/CalendarButton.cs
  88. 9
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  89. 2
      src/Avalonia.Controls/Calendar/CalendarDayButton.cs
  90. 81
      src/Avalonia.Controls/Calendar/CalendarItem.cs
  91. 2
      src/Avalonia.Controls/Chrome/CaptionButtons.cs
  92. 2
      src/Avalonia.Controls/Chrome/TitleBar.cs
  93. 4
      src/Avalonia.Controls/ComboBox.cs
  94. 13
      src/Avalonia.Controls/ContextMenu.cs
  95. 2
      src/Avalonia.Controls/DataValidationErrors.cs
  96. 4
      src/Avalonia.Controls/DateTimePickers/DatePicker.cs
  97. 4
      src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs
  98. 4
      src/Avalonia.Controls/DateTimePickers/TimePicker.cs
  99. 3
      src/Avalonia.Controls/Expander.cs
  100. 6
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

1
Avalonia.sln.DotSettings

@ -37,4 +37,5 @@
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypeParameters/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String> <s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=TypesAndNamespaces/@EntryIndexedValue">&lt;Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EDaemon_002ESettings_002EMigration_002ESwaWarningsModeSettingsMigrate/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary> <s:Boolean x:Key="/Default/UserDictionary/Words/=Avalonia/@EntryIndexedValue">True</s:Boolean></wpf:ResourceDictionary>

4
azure-pipelines.yml

@ -31,6 +31,8 @@ jobs:
condition: not(canceled()) condition: not(canceled())
- job: macOS - job: macOS
variables:
SolutionDir: '$(Build.SourcesDirectory)'
pool: pool:
vmImage: 'macOS-10.14' vmImage: 'macOS-10.14'
steps: steps:
@ -97,6 +99,8 @@ jobs:
- job: Windows - job: Windows
pool: pool:
vmImage: 'windows-2019' vmImage: 'windows-2019'
variables:
SolutionDir: '$(Build.SourcesDirectory)'
steps: steps:
- task: UseDotNet@2 - task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.401' displayName: 'Use .NET Core SDK 3.1.401'

2
build.ps1

@ -62,6 +62,8 @@ else {
} else { } else {
ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath }
} }
$env:PATH="$DotNetDirectory;$env:PATH"
} }
Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)"

2
build/ApiDiff.props

@ -7,6 +7,6 @@
<ItemGroup> <ItemGroup>
<PackageDownload Include="$(NugetPackageName)" Version="[$(ApiContractPackageVersion)]" /> <PackageDownload Include="$(NugetPackageName)" Version="[$(ApiContractPackageVersion)]" />
<PackageReference Include="Microsoft.DotNet.ApiCompat" Version="5.0.0-beta.20372.2" PrivateAssets="All" /> <PackageReference Include="Microsoft.DotNet.ApiCompat" Version="5.0.0-beta.20372.2" PrivateAssets="All" />
<ResolvedMatchingContract Include="$(NuGetPackageRoot)\$(NugetPackageName.ToLower())\$(ApiContractPackageVersion)\lib\$(TargetFramework)\$(AssemblyName).dll" /> <ResolvedMatchingContract Include="$(NuGetPackageRoot)\$(NugetPackageName.ToLowerInvariant())\$(ApiContractPackageVersion)\lib\$(TargetFramework)\$(AssemblyName).dll" />
</ItemGroup> </ItemGroup>
</Project> </Project>

BIN
build/Assets/Icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

9
build/SharedVersion.props

@ -10,10 +10,17 @@
<NoWarn>CS1591</NoWarn> <NoWarn>CS1591</NoWarn>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageIconUrl>https://avatars2.githubusercontent.com/u/14075148?s=200</PackageIconUrl> <PackageIcon>Icon.png</PackageIcon>
<PackageDescription>Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS.</PackageDescription> <PackageDescription>Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS.</PackageDescription>
<PackageTags>avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin</PackageTags> <PackageTags>avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin</PackageTags>
<PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes> <PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
<RepositoryType>git</RepositoryType> <RepositoryType>git</RepositoryType>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>false</SignAssembly>
<DefineConstants Condition="$(SignAssembly) == true">$(DefineConstants);SIGNED_BUILD</DefineConstants>
</PropertyGroup> </PropertyGroup>
<ItemGroup Label="PackageIcon">
<None Include="$(MSBuildThisFileDirectory)/Assets/Icon.png" Pack="true" PackagePath=""/>
</ItemGroup>
</Project> </Project>

4
build/SourceLink.props

@ -1,5 +1,5 @@
<Project> <Project>
<ItemGroup> <ItemGroup>
<PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.0" PrivateAssets="All" /> <PackageReference Include="SourceLink.Create.CommandLine" Version="2.8.3" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
</Project> </Project>

4
build/XUnit.props

@ -11,4 +11,8 @@
<PackageReference Include="Xunit.SkippableFact" Version="1.3.6" /> <PackageReference Include="Xunit.SkippableFact" Version="1.3.6" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
</ItemGroup> </ItemGroup>
<PropertyGroup>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>False</SignAssembly>
</PropertyGroup>
</Project> </Project>

BIN
build/avalonia.snk

Binary file not shown.

1
dirs.proj

@ -21,6 +21,7 @@
<ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'"> <ItemGroup Condition="!$([MSBuild]::IsOsPlatform('Windows')) OR '$(MSBuildRuntimeType)' != 'Full'">
<ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" /> <ProjectReference Remove="src/Windows/Avalonia.Win32.Interop/Avalonia.Win32.Interop.csproj" />
<ProjectReference Remove="samples/interop/**/*.*proj" /> <ProjectReference Remove="samples/interop/**/*.*proj" />
<ProjectReference Remove="samples/ControlCatalog.Desktop/*.*proj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

6
native/Avalonia.Native/src/OSX/window.mm

@ -1338,6 +1338,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
} }
_parent->BaseEvents->RunRenderPriorityJobs(); _parent->BaseEvents->RunRenderPriorityJobs();
if (_parent == nullptr)
{
return;
}
_parent->BaseEvents->Paint(); _parent->BaseEvents->Paint();
} }

14
nukebuild/Build.cs

@ -138,9 +138,19 @@ partial class Build : NukeBuild
.SetWorkingDirectory(webappDir) .SetWorkingDirectory(webappDir)
.SetCommand("dist")); .SetCommand("dist"));
}); });
Target Compile => _ => _ Target CompileNative => _ => _
.DependsOn(Clean) .DependsOn(Clean)
.OnlyWhenStatic(() => EnvironmentInfo.IsOsx)
.Executes(() =>
{
var project = $"{RootDirectory}/native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/";
var args = $"-project {project} -configuration {Parameters.Configuration} CONFIGURATION_BUILD_DIR={RootDirectory}/Build/Products/Release";
ProcessTasks.StartProcess("xcodebuild", args).AssertZeroExitCode();
});
Target Compile => _ => _
.DependsOn(Clean, CompileNative)
.DependsOn(CompileHtmlPreviewer) .DependsOn(CompileHtmlPreviewer)
.Executes(async () => .Executes(async () =>
{ {

6
nukebuild/BuildTasksPatcher.cs

@ -29,7 +29,11 @@ public class BuildTasksPatcher
InputAssemblies = new[] InputAssemblies = new[]
{ {
temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0] temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0]
.FullyQualifiedName .FullyQualifiedName,
typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName,
typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName,
typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName
}, },
SearchDirectories = new string[0], SearchDirectories = new string[0],
OutputFile = output OutputFile = output

2
nukebuild/_build.csproj

@ -16,7 +16,7 @@
<PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " /> <PackageReference Include="vswhere" Version="2.6.7" Condition=" '$(OS)' == 'Windows_NT' " />
<PackageReference Include="ILRepack.NETStandard" Version="2.0.4" /> <PackageReference Include="ILRepack.NETStandard" Version="2.0.4" />
<!-- Keep in sync with Avalonia.Build.Tasks --> <!-- Keep in sync with Avalonia.Build.Tasks -->
<PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" /> <PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Pharmacist.Core" Version="1.8.1" /> <PackageReference Include="Pharmacist.Core" Version="1.8.1" />
</ItemGroup> </ItemGroup>

3
packages/Avalonia/AvaloniaBuildTasks.targets

@ -87,6 +87,9 @@
ProjectDirectory="$(MSBuildProjectDirectory)" ProjectDirectory="$(MSBuildProjectDirectory)"
VerifyIl="$(AvaloniaXamlIlVerifyIl)" VerifyIl="$(AvaloniaXamlIlVerifyIl)"
ReportImportance="$(AvaloniaXamlReportImportance)" ReportImportance="$(AvaloniaXamlReportImportance)"
AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)"
SignAssembly="$(SignAssembly)"
DelaySign="$(DelaySign)"
/> />
<Exec <Exec
Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'" Condition="'$(_AvaloniaUseExternalMSBuild)' == 'true'"

2
readme.md

@ -39,7 +39,7 @@ Examples of UIs built with Avalonia
## JetBrains Rider ## JetBrains Rider
If you need to develop Avalonia app with JetBrains Rider, go and *vote* on [this issue](https://youtrack.jetbrains.com/issue/RIDER-39247) in their tracker. JetBrains won't do things without their users telling them that they want the feature, so only **YOU** can make it happen. If you need to develop Avalonia app with JetBrains Rider you can use latest Rider [preview builds](https://www.jetbrains.com/rider/nextversion/).
## Bleeding Edge Builds ## Bleeding Edge Builds

20
samples/BindingDemo/App.xaml.cs

@ -1,6 +1,5 @@
using System;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
@ -13,13 +12,20 @@ namespace BindingDemo
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private static void Main() public override void OnFrameworkInitializationCompleted()
{ {
AppBuilder.Configure<App>() if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug() .LogToTrace();
.Start<MainWindow>();
}
} }
} }

1
samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj

@ -3,6 +3,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net461</TargetFramework> <TargetFramework>net461</TargetFramework>
<PlatformTarget>x64</PlatformTarget>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

10
samples/ControlCatalog.Desktop/Program.cs

@ -10,19 +10,15 @@ namespace ControlCatalog
internal class Program internal class Program
{ {
[STAThread] [STAThread]
static void Main(string[] args) public static int Main(string[] args)
{ => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again.
BuildAvaloniaApp().Start<MainWindow>();
}
/// <summary> /// <summary>
/// This method is needed for IDE previewer infrastructure /// This method is needed for IDE previewer infrastructure
/// </summary> /// </summary>
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.LogToDebug() .LogToTrace()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI(); .UseReactiveUI();

3
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -11,9 +11,8 @@
<ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" /> <ProjectReference Include="..\..\src\Avalonia.Dialogs\Avalonia.Dialogs.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" /> <ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" /> <ProjectReference Include="..\ControlCatalog\ControlCatalog.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" /> <ProjectReference Include="..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" /> <PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
</ItemGroup> </ItemGroup>

5
samples/ControlCatalog.NetCore/Program.cs

@ -7,12 +7,11 @@ using System.Threading.Tasks;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Dialogs;
using Avalonia.Headless; using Avalonia.Headless;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Skia;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Dialogs;
namespace ControlCatalog.NetCore namespace ControlCatalog.NetCore
{ {
@ -121,7 +120,7 @@ namespace ControlCatalog.NetCore
.UseSkia() .UseSkia()
.UseReactiveUI() .UseReactiveUI()
.UseManagedSystemDialogs() .UseManagedSystemDialogs()
.LogToDebug(); .LogToTrace();
static void SilenceConsole() static void SilenceConsole()
{ {

10
samples/ControlCatalog/App.xaml

@ -12,6 +12,16 @@
<Style Selector="TextBlock.h3"> <Style Selector="TextBlock.h3">
<Setter Property="FontSize" Value="12" /> <Setter Property="FontSize" Value="12" />
</Style> </Style>
<Style Selector="Label.h1">
<Setter Property="FontSize" Value="16" />
<Setter Property="FontWeight" Value="Medium" />
</Style>
<Style Selector="Label.h2">
<Setter Property="FontSize" Value="14" />
</Style>
<Style Selector="Label.h3">
<Setter Property="FontSize" Value="12" />
</Style>
<StyleInclude Source="/SideBar.xaml"/> <StyleInclude Source="/SideBar.xaml"/>
</Application.Styles> </Application.Styles>
</Application> </Application>

2
samples/ControlCatalog/App.xaml.cs

@ -81,7 +81,7 @@ namespace ControlCatalog
public override void Initialize() public override void Initialize()
{ {
Styles.Insert(0, FluentDark); Styles.Insert(0, FluentLight);
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }

3
samples/ControlCatalog/MainView.xaml

@ -44,6 +44,7 @@
ScrollViewer.HorizontalScrollBarVisibility="Disabled"> ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<pages:ItemsRepeaterPage/> <pages:ItemsRepeaterPage/>
</TabItem> </TabItem>
<TabItem Header="Label"><pages:LabelsPage/></TabItem>
<TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem> <TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
<TabItem Header="ListBox" <TabItem Header="ListBox"
ScrollViewer.VerticalScrollBarVisibility="Disabled"> ScrollViewer.VerticalScrollBarVisibility="Disabled">
@ -77,8 +78,8 @@
<ComboBoxItem>Full Decorations</ComboBoxItem> <ComboBoxItem>Full Decorations</ComboBoxItem>
</ComboBox> </ComboBox>
<ComboBox x:Name="Themes" SelectedIndex="0"> <ComboBox x:Name="Themes" SelectedIndex="0">
<ComboBoxItem>Fluent - Dark</ComboBoxItem>
<ComboBoxItem>Fluent - Light</ComboBoxItem> <ComboBoxItem>Fluent - Light</ComboBoxItem>
<ComboBoxItem>Fluent - Dark</ComboBoxItem>
<ComboBoxItem>Simple - Light</ComboBoxItem> <ComboBoxItem>Simple - Light</ComboBoxItem>
<ComboBoxItem>Simple - Dark</ComboBoxItem> <ComboBoxItem>Simple - Dark</ComboBoxItem>
</ComboBox> </ComboBox>

4
samples/ControlCatalog/MainView.xaml.cs

@ -38,10 +38,10 @@ namespace ControlCatalog
switch (themes.SelectedIndex) switch (themes.SelectedIndex)
{ {
case 0: case 0:
Application.Current.Styles[0] = App.FluentDark; Application.Current.Styles[0] = App.FluentLight;
break; break;
case 1: case 1:
Application.Current.Styles[0] = App.FluentLight; Application.Current.Styles[0] = App.FluentDark;
break; break;
case 2: case 2:
Application.Current.Styles[0] = App.DefaultLight; Application.Current.Styles[0] = App.DefaultLight;

16
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml

@ -1,5 +1,6 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=netstandard"
x:Class="ControlCatalog.Pages.AutoCompleteBoxPage"> x:Class="ControlCatalog.Pages.AutoCompleteBoxPage">
<StackPanel Orientation="Vertical" Spacing="4"> <StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">AutoCompleteBox</TextBlock> <TextBlock Classes="h1">AutoCompleteBox</TextBlock>
@ -51,6 +52,21 @@
Width="200" Width="200"
Margin="0,0,0,8" Margin="0,0,0,8"
FilterMode="None"/> FilterMode="None"/>
<TextBlock Text="Custom Autocomplete"/>
<AutoCompleteBox Name="CustomAutocompleteBox"
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> </StackPanel>
</StackPanel> </StackPanel>

58
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -92,13 +92,28 @@ namespace ControlCatalog.Pages
} }
public StateData[] States { get; private set; } public StateData[] States { get; private set; }
private LinkedList<string>[] BuildAllSentences()
{
return new string[]
{
"Hello world",
"No this is Patrick",
"Never gonna give you up",
"How does one patch KDE2 under FreeBSD"
}
.Select(x => new LinkedList<string>(x.Split(' ')))
.ToArray();
}
public LinkedList<string>[] Sentences { get; private set; }
public AutoCompleteBoxPage() public AutoCompleteBoxPage()
{ {
this.InitializeComponent(); this.InitializeComponent();
States = BuildAllStates(); States = BuildAllStates();
Sentences = BuildAllSentences();
foreach (AutoCompleteBox box in GetAllAutoCompleteBox()) foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox"))
{ {
box.Items = States; box.Items = States;
} }
@ -116,6 +131,11 @@ namespace ControlCatalog.Pages
var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox"); var asyncBox = this.FindControl<AutoCompleteBox>("AsyncBox");
asyncBox.AsyncPopulator = PopulateAsync; asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.FindControl<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord;
} }
private IEnumerable<AutoCompleteBox> GetAllAutoCompleteBox() private IEnumerable<AutoCompleteBox> GetAllAutoCompleteBox()
{ {
@ -137,6 +157,42 @@ namespace ControlCatalog.Pages
.ToList(); .ToList();
} }
private bool LastWordContains(string searchText, string item)
{
var words = searchText.Split(' ');
var options = Sentences.Select(x => x.First).ToArray();
for (var i = 0; i < words.Length; ++i)
{
var word = words[i];
for (var j = 0; j < options.Length; ++j)
{
var option = options[j];
if (option == null)
continue;
if (i == words.Length - 1)
{
options[j] = option.Value.ToLower().Contains(word.ToLower()) ? option : null;
}
else
{
options[j] = option.Value.Equals(word, StringComparison.InvariantCultureIgnoreCase) ? option.Next : null;
}
}
}
return options.Any(x => x != null && x.Value == item);
}
private string AppendWord(string text, string item)
{
string[] parts = text.Split(' ');
if (parts.Length == 0)
return item;
parts[parts.Length - 1] = item;
return string.Join(" ", parts);
}
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);

11
samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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"> <StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ButtonSpinner</TextBlock> <TextBlock Classes="h1">ButtonSpinner</TextBlock>
@ -19,6 +20,14 @@
ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}"> ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/> <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="Everest"/>
</ButtonSpinner> </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>
</StackPanel> </StackPanel>

13
samples/ControlCatalog/Pages/ComboBoxPage.xaml

@ -1,6 +1,7 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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"> <StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">ComboBox</TextBlock> <TextBlock Classes="h1">ComboBox</TextBlock>
<TextBlock Classes="h2">A drop-down list.</TextBlock> <TextBlock Classes="h2">A drop-down list.</TextBlock>
@ -35,6 +36,16 @@
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </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>
</StackPanel> </StackPanel>

17
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -11,12 +11,17 @@
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" /> <Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</Style> </Style>
</UserControl.Styles> </UserControl.Styles>
<Grid RowDefinitions="Auto,*"> <Grid RowDefinitions="Auto,Auto,*">
<StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0"> <StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
<TextBlock Classes="h1">DataGrid</TextBlock> <TextBlock Classes="h1">DataGrid</TextBlock>
<TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock> <TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock>
</StackPanel> </StackPanel>
<TabControl Grid.Row="1"> <StackPanel Grid.Row="1" Spacing="4" Orientation="Horizontal" IsVisible="{Binding #EditableTab.IsSelected}">
<TextBlock Text="FontSize:" VerticalAlignment="Center"/>
<Slider x:Name="FontSizeSlider" Minimum="5" Maximum="30" Value="14" Width="100" VerticalAlignment="Center" />
<CheckBox x:Name="IsThreeStateCheckBox" IsChecked="False" Content="IsThreeState"/>
</StackPanel>
<TabControl Grid.Row="2">
<TabItem Header="DataGrid"> <TabItem Header="DataGrid">
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All"> <DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
<DataGrid.Columns> <DataGrid.Columns>
@ -39,13 +44,13 @@
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
</TabItem> </TabItem>
<TabItem Header="Editable"> <TabItem x:Name="EditableTab" Header="Editable">
<Grid RowDefinitions="*,Auto"> <Grid RowDefinitions="*,Auto">
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0"> <DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" /> <DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" /> <DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" /> <DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" IsThreeState="{Binding #IsThreeStateCheckBox.IsChecked, Mode=OneWay}" />
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
<Button Grid.Row="1" Name="btnAdd" Margin="12,0,12,12" Content="Add" HorizontalAlignment="Right" /> <Button Grid.Row="1" Name="btnAdd" Margin="12,0,12,12" Content="Add" HorizontalAlignment="Right" />

20
samples/ControlCatalog/Pages/DateTimePickerPage.xaml

@ -2,6 +2,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 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" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="ControlCatalog.Pages.DateTimePickerPage"> x:Class="ControlCatalog.Pages.DateTimePickerPage">
<StackPanel Orientation="Vertical" Spacing="4" HorizontalAlignment="Stretch"> <StackPanel Orientation="Vertical" Spacing="4" HorizontalAlignment="Stretch">
@ -30,6 +31,16 @@
</Panel> </Panel>
</StackPanel> </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> <TextBlock FontSize="18">A DatePicker with day formatted and year hidden.</TextBlock>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">
<Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}" <Border BorderBrush="{DynamicResource SystemControlHighlightBaseLowBrush}"
@ -66,6 +77,15 @@
</TextBlock> </TextBlock>
</Panel> </Panel>
</StackPanel> </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> <TextBlock FontSize="18">A TimePicker with a header and minute increments specified.</TextBlock>
<StackPanel Orientation="Vertical"> <StackPanel Orientation="Vertical">

42
samples/ControlCatalog/Pages/LabelsPage.axaml

@ -0,0 +1,42 @@
<UserControl xmlns="https://github.com/avaloniaui"
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"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="250"
x:Class="ControlCatalog.Pages.LabelsPage"
x:Name="_labelsPage">
<UserControl.Styles>
<Style Selector="Label">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="6,3,0,3"/>
</Style>
<Style Selector="TextBox">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,3,6,3"/>
</Style>
<Style Selector="CheckBox">
<Setter Property="VerticalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,3,6,3"/>
</Style>
<Style Selector="Button[IsDefault=true]">
<Setter Property="Background" Value="{DynamicResource HighlightBrush}"/>
</Style>
</UserControl.Styles>
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Hidden">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" RowDefinitions="Auto,Auto,Auto,Auto,Auto,*" ColumnDefinitions="Auto,6,*" Width="246">
<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="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="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>
<StackPanel Grid.Column="0" Grid.Row="4" Grid.ColumnSpan="3" Orientation="Horizontal" HorizontalAlignment="Right">
<Button IsCancel="True" Command="{Binding #_labelsPage.DoCancel}">Cancel</Button>
<Button IsDefault="True" Command="{Binding #_labelsPage.DoSave}">Save</Button>
</StackPanel>
</Grid>
</ScrollViewer>
</UserControl>

43
samples/ControlCatalog/Pages/LabelsPage.axaml.cs

@ -0,0 +1,43 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.Models;
using ReactiveUI;
namespace ControlCatalog.Pages
{
public class LabelsPage : UserControl
{
private Person _person;
public LabelsPage()
{
CreateDefaultPerson();
this.InitializeComponent();
}
private void CreateDefaultPerson()
{
DataContext = _person = new Person
{
FirstName = "John",
LastName = "Doe",
IsBanned = true,
};
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
public void DoSave()
{
}
public void DoCancel()
{
CreateDefaultPerson();
}
}
}

10
samples/ControlCatalog/Pages/NumericUpDownPage.xaml

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

1
samples/ControlCatalog/Pages/OpenGlPage.xaml.cs

@ -7,6 +7,7 @@ using System.Runtime.InteropServices;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.OpenGL; using Avalonia.OpenGL;
using Avalonia.OpenGL.Controls;
using Avalonia.Platform.Interop; using Avalonia.Platform.Interop;
using Avalonia.Threading; using Avalonia.Threading;
using static Avalonia.OpenGL.GlConsts; using static Avalonia.OpenGL.GlConsts;

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"> <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"/> <TextBlock Text="Rect6" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect7 (RightOf Rect1)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect8 (Below Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </Border>
<Border Name="Rect9" Background="Blue" Height="140" Width="460" RelativePanel.AlignHorizontalCenterWithPanel="True" RelativePanel.AlignVerticalCenterWithPanel="True"> <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"/> <TextBlock Text="Rect9" Padding="10" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Top"/>
</Border> </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 Text="Rect14 (RightOf Rect9, AlignVerticalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock.RenderTransform> <TextBlock.RenderTransform>
<TransformGroup> <TransformGroup>
@ -41,19 +41,19 @@
</TextBlock.RenderTransform> </TextBlock.RenderTransform>
</TextBlock> </TextBlock>
</Border> </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"/> <TextBlock Text="Rect11 (AlignBottomWith Rect9, AlignHorizontalCenterWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect12 (Below Rect8, AlignLeftWith Rect7)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect13 (Below Rect12, AlignRightWith Rect12)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect14 (Above Rect9, AlignRightWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </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"/> <TextBlock Text="Rect15 (LeftOf Rect2, AlignTopWith Rect9)" Padding="10,0" Foreground="White" FontWeight="Bold" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border> </Border>
</RelativePanel> </RelativePanel>

10
samples/ControlCatalog/Pages/SliderPage.xaml

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

4
samples/ControlCatalog/Pages/TextBlockPage.xaml

@ -18,8 +18,8 @@
</StackPanel.Styles> </StackPanel.Styles>
<Border> <Border>
<StackPanel Width="200" Spacing="8"> <StackPanel Width="200" Spacing="8">
<TextBlock TextTrimming="CharacterEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/> <TextBlock Margin="0 0 10 0" TextTrimming="CharacterEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBlock TextTrimming="WordEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/> <TextBlock Margin="0 0 10 0" TextTrimming="WordEllipsis" Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/>
<TextBlock Text="Left aligned text" TextAlignment="Left" /> <TextBlock Text="Left aligned text" TextAlignment="Left" />
<TextBlock Text="Center aligned text" TextAlignment="Center" /> <TextBlock Text="Center aligned text" TextAlignment="Center" />
<TextBlock Text="Right aligned text" TextAlignment="Right" /> <TextBlock Text="Right aligned text" TextAlignment="Right" />

47
samples/ControlCatalog/Pages/TextBoxPage.xaml

@ -1,9 +1,10 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 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"> <StackPanel Orientation="Vertical" Spacing="4">
<TextBlock Classes="h1">TextBox</TextBlock> <Label Classes="h1">TextBox</Label>
<TextBlock Classes="h2">A control into which the user can input text</TextBlock> <Label Classes="h2">A control into which the user can input text</Label>
<StackPanel Orientation="Horizontal" <StackPanel Orientation="Horizontal"
Margin="0,16,0,0" Margin="0,16,0,0"
@ -11,12 +12,18 @@
Spacing="16"> Spacing="16">
<StackPanel Orientation="Vertical" Spacing="8"> <StackPanel Orientation="Vertical" Spacing="8">
<TextBox Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit." Width="200" /> <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="Watermark" />
<TextBox Width="200" <TextBox Width="200"
Watermark="Floating Watermark" Watermark="Floating Watermark"
UseFloatingWatermark="True" UseFloatingWatermark="True"
Text="Lorem ipsum dolor sit amet, consectetur adipiscing elit."/> 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" <TextBox Width="200"
Watermark="Password Box" Watermark="Password Box"
@ -38,24 +45,24 @@
Text="Multiline TextBox with TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." /> Text="Multiline TextBox with TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
<TextBox AcceptsReturn="True" Width="200" Height="125" <TextBox AcceptsReturn="True" Width="200" Height="125"
Text="Multiline TextBox with no TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." /> Text="Multiline TextBox with no TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
<TextBox Classes="clearButton" Text="Clear Content" Width="200" FontWeight="Normal" FontStyle="Normal" Watermark="Watermark" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/> <TextBox Classes="clearButton" Text="Clear Content" Width="200" FontWeight="Normal" FontStyle="Normal" Watermark="Watermark" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" Spacing="8"> <StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">resm fonts</TextBlock> <Label Classes="h2" Target="{Binding #firstResMFont}">res_m fonts</Label>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/> <TextBox Width="200" x:Name="firstResMFont" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/> <TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="resm:ControlCatalog.Assets.Fonts?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-Italic.ttf?assembly=ControlCatalog#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-Italic.ttf?assembly=ControlCatalog#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-*.ttf?assembly=ControlCatalog#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="resm:ControlCatalog.Assets.Fonts.SourceSansPro-*.ttf?assembly=ControlCatalog#Source Sans Pro"/>
</StackPanel> </StackPanel>
<StackPanel Orientation="Vertical" Spacing="8"> <StackPanel Orientation="Vertical" Spacing="8">
<TextBlock Classes="h2">res fonts</TextBlock> <Label Classes="h2" Target="{Binding #firstResFont}">_res fonts</Label>
<TextBox Width="200" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/> <TextBox Width="200" x:Name="firstResFont" Text="Custom font regular" FontWeight="Normal" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/> <TextBox Width="200" Text="Custom font bold" FontWeight="Bold" FontStyle="Normal" FontFamily="avares://ControlCatalog/Assets/Fonts#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic" FontWeight="Normal" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-Italic.ttf#Source Sans Pro"/>
<TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/> <TextBox Width="200" Text="Custom font italic bold" FontWeight="Bold" FontStyle="Italic" FontFamily="/Assets/Fonts/SourceSansPro-*.ttf#Source Sans Pro"/>
</StackPanel>
</StackPanel> </StackPanel>
</StackPanel>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

10
samples/Previewer/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
namespace Previewer namespace Previewer
@ -9,6 +10,13 @@ namespace Previewer
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
} }
} }

15
samples/Previewer/Program.cs

@ -1,13 +1,14 @@
using System; using Avalonia;
using Avalonia;
namespace Previewer namespace Previewer
{ {
class Program class Program
{ {
static void Main(string[] args) public static AppBuilder BuildAvaloniaApp()
{ => AppBuilder.Configure<App>()
AppBuilder.Configure<App>().UsePlatformDetect().Start<MainWindow>(); .UsePlatformDetect();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
} }
} }

17
samples/RenderDemo/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
@ -11,15 +12,27 @@ namespace RenderDemo
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
// TODO: Make this work with GTK/Skia/Cairo depending on command-line args // TODO: Make this work with GTK/Skia/Cairo depending on command-line args
// again. // again.
static void Main(string[] args) => BuildAvaloniaApp().Start<MainWindow>(); static void Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
// App configuration, used by the entry point and previewer // App configuration, used by the entry point and previewer
static AppBuilder BuildAvaloniaApp() static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() => AppBuilder.Configure<App>()
.With(new Win32PlatformOptions
{
OverlayPopups = true,
})
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug(); .LogToTrace();
} }
} }

8
samples/RenderDemo/MainWindow.xaml

@ -3,8 +3,8 @@
x:Class="RenderDemo.MainWindow" x:Class="RenderDemo.MainWindow"
Title="AvaloniaUI Rendering Test" Title="AvaloniaUI Rendering Test"
xmlns:pages="clr-namespace:RenderDemo.Pages" xmlns:pages="clr-namespace:RenderDemo.Pages"
Width="800" Width="{Binding Width, Mode=TwoWay}"
Height="600"> Height="{Binding Height, Mode=TwoWay}">
<DockPanel> <DockPanel>
<Menu DockPanel.Dock="Top"> <Menu DockPanel.Dock="Top">
<MenuItem Header="Rendering"> <MenuItem Header="Rendering">
@ -24,6 +24,10 @@
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
</MenuItem> </MenuItem>
<MenuItem Header="Tests">
<MenuItem Header="Resize window"
Command="{Binding ResizeWindow}"/>
</MenuItem>
</Menu> </Menu>
<TabControl Classes="sidebar"> <TabControl Classes="sidebar">
<TabItem Header="Animations"> <TabItem Header="Animations">

6
samples/RenderDemo/Pages/GlyphRunPage.xaml

@ -6,9 +6,9 @@
x:Class="RenderDemo.Pages.GlyphRunPage"> x:Class="RenderDemo.Pages.GlyphRunPage">
<Border <Border
Background="White"> Background="White">
<DrawingPresenter <Image
x:Name="drawingPresenter" x:Name="imageControl"
Stretch="None"> Stretch="None">
</DrawingPresenter> </Image>
</Border> </Border>
</UserControl> </UserControl>

10
samples/RenderDemo/Pages/GlyphRunPage.xaml.cs

@ -9,7 +9,7 @@ namespace RenderDemo.Pages
{ {
public class GlyphRunPage : UserControl public class GlyphRunPage : UserControl
{ {
private DrawingPresenter _drawingPresenter; private Image _imageControl;
private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface;
private readonly Random _rand = new Random(); private readonly Random _rand = new Random();
private ushort[] _glyphIndices = new ushort[1]; private ushort[] _glyphIndices = new ushort[1];
@ -25,7 +25,8 @@ namespace RenderDemo.Pages
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
_drawingPresenter = this.FindControl<DrawingPresenter>("drawingPresenter"); _imageControl = this.FindControl<Image>("imageControl");
_imageControl.Source = new DrawingImage();
DispatcherTimer.Run(() => DispatcherTimer.Run(() =>
{ {
@ -61,7 +62,6 @@ namespace RenderDemo.Pages
{ {
Foreground = Brushes.Black, Foreground = Brushes.Black,
GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices), GlyphRun = new GlyphRun(_glyphTypeface, _fontSize, _glyphIndices),
BaselineOrigin = new Point(0, -_glyphTypeface.Ascent * scale)
}; };
drawingGroup.Children.Add(glyphRunDrawing); drawingGroup.Children.Add(glyphRunDrawing);
@ -69,12 +69,12 @@ namespace RenderDemo.Pages
var geometryDrawing = new GeometryDrawing var geometryDrawing = new GeometryDrawing
{ {
Pen = new Pen(Brushes.Black), Pen = new Pen(Brushes.Black),
Geometry = new RectangleGeometry { Rect = glyphRunDrawing.GlyphRun.Bounds } Geometry = new RectangleGeometry { Rect = new Rect(glyphRunDrawing.GlyphRun.Size) }
}; };
drawingGroup.Children.Add(geometryDrawing); drawingGroup.Children.Add(geometryDrawing);
_drawingPresenter.Drawing = drawingGroup; (_imageControl.Source as DrawingImage).Drawing = drawingGroup;
} }
} }
} }

48
samples/RenderDemo/ViewModels/MainWindowViewModel.cs

@ -1,5 +1,6 @@
using System; using System.Reactive;
using System.Reactive; using System.Threading.Tasks;
using ReactiveUI; using ReactiveUI;
namespace RenderDemo.ViewModels namespace RenderDemo.ViewModels
@ -8,26 +9,61 @@ namespace RenderDemo.ViewModels
{ {
private bool drawDirtyRects = false; private bool drawDirtyRects = false;
private bool drawFps = true; private bool drawFps = true;
private double width = 800;
private double height = 600;
public MainWindowViewModel() public MainWindowViewModel()
{ {
ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects); ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps); ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps);
ResizeWindow = ReactiveCommand.CreateFromTask(ResizeWindowAsync);
} }
public bool DrawDirtyRects public bool DrawDirtyRects
{ {
get { return drawDirtyRects; } get => drawDirtyRects;
set { this.RaiseAndSetIfChanged(ref drawDirtyRects, value); } set => this.RaiseAndSetIfChanged(ref drawDirtyRects, value);
} }
public bool DrawFps public bool DrawFps
{ {
get { return drawFps; } get => drawFps;
set { this.RaiseAndSetIfChanged(ref drawFps, value); } set => this.RaiseAndSetIfChanged(ref drawFps, value);
}
public double Width
{
get => width;
set => this.RaiseAndSetIfChanged(ref width, value);
}
public double Height
{
get => height;
set => this.RaiseAndSetIfChanged(ref height, value);
} }
public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; } public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; }
public ReactiveCommand<Unit, bool> ToggleDrawFps { get; } public ReactiveCommand<Unit, bool> ToggleDrawFps { get; }
public ReactiveCommand<Unit, Unit> ResizeWindow { get; }
private async Task ResizeWindowAsync()
{
for (int i = 0; i < 30; i++)
{
Width += 10;
Height += 5;
await Task.Delay(10);
}
await Task.Delay(10);
for (int i = 0; i < 30; i++)
{
Width -= 10;
Height -= 5;
await Task.Delay(10);
}
}
} }
} }

2
samples/Sandbox/Program.cs

@ -10,7 +10,7 @@ namespace Sandbox
AppBuilder.Configure<App>() AppBuilder.Configure<App>()
.UsePlatformDetect() .UsePlatformDetect()
.UseReactiveUI() .UseReactiveUI()
.LogToDebug() .LogToTrace()
.StartWithClassicDesktopLifetime(args); .StartWithClassicDesktopLifetime(args);
} }
} }

8
samples/VirtualizationDemo/App.xaml.cs

@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
namespace VirtualizationDemo namespace VirtualizationDemo
@ -9,5 +10,12 @@ namespace VirtualizationDemo
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
} }
} }

20
samples/VirtualizationDemo/Program.cs

@ -1,19 +1,17 @@
using System; using Avalonia;
using Avalonia;
using Avalonia.Controls;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace VirtualizationDemo namespace VirtualizationDemo
{ {
class Program class Program
{ {
static void Main(string[] args) public static AppBuilder BuildAvaloniaApp()
{ => AppBuilder.Configure<App>()
AppBuilder.Configure<App>() .UsePlatformDetect()
.UsePlatformDetect() .UseReactiveUI()
.UseReactiveUI() .LogToTrace();
.LogToDebug()
.Start<MainWindow>(); public static int Main(string[] args)
} => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
} }
} }

8
samples/interop/Direct3DInteropSample/App.paml.cs

@ -1,4 +1,5 @@
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
namespace Direct3DInteropSample namespace Direct3DInteropSample
@ -9,5 +10,12 @@ namespace Direct3DInteropSample
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.MainWindow = new MainWindow();
base.OnFrameworkInitializationCompleted();
}
} }
} }

21
samples/interop/Direct3DInteropSample/Program.cs

@ -1,19 +1,16 @@
using System; using Avalonia;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia;
namespace Direct3DInteropSample namespace Direct3DInteropSample
{ {
class Program class Program
{ {
static void Main(string[] args) public static AppBuilder BuildAvaloniaApp()
{ => AppBuilder.Configure<App>()
AppBuilder.Configure<App>() .With(new Win32PlatformOptions { UseDeferredRendering = false })
.With(new Win32PlatformOptions {UseDeferredRendering = false}) .UseWin32()
.UseWin32().UseDirect2D1().Start<MainWindow>(); .UseDirect2D1();
}
public static int Main(string[] args)
=> BuildAvaloniaApp().StartWithClassicDesktopLifetime(args);
} }
} }

3
samples/interop/NativeEmbedSample/NativeEmbedSample.csproj

@ -9,11 +9,10 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="MonoMac.NetStandard" Version="0.0.4" /> <PackageReference Include="MonoMac.NetStandard" Version="0.0.4" />
<ProjectReference Include="..\..\..\src\Avalonia.Desktop\Avalonia.Desktop.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" /> <ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" /> <ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" /> <ProjectReference Include="..\..\..\src\Avalonia.X11\Avalonia.X11.csproj" />
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2019013001" /> <PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
<AvaloniaResource Include="**\*.xaml"> <AvaloniaResource Include="**\*.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>

2
src/Avalonia.Animation/KeySplineTypeConverter.cs

@ -19,7 +19,7 @@ namespace Avalonia.Animation
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{ {
return KeySpline.Parse((string)value, culture); return KeySpline.Parse((string)value, CultureInfo.InvariantCulture);
} }
} }
} }

5
src/Avalonia.Animation/Properties/AssemblyInfo.cs

@ -6,5 +6,10 @@ using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")]
#if SIGNED_BUILD
[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else
[assembly: InternalsVisibleTo("Avalonia.LeakTests")] [assembly: InternalsVisibleTo("Avalonia.LeakTests")]
[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")]
#endif

4
src/Avalonia.Base/ApiCompatBaseline.txt

@ -0,0 +1,4 @@
Compat issues with assembly Avalonia.Base:
CannotAddAbstractMembers : Member 'protected System.IObservable<Avalonia.AvaloniaPropertyChangedEventArgs> Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract.
TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract.
Total Issues: 2

17
src/Avalonia.Base/AvaloniaLocator.cs

@ -54,6 +54,23 @@ namespace Avalonia
return _locator; return _locator;
} }
public AvaloniaLocator ToLazy<TImlp>(Func<TImlp> func) where TImlp : TService
{
var constructed = false;
TImlp instance = default;
_locator._registry[typeof (TService)] = () =>
{
if (!constructed)
{
instance = func();
constructed = true;
}
return instance;
};
return _locator;
}
public AvaloniaLocator ToSingleton<TImpl>() where TImpl : class, TService, new() public AvaloniaLocator ToSingleton<TImpl>() where TImpl : class, TService, new()
{ {
TImpl instance = null; TImpl instance = null;

12
src/Avalonia.Base/AvaloniaObject.cs

@ -113,16 +113,8 @@ namespace Avalonia
/// <param name="binding">The binding information.</param> /// <param name="binding">The binding information.</param>
public IBinding this[IndexerDescriptor binding] public IBinding this[IndexerDescriptor binding]
{ {
get get { return new IndexerBinding(this, binding.Property, binding.Mode); }
{ set { this.Bind(binding.Property, value); }
return new IndexerBinding(this, binding.Property, binding.Mode);
}
set
{
var sourceBinding = value as IBinding;
this.Bind(binding.Property, sourceBinding);
}
} }
public bool CheckAccess() => Dispatcher.UIThread.CheckAccess(); public bool CheckAccess() => Dispatcher.UIThread.CheckAccess();

17
src/Avalonia.Base/AvaloniaProperty.cs

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reactive.Subjects;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Data.Core; using Avalonia.Data.Core;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -18,7 +17,6 @@ namespace Avalonia
public static readonly object UnsetValue = new UnsetValueType(); public static readonly object UnsetValue = new UnsetValueType();
private static int s_nextId; private static int s_nextId;
private readonly Subject<AvaloniaPropertyChangedEventArgs> _changed;
private readonly PropertyMetadata _defaultMetadata; private readonly PropertyMetadata _defaultMetadata;
private readonly Dictionary<Type, PropertyMetadata> _metadata; private readonly Dictionary<Type, PropertyMetadata> _metadata;
private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>(); private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>();
@ -50,7 +48,6 @@ namespace Avalonia
throw new ArgumentException("'name' may not contain periods."); throw new ArgumentException("'name' may not contain periods.");
} }
_changed = new Subject<AvaloniaPropertyChangedEventArgs>();
_metadata = new Dictionary<Type, PropertyMetadata>(); _metadata = new Dictionary<Type, PropertyMetadata>();
Name = name; Name = name;
@ -77,7 +74,6 @@ namespace Avalonia
Contract.Requires<ArgumentNullException>(source != null); Contract.Requires<ArgumentNullException>(source != null);
Contract.Requires<ArgumentNullException>(ownerType != null); Contract.Requires<ArgumentNullException>(ownerType != null);
_changed = source._changed;
_metadata = new Dictionary<Type, PropertyMetadata>(); _metadata = new Dictionary<Type, PropertyMetadata>();
Name = source.Name; Name = source.Name;
@ -139,7 +135,7 @@ namespace Avalonia
/// An observable that is fired when this property changes on any /// An observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance. /// <see cref="AvaloniaObject"/> instance.
/// </value> /// </value>
public IObservable<AvaloniaPropertyChangedEventArgs> Changed => _changed; public IObservable<AvaloniaPropertyChangedEventArgs> Changed => GetChanged();
/// <summary> /// <summary>
/// Gets a method that gets called before and after the property starts being notified on an /// Gets a method that gets called before and after the property starts being notified on an
@ -474,15 +470,6 @@ namespace Avalonia
public abstract void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data) public abstract void Accept<TData>(IAvaloniaPropertyVisitor<TData> vistor, ref TData data)
where TData : struct; where TData : struct;
/// <summary>
/// Notifies the <see cref="Changed"/> observable.
/// </summary>
/// <param name="e">The observable arguments.</param>
internal void NotifyChanged(AvaloniaPropertyChangedEventArgs e)
{
_changed.OnNext(e);
}
/// <summary> /// <summary>
/// Routes an untyped ClearValue call to a typed call. /// Routes an untyped ClearValue call to a typed call.
/// </summary> /// </summary>
@ -553,6 +540,8 @@ namespace Avalonia
_hasMetadataOverrides = true; _hasMetadataOverrides = true;
} }
protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
private PropertyMetadata GetMetadataWithOverrides(Type type) private PropertyMetadata GetMetadataWithOverrides(Type type)
{ {
if (type is null) if (type is null)

48
src/Avalonia.Base/AvaloniaProperty`1.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Reactive.Subjects;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -10,6 +11,8 @@ namespace Avalonia
/// <typeparam name="TValue">The value type of the property.</typeparam> /// <typeparam name="TValue">The value type of the property.</typeparam>
public abstract class AvaloniaProperty<TValue> : AvaloniaProperty public abstract class AvaloniaProperty<TValue> : AvaloniaProperty
{ {
private readonly Subject<AvaloniaPropertyChangedEventArgs<TValue>> _changed;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class. /// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary> /// </summary>
@ -24,22 +27,61 @@ namespace Avalonia
Action<IAvaloniaObject, bool> notifying = null) Action<IAvaloniaObject, bool> notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying) : base(name, typeof(TValue), ownerType, metadata, notifying)
{ {
_changed = new Subject<AvaloniaPropertyChangedEventArgs<TValue>>();
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty"/> class. /// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary> /// </summary>
/// <param name="source">The property to copy.</param> /// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param> /// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param> /// <param name="metadata">Optional overridden metadata.</param>
[Obsolete("Use constructor with AvaloniaProperty<TValue> instead.", true)]
protected AvaloniaProperty( protected AvaloniaProperty(
AvaloniaProperty source, AvaloniaProperty source,
Type ownerType, Type ownerType,
PropertyMetadata metadata)
: this(source as AvaloniaProperty<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
protected AvaloniaProperty(
AvaloniaProperty<TValue> source,
Type ownerType,
PropertyMetadata metadata) PropertyMetadata metadata)
: base(source, ownerType, metadata) : base(source, ownerType, metadata)
{ {
_changed = source._changed;
}
/// <summary>
/// Gets an observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance.
/// </summary>
/// <value>
/// An observable that is fired when this property changes on any
/// <see cref="AvaloniaObject"/> instance.
/// </value>
public new IObservable<AvaloniaPropertyChangedEventArgs<TValue>> Changed => _changed;
/// <summary>
/// Notifies the <see cref="Changed"/> observable.
/// </summary>
/// <param name="e">The observable arguments.</param>
internal void NotifyChanged(AvaloniaPropertyChangedEventArgs<TValue> e)
{
_changed.OnNext(e);
} }
protected override IObservable<AvaloniaPropertyChangedEventArgs> GetChanged() => Changed;
protected BindingValue<object> TryConvert(object value) protected BindingValue<object> TryConvert(object value)
{ {
if (value == UnsetValue) if (value == UnsetValue)

4
src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs

@ -63,12 +63,12 @@ namespace Avalonia.Data.Core.Plugins
{ {
if (errors.Count == 1) if (errors.Count == 1)
{ {
return new ValidationException(errors[0].ErrorMessage); return new DataValidationException(errors[0].ErrorMessage);
} }
else else
{ {
return new AggregateException( return new AggregateException(
errors.Select(x => new ValidationException(x.ErrorMessage))); errors.Select(x => new DataValidationException(x.ErrorMessage)));
} }
} }
} }

44
src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Reflection; using System.Reflection;
using Avalonia.Utilities; using Avalonia.Utilities;
@ -11,8 +12,11 @@ namespace Avalonia.Data.Core.Plugins
/// </summary> /// </summary>
public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{ {
private readonly Dictionary<(Type, string), PropertyInfo> _propertyLookup =
new Dictionary<(Type, string), PropertyInfo>();
/// <inheritdoc/> /// <inheritdoc/>
public bool Match(object obj, string propertyName) => GetPropertyWithName(obj.GetType(), propertyName) != null; public bool Match(object obj, string propertyName) => GetFirstPropertyWithName(obj.GetType(), propertyName) != null;
/// <summary> /// <summary>
/// Starts monitoring the value of a property on an object. /// Starts monitoring the value of a property on an object.
@ -30,7 +34,7 @@ namespace Avalonia.Data.Core.Plugins
reference.TryGetTarget(out object instance); reference.TryGetTarget(out object instance);
var p = GetPropertyWithName(instance.GetType(), propertyName); var p = GetFirstPropertyWithName(instance.GetType(), propertyName);
if (p != null) if (p != null)
{ {
@ -44,12 +48,40 @@ namespace Avalonia.Data.Core.Plugins
} }
} }
private static PropertyInfo GetPropertyWithName(Type type, string propertyName) private PropertyInfo GetFirstPropertyWithName(Type type, string propertyName)
{ {
const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | var key = (type, propertyName);
BindingFlags.Static | BindingFlags.Instance;
if (!_propertyLookup.TryGetValue(key, out PropertyInfo propertyInfo))
{
propertyInfo = TryFindAndCacheProperty(type, propertyName);
}
return propertyInfo;
}
private PropertyInfo TryFindAndCacheProperty(Type type, string propertyName)
{
PropertyInfo found = null;
const BindingFlags bindingFlags =
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
var properties = type.GetProperties(bindingFlags);
foreach (PropertyInfo propertyInfo in properties)
{
if (propertyInfo.Name == propertyName)
{
found = propertyInfo;
break;
}
}
_propertyLookup.Add((type, propertyName), found);
return type.GetProperty(propertyName, bindingFlags); return found;
} }
private class Accessor : PropertyAccessorBase, IWeakSubscriber<PropertyChangedEventArgs> private class Accessor : PropertyAccessorBase, IWeakSubscriber<PropertyChangedEventArgs>

17
src/Avalonia.Base/DirectPropertyBase.cs

@ -32,15 +32,30 @@ namespace Avalonia
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="AvaloniaProperty"/> class. /// Initializes a new instance of the <see cref="DirectPropertyBase{TValue}"/> class.
/// </summary> /// </summary>
/// <param name="source">The property to copy.</param> /// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param> /// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param> /// <param name="metadata">Optional overridden metadata.</param>
[Obsolete("Use constructor with DirectPropertyBase<TValue> instead.", true)]
protected DirectPropertyBase( protected DirectPropertyBase(
AvaloniaProperty source, AvaloniaProperty source,
Type ownerType, Type ownerType,
PropertyMetadata metadata) PropertyMetadata metadata)
: this(source as DirectPropertyBase<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DirectPropertyBase{TValue}"/> class.
/// </summary>
/// <param name="source">The property to copy.</param>
/// <param name="ownerType">The new owner type.</param>
/// <param name="metadata">Optional overridden metadata.</param>
protected DirectPropertyBase(
DirectPropertyBase<TValue> source,
Type ownerType,
PropertyMetadata metadata)
: base(source, ownerType, metadata) : base(source, ownerType, metadata)
{ {
} }

14
src/Avalonia.Base/Logging/DebugLogSink.cs → src/Avalonia.Base/Logging/TraceLogSink.cs

@ -6,12 +6,12 @@ using Avalonia.Utilities;
namespace Avalonia.Logging namespace Avalonia.Logging
{ {
public class DebugLogSink : ILogSink public class TraceLogSink : ILogSink
{ {
private readonly LogEventLevel _level; private readonly LogEventLevel _level;
private readonly IList<string> _areas; private readonly IList<string> _areas;
public DebugLogSink( public TraceLogSink(
LogEventLevel minimumLevel, LogEventLevel minimumLevel,
IList<string> areas = null) IList<string> areas = null)
{ {
@ -28,7 +28,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<object, object, object>(area, messageTemplate, source)); Trace.WriteLine(Format<object, object, object>(area, messageTemplate, source));
} }
} }
@ -36,7 +36,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0)); Trace.WriteLine(Format<T0, object, object>(area, messageTemplate, source, propertyValue0));
} }
} }
@ -44,7 +44,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1)); Trace.WriteLine(Format<T0, T1, object>(area, messageTemplate, source, propertyValue0, propertyValue1));
} }
} }
@ -52,7 +52,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2)); Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2));
} }
} }
@ -60,7 +60,7 @@ namespace Avalonia.Logging
{ {
if (IsEnabled(level, area)) if (IsEnabled(level, area))
{ {
Debug.WriteLine(Format(area, messageTemplate, source, propertyValues)); Trace.WriteLine(Format(area, messageTemplate, source, propertyValues));
} }
} }

39
src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs

@ -0,0 +1,39 @@
using System;
namespace Avalonia.Metadata
{
/// <summary>
/// Use to predefine the prefix associated to an xml namespace in a xaml file
/// </summary>
/// <remarks>
/// example:
/// [assembly: XmlnsPrefix("https://github.com/avaloniaui", "av")]
/// xaml:
/// xmlns:av="https://github.com/avaloniaui"
/// </remarks>
[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
public sealed class XmlnsPrefixAttribute : Attribute
{
/// <summary>
/// Constructor
/// </summary>
/// <param name="xmlNamespace">XML namespce</param>
/// <param name="prefix">recommended prefix</param>
public XmlnsPrefixAttribute(string xmlNamespace, string prefix)
{
XmlNamespace = xmlNamespace ?? throw new ArgumentNullException(nameof(xmlNamespace));
Prefix = prefix ?? throw new ArgumentNullException(nameof(prefix));
}
/// <summary>
/// XML Namespace
/// </summary>
public string XmlNamespace { get; }
/// <summary>
/// New Xml Namespace
/// </summary>
public string Prefix { get; }
}
}

8
src/Avalonia.Base/Properties/AssemblyInfo.cs

@ -5,8 +5,16 @@ using System.Runtime.CompilerServices;
using Avalonia.Metadata; using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")]
#if SIGNED_BUILD
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
#endif

2
src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj

@ -59,7 +59,7 @@
</Compile> </Compile>
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\**\obj\**\*.cs" />
<Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" /> <Compile Remove="../Markup/Avalonia.Markup.Xaml.Loader\xamlil.github\src\XamlX\IL\SreTypeSystem.cs" />
<PackageReference Include="Avalonia.Unofficial.Cecil" Version="20190417.2.0" PrivateAssets="All" /> <PackageReference Include="Mono.Cecil" Version="0.11.2" />
<PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" /> <PackageReference Include="Microsoft.Build.Framework" Version="15.1.548" PrivateAssets="All" />
</ItemGroup> </ItemGroup>
</Project> </Project>

8
src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs

@ -39,7 +39,9 @@ namespace Avalonia.Build.Tasks
var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input, var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input,
File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(), File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(),
ProjectDirectory, OutputPath, VerifyIl, outputImportance); ProjectDirectory, OutputPath, VerifyIl, outputImportance,
(SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null
);
if (!res.Success) if (!res.Success)
return false; return false;
if (!res.WrittenFile) if (!res.WrittenFile)
@ -73,6 +75,10 @@ namespace Avalonia.Build.Tasks
public string OutputPath { get; set; } public string OutputPath { get; set; }
public bool VerifyIl { get; set; } public bool VerifyIl { get; set; }
public string AssemblyOriginatorKeyFile { get; set; }
public bool SignAssembly { get; set; }
public bool DelaySign { get; set; }
public string ReportImportance { get; set; } public string ReportImportance { get; set; }

26
src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs

@ -42,7 +42,7 @@ namespace Avalonia.Build.Tasks
} }
public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory, public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory,
string output, bool verifyIl, MessageImportance logImportance) string output, bool verifyIl, MessageImportance logImportance, string strongNameKey)
{ {
var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input); var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input);
var asm = typeSystem.TargetAssemblyDefinition; var asm = typeSystem.TargetAssemblyDefinition;
@ -345,6 +345,20 @@ namespace Avalonia.Build.Tasks
} }
res.Remove(); res.Remove();
} }
// Technically that's a hack, but it fixes corert incompatibility caused by deterministic builds
int dupeCounter = 1;
foreach (var grp in typeDef.NestedTypes.GroupBy(x => x.Name))
{
if (grp.Count() > 1)
{
foreach (var dupe in grp)
dupe.Name += "_dup" + dupeCounter++;
}
}
return true; return true;
} }
@ -361,10 +375,12 @@ namespace Avalonia.Build.Tasks
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull)); loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull));
loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
asm.Write(output, new WriterParameters
{ var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols };
WriteSymbols = asm.MainModule.HasSymbols if (!string.IsNullOrWhiteSpace(strongNameKey))
}); writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey);
asm.Write(output, writerParameters);
return new CompileResult(true, true); return new CompileResult(true, true);
} }

5
src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt

@ -0,0 +1,5 @@
Compat issues with assembly Avalonia.Controls.DataGrid:
MembersMustExist : Member 'public Avalonia.StyledProperty<System.String> Avalonia.StyledProperty<System.String> Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
Total Issues: 3

24
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -24,12 +24,14 @@ using Avalonia.Input.Platform;
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Layout; using Avalonia.Layout;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// Displays data in a customizable grid. /// Displays data in a customizable grid.
/// </summary> /// </summary>
[PseudoClasses(":invalid", ":empty-rows", ":empty-columns")]
public partial class DataGrid : TemplatedControl public partial class DataGrid : TemplatedControl
{ {
private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter"; private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";
@ -709,6 +711,7 @@ namespace Avalonia.Controls
DisplayData = new DataGridDisplayData(this); DisplayData = new DataGridDisplayData(this);
ColumnsInternal = CreateColumnsInstance(); ColumnsInternal = CreateColumnsInstance();
ColumnsInternal.CollectionChanged += ColumnsInternal_CollectionChanged;
RowHeightEstimate = DATAGRID_defaultRowHeight; RowHeightEstimate = DATAGRID_defaultRowHeight;
RowDetailsHeightEstimate = 0; RowDetailsHeightEstimate = 0;
@ -725,6 +728,8 @@ namespace Avalonia.Controls
CurrentCellCoordinates = new DataGridCellCoordinates(-1, -1); CurrentCellCoordinates = new DataGridCellCoordinates(-1, -1);
RowGroupHeaderHeightEstimate = DATAGRID_defaultRowHeight; RowGroupHeaderHeightEstimate = DATAGRID_defaultRowHeight;
UpdatePseudoClasses();
} }
private void SetValueNoCallback<T>(AvaloniaProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue) private void SetValueNoCallback<T>(AvaloniaProperty<T> property, T value, BindingPriority priority = BindingPriority.LocalValue)
@ -849,9 +854,27 @@ namespace Avalonia.Controls
// can be set when the DataGrid is not part of the visual tree // can be set when the DataGrid is not part of the visual tree
_measured = false; _measured = false;
InvalidateMeasure(); InvalidateMeasure();
UpdatePseudoClasses();
} }
} }
private void ColumnsInternal_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Add
|| e.Action == NotifyCollectionChangedAction.Remove
|| e.Action == NotifyCollectionChangedAction.Reset)
{
UpdatePseudoClasses();
}
}
internal void UpdatePseudoClasses()
{
PseudoClasses.Set(":empty-columns", !ColumnsInternal.GetVisibleColumns().Any());
PseudoClasses.Set(":empty-rows", !DataConnection.Any());
}
private void OnSelectedIndexChanged(AvaloniaPropertyChangedEventArgs e) private void OnSelectedIndexChanged(AvaloniaPropertyChangedEventArgs e)
{ {
if (!_areHandlersSuspended) if (!_areHandlersSuspended)
@ -1346,7 +1369,6 @@ namespace Avalonia.Controls
internal DataGridColumnCollection ColumnsInternal internal DataGridColumnCollection ColumnsInternal
{ {
get; get;
private set;
} }
internal int AnchorSlot internal int AnchorSlot

2
src/Avalonia.Controls.DataGrid/DataGridCell.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved. // All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Input; using Avalonia.Input;
@ -12,6 +13,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> cell. /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> cell.
/// </summary> /// </summary>
[PseudoClasses(":selected", ":current", ":edited", ":invalid")]
public class DataGridCell : ContentControl public class DataGridCell : ContentControl
{ {
private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine"; private const string DATAGRIDCELL_elementRightGridLine = "PART_RightGridLine";

34
src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs

@ -17,9 +17,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public class DataGridCheckBoxColumn : DataGridBoundColumn public class DataGridCheckBoxColumn : DataGridBoundColumn
{ {
private bool _beganEditWithKeyboard; private bool _beganEditWithKeyboard;
private bool _isThreeState;
private CheckBox _currentCheckBox; private CheckBox _currentCheckBox;
private DataGrid _owningGrid; private DataGrid _owningGrid;
@ -31,6 +29,12 @@ namespace Avalonia.Controls
BindingTarget = CheckBox.IsCheckedProperty; BindingTarget = CheckBox.IsCheckedProperty;
} }
/// <summary>
/// Defines the <see cref="IsThreeState"/> property.
/// </summary>
public static StyledProperty<bool> IsThreeStateProperty =
CheckBox.IsThreeStateProperty.AddOwner<DataGridCheckBoxColumn>();
/// <summary> /// <summary>
/// Gets or sets a value that indicates whether the hosted <see cref="T:System.Windows.Controls.CheckBox" /> controls allow three states or two. /// Gets or sets a value that indicates whether the hosted <see cref="T:System.Windows.Controls.CheckBox" /> controls allow three states or two.
/// </summary> /// </summary>
@ -39,17 +43,17 @@ namespace Avalonia.Controls
/// </returns> /// </returns>
public bool IsThreeState public bool IsThreeState
{ {
get get => GetValue(IsThreeStateProperty);
{ set => SetValue(IsThreeStateProperty, value);
return _isThreeState; }
}
set protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == IsThreeStateProperty)
{ {
if (_isThreeState != value) NotifyPropertyChanged(change.Property.Name);
{
_isThreeState = value;
NotifyPropertyChanged(nameof(IsThreeState));
}
} }
} }
@ -203,9 +207,9 @@ namespace Avalonia.Controls
{ {
throw new ArgumentNullException("element"); throw new ArgumentNullException("element");
} }
if(element is CheckBox checkBox) if (element is CheckBox checkBox)
{ {
checkBox.IsThreeState = IsThreeState; DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
} }
else else
{ {
@ -229,7 +233,7 @@ namespace Avalonia.Controls
{ {
checkBox.HorizontalAlignment = HorizontalAlignment.Center; checkBox.HorizontalAlignment = HorizontalAlignment.Center;
checkBox.VerticalAlignment = VerticalAlignment.Center; checkBox.VerticalAlignment = VerticalAlignment.Center;
checkBox.IsThreeState = IsThreeState; DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
} }
private bool EnsureOwningGrid() private bool EnsureOwningGrid()

1
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -665,6 +665,7 @@ namespace Avalonia.Controls
/// <param name="dataItem"> /// <param name="dataItem">
/// The data item represented by the row that contains the intended cell. /// The data item represented by the row that contains the intended cell.
/// </param> /// </param>
/// <param name="binding">When the method returns, contains the applied binding.</param>
/// <returns> /// <returns>
/// A new editing element that is bound to the column's <see cref="P:Avalonia.Controls.DataGridBoundColumn.Binding" /> property value. /// A new editing element that is bound to the column's <see cref="P:Avalonia.Controls.DataGridBoundColumn.Binding" /> property value.
/// </returns> /// </returns>

15
src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs

@ -14,12 +14,14 @@ using Avalonia.Utilities;
using System; using System;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Controls.Mixins; using Avalonia.Controls.Mixins;
using Avalonia.Controls.Metadata;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
/// <summary> /// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> column header. /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> column header.
/// </summary> /// </summary>
[PseudoClasses(":dragIndicator", ":pressed", ":sortascending", ":sortdescending")]
public class DataGridColumnHeader : ContentControl public class DataGridColumnHeader : ContentControl
{ {
private enum DragMode private enum DragMode
@ -338,8 +340,6 @@ namespace Avalonia.Controls
if (OwningGrid != null && OwningGrid.ColumnHeaders != null) if (OwningGrid != null && OwningGrid.ColumnHeaders != null)
{ {
args.Pointer.Capture(this);
_dragMode = DragMode.MouseDown; _dragMode = DragMode.MouseDown;
_frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth(); _frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth();
_lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition); _lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition);
@ -411,8 +411,9 @@ namespace Avalonia.Controls
} }
//TODO DragEvents //TODO DragEvents
internal void OnMouseMove(ref bool handled, Point mousePosition, Point mousePositionHeaders) internal void OnMouseMove(PointerEventArgs args, Point mousePosition, Point mousePositionHeaders)
{ {
var handled = args.Handled;
if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null) if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null)
{ {
return; return;
@ -436,7 +437,10 @@ namespace Avalonia.Controls
} }
_lastMousePositionHeaders = mousePositionHeaders; _lastMousePositionHeaders = mousePositionHeaders;
if (args.Pointer.Captured != this && _dragMode == DragMode.Drag)
args.Pointer.Capture(this);
SetDragCursor(mousePosition); SetDragCursor(mousePosition);
} }
@ -504,8 +508,7 @@ namespace Avalonia.Controls
Point mousePosition = e.GetPosition(this); Point mousePosition = e.GetPosition(this);
Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders); Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders);
bool handled = false; OnMouseMove(e, mousePosition, mousePositionHeaders);
OnMouseMove(ref handled, mousePosition, mousePositionHeaders);
} }
/// <summary> /// <summary>

39
src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs

@ -77,24 +77,7 @@ namespace Avalonia.Controls
private set; private set;
} }
public int Count public int Count => GetCount(true);
{
get
{
IList list = List;
if (list != null)
{
return list.Count;
}
if(DataSource is DataGridCollectionView cv)
{
return cv.Count;
}
return DataSource?.Cast<object>().Count() ?? 0;
}
}
public bool DataIsPrimitive public bool DataIsPrimitive
{ {
@ -210,6 +193,24 @@ namespace Avalonia.Controls
} }
} }
internal bool Any()
{
return GetCount(false) > 0;
}
/// <param name="allowSlow">When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.</param>
private int GetCount(bool allowSlow)
{
return DataSource switch
{
ICollection collection => collection.Count,
DataGridCollectionView cv => cv.Count,
IEnumerable enumerable when allowSlow => enumerable.Cast<object>().Count(),
IEnumerable enumerable when !allowSlow => enumerable.Cast<object>().Any() ? 1 : 0,
_ => 0
};
}
/// <summary> /// <summary>
/// Puts the entity into editing mode if possible /// Puts the entity into editing mode if possible
/// </summary> /// </summary>
@ -675,6 +676,8 @@ namespace Avalonia.Controls
} }
break; break;
} }
_owner.UpdatePseudoClasses();
} }
private void UpdateDataProperties() private void UpdateDataProperties()

2
src/Avalonia.Controls.DataGrid/DataGridRow.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved. // All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
@ -20,6 +21,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a <see cref="T:Avalonia.Controls.DataGrid" /> row. /// Represents a <see cref="T:Avalonia.Controls.DataGrid" /> row.
/// </summary> /// </summary>
[PseudoClasses(":selected", ":editing", ":invalid")]
public class DataGridRow : TemplatedControl public class DataGridRow : TemplatedControl
{ {

2
src/Avalonia.Controls.DataGrid/DataGridRowGroupHeader.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved. // All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Mixins; using Avalonia.Controls.Mixins;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
@ -13,6 +14,7 @@ using System.Reactive.Linq;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
[PseudoClasses(":pressed", ":current", ":expanded")]
public class DataGridRowGroupHeader : TemplatedControl public class DataGridRowGroupHeader : TemplatedControl
{ {
private const string DATAGRIDROWGROUPHEADER_expanderButton = "ExpanderButton"; private const string DATAGRIDROWGROUPHEADER_expanderButton = "ExpanderButton";

2
src/Avalonia.Controls.DataGrid/DataGridRowHeader.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved. // All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Media; using Avalonia.Media;
using System.Diagnostics; using System.Diagnostics;
@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> row header. /// Represents an individual <see cref="T:Avalonia.Controls.DataGrid" /> row header.
/// </summary> /// </summary>
[PseudoClasses(":invalid", ":selected", ":editing", ":current")]
public class DataGridRowHeader : ContentControl public class DataGridRowHeader : ContentControl
{ {
private const string DATAGRIDROWHEADER_elementRootName = "PART_Root"; private const string DATAGRIDROWHEADER_elementRootName = "PART_Root";

231
src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs

@ -20,11 +20,6 @@ namespace Avalonia.Controls
{ {
private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin"; private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin";
private double? _fontSize;
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private IBrush _foreground;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class. /// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class.
/// </summary> /// </summary>
@ -36,18 +31,24 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Identifies the FontFamily dependency property. /// Identifies the FontFamily dependency property.
/// </summary> /// </summary>
public static readonly StyledProperty<string> FontFamilyProperty = public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
AvaloniaProperty.Register<DataGridTextColumn, string>(nameof(FontFamily)); TextBlock.FontFamilyProperty.AddOwner<DataGridTextColumn>();
/// <summary> /// <summary>
/// Gets or sets the font name. /// Gets or sets the font name.
/// </summary> /// </summary>
public string FontFamily public FontFamily FontFamily
{ {
get { return GetValue(FontFamilyProperty); } get => GetValue(FontFamilyProperty);
set { SetValue(FontFamilyProperty, value); } set => SetValue(FontFamilyProperty, value);
} }
/// <summary>
/// Identifies the FontSize dependency property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<DataGridTextColumn>();
/// <summary> /// <summary>
/// Gets or sets the font size. /// Gets or sets the font size.
/// </summary> /// </summary>
@ -55,74 +56,66 @@ namespace Avalonia.Controls
[DefaultValue(double.NaN)] [DefaultValue(double.NaN)]
public double FontSize public double FontSize
{ {
get get => GetValue(FontSizeProperty);
{ set => SetValue(FontSizeProperty, value);
return _fontSize ?? Double.NaN;
}
set
{
if (_fontSize != value)
{
_fontSize = value;
NotifyPropertyChanged(nameof(FontSize));
}
}
} }
/// <summary>
/// Identifies the FontStyle dependency property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<DataGridTextColumn>();
/// <summary> /// <summary>
/// Gets or sets the font style. /// Gets or sets the font style.
/// </summary> /// </summary>
public FontStyle FontStyle public FontStyle FontStyle
{ {
get get => GetValue(FontStyleProperty);
{ set => SetValue(FontStyleProperty, value);
return _fontStyle ?? FontStyle.Normal;
}
set
{
if (_fontStyle != value)
{
_fontStyle = value;
NotifyPropertyChanged(nameof(FontStyle));
}
}
} }
/// <summary>
/// Identifies the FontWeight dependency property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<DataGridTextColumn>();
/// <summary> /// <summary>
/// Gets or sets the font weight or thickness. /// Gets or sets the font weight or thickness.
/// </summary> /// </summary>
public FontWeight FontWeight public FontWeight FontWeight
{ {
get get => GetValue(FontWeightProperty);
{ set => SetValue(FontWeightProperty, value);
return _fontWeight ?? FontWeight.Normal;
}
set
{
if (_fontWeight != value)
{
_fontWeight = value;
NotifyPropertyChanged(nameof(FontWeight));
}
}
} }
/// <summary>
/// Identifies the Foreground dependency property.
/// </summary>
public static readonly AttachedProperty<IBrush> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<DataGridTextColumn>();
/// <summary> /// <summary>
/// Gets or sets a brush that describes the foreground of the column cells. /// Gets or sets a brush that describes the foreground of the column cells.
/// </summary> /// </summary>
public IBrush Foreground public IBrush Foreground
{ {
get get => GetValue(ForegroundProperty);
{ set => SetValue(ForegroundProperty, value);
return _foreground; }
}
set protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == FontFamilyProperty
|| change.Property == FontSizeProperty
|| change.Property == FontStyleProperty
|| change.Property == FontWeightProperty
|| change.Property == ForegroundProperty)
{ {
if (_foreground != value) NotifyPropertyChanged(change.Property.Name);
{
_foreground = value;
NotifyPropertyChanged(nameof(Foreground));
}
} }
} }
@ -154,26 +147,7 @@ namespace Avalonia.Controls
Background = new SolidColorBrush(Colors.Transparent) Background = new SolidColorBrush(Colors.Transparent)
}; };
if (IsSet(FontFamilyProperty)) SyncProperties(textBox);
{
textBox.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBox.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBox.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBox.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBox.Foreground = _foreground;
}
return textBox; return textBox;
} }
@ -192,26 +166,8 @@ namespace Avalonia.Controls
VerticalAlignment = VerticalAlignment.Center VerticalAlignment = VerticalAlignment.Center
}; };
if (IsSet(FontFamilyProperty)) SyncProperties(textBlockElement);
{
textBlockElement.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBlockElement.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBlockElement.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBlockElement.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBlockElement.Foreground = _foreground;
}
if (Binding != null) if (Binding != null)
{ {
textBlockElement.Bind(TextBlock.TextProperty, Binding); textBlockElement.Bind(TextBlock.TextProperty, Binding);
@ -261,99 +217,42 @@ namespace Avalonia.Controls
throw new ArgumentNullException("element"); throw new ArgumentNullException("element");
} }
if(element is TextBox textBox) if (element is AvaloniaObject content)
{ {
if (propertyName == nameof(FontFamily)) if (propertyName == nameof(FontFamily))
{ {
textBox.FontFamily = FontFamily; DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
} }
else if (propertyName == nameof(FontSize)) else if (propertyName == nameof(FontSize))
{ {
SetTextFontSize(textBox, TextBox.FontSizeProperty); DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
} }
else if (propertyName == nameof(FontStyle)) else if (propertyName == nameof(FontStyle))
{ {
textBox.FontStyle = FontStyle; DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
} }
else if (propertyName == nameof(FontWeight)) else if (propertyName == nameof(FontWeight))
{ {
textBox.FontWeight = FontWeight; DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
} }
else if (propertyName == nameof(Foreground)) else if (propertyName == nameof(Foreground))
{ {
textBox.Foreground = Foreground; DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
else
{
if (FontFamily != null)
{
textBox.FontFamily = FontFamily;
}
SetTextFontSize(textBox, TextBox.FontSizeProperty);
textBox.FontStyle = FontStyle;
textBox.FontWeight = FontWeight;
if (Foreground != null)
{
textBox.Foreground = Foreground;
}
}
}
else if (element is TextBlock textBlock)
{
if (propertyName == nameof(FontFamily))
{
textBlock.FontFamily = FontFamily;
}
else if (propertyName == nameof(FontSize))
{
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
textBlock.FontStyle = FontStyle;
}
else if (propertyName == nameof(FontWeight))
{
textBlock.FontWeight = FontWeight;
}
else if (propertyName == nameof(Foreground))
{
textBlock.Foreground = Foreground;
}
else
{
if (FontFamily != null)
{
textBlock.FontFamily = FontFamily;
}
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
textBlock.FontStyle = FontStyle;
textBlock.FontWeight = FontWeight;
if (Foreground != null)
{
textBlock.Foreground = Foreground;
}
} }
} }
else else
{ {
throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr("element", typeof(TextBox), typeof(TextBlock)); throw DataGridError.DataGrid.ValueIsNotAnInstanceOf("element", typeof(AvaloniaObject));
} }
} }
private void SetTextFontSize(AvaloniaObject textElement, AvaloniaProperty fontSizeProperty) private void SyncProperties(AvaloniaObject content)
{ {
double newFontSize = FontSize; DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
if (double.IsNaN(newFontSize)) DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
{ DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
textElement.ClearValue(fontSizeProperty); DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
} DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
else
{
textElement.SetValue(fontSizeProperty, newFontSize);
}
} }
} }
} }

7
src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs

@ -1,10 +1,13 @@
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Avalonia.Metadata; using Avalonia.Metadata;
#if SIGNED_BUILD
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.DesignerSupport")] [assembly: InternalsVisibleTo("Avalonia.DesignerSupport")]
#endif
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")]

21
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@ -588,18 +588,11 @@
<!--<DataGridColumnHeader Name="PART_TopRightCornerHeader" <!--<DataGridColumnHeader Name="PART_TopRightCornerHeader"
Grid.Column="2" Grid.Column="2"
Template="{StaticResource TopRightHeaderTemplate}" />--> Template="{StaticResource TopRightHeaderTemplate}" />-->
<!--<Rectangle Name="PART_ColumnHeadersAndRowsSeparator" <Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3" Grid.ColumnSpan="3"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"
StrokeThickness="1"
Height="1" Height="1"
Fill="{DynamicResource DataGridGridLinesBrush}" />--> Fill="{DynamicResource DataGridGridLinesBrush}" />
<Border Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3"
Height="2"
VerticalAlignment="Bottom"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource DataGridGridLinesBrush}" />
<DataGridRowsPresenter Name="PART_RowsPresenter" <DataGridRowsPresenter Name="PART_RowsPresenter"
Grid.Row="1" Grid.Row="1"
@ -642,4 +635,14 @@
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</Style> </Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeader#PART_TopLeftCornerHeader">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeadersPresenter#PART_ColumnHeadersPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ Rectangle#PART_ColumnHeadersAndRowsSeparator">
<Setter Property="IsVisible" Value="False" />
</Style>
</Styles> </Styles>

22
src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs

@ -0,0 +1,22 @@
namespace Avalonia.Controls
{
internal static class DataGridHelper
{
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> property)
{
SyncColumnProperty(column, content, property, property);
}
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> contentProperty, AvaloniaProperty<T> columnProperty)
{
if (!column.IsSet(columnProperty))
{
content.ClearValue(contentProperty);
}
else
{
content.SetValue(contentProperty, column.GetValue(columnProperty));
}
}
}
}

8
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -8,6 +8,12 @@ MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(A
TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.StyledProperty<Avalonia.Controls.IControl> Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.TreeView, Avalonia.Controls.ISelectionModel> Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Interactivity.RoutedEvent<Avalonia.Controls.SelectionChangedEventArgs> Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract.
@ -17,4 +23,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalo
MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.DirectProperty<Avalonia.Controls.Primitives.SelectingItemsControl, Avalonia.Controls.ISelectionModel> Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
Total Issues: 18 Total Issues: 24

96
src/Avalonia.Controls/AutoCompleteBox.cs

@ -14,6 +14,7 @@ using System.Reactive.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Collections; using Avalonia.Collections;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
@ -30,6 +31,7 @@ namespace Avalonia.Controls
/// <see cref="E:Avalonia.Controls.AutoCompleteBox.Populated" /> /// <see cref="E:Avalonia.Controls.AutoCompleteBox.Populated" />
/// event. /// event.
/// </summary> /// </summary>
[PseudoClasses(":dropdownopen")]
public class PopulatedEventArgs : EventArgs public class PopulatedEventArgs : EventArgs
{ {
/// <summary> /// <summary>
@ -225,6 +227,27 @@ namespace Avalonia.Controls
Custom = 13, Custom = 13,
} }
/// <summary>
/// Represents the selector used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" /> control to
/// determine how the specified text should be modified with an item.
/// </summary>
/// <returns>
/// Modified text that will be used by the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// </returns>
/// <param name="search">The string used as the basis for filtering.</param>
/// <param name="item">
/// The selected item that should be combined with the
/// <paramref name="search" /> parameter.
/// </param>
/// <typeparam name="T">
/// The type used for filtering the
/// <see cref="T:Avalonia.Controls.AutoCompleteBox" />.
/// This type can be either a string or an object.
/// </typeparam>
public delegate string AutoCompleteSelector<T>(string search, T item);
/// <summary> /// <summary>
/// Represents a control that provides a text box for user input and a /// Represents a control that provides a text box for user input and a
/// drop-down that contains possible matches based on the input in the text /// drop-down that contains possible matches based on the input in the text
@ -362,6 +385,9 @@ namespace Avalonia.Controls
private AutoCompleteFilterPredicate<object> _itemFilter; private AutoCompleteFilterPredicate<object> _itemFilter;
private AutoCompleteFilterPredicate<string> _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith); private AutoCompleteFilterPredicate<string> _textFilter = AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith);
private AutoCompleteSelector<object> _itemSelector;
private AutoCompleteSelector<string> _textSelector;
public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent = public static readonly RoutedEvent<SelectionChangedEventArgs> SelectionChangedEvent =
RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox)); RoutedEvent.Register<SelectionChangedEventArgs>(nameof(SelectionChanged), RoutingStrategies.Bubble, typeof(AutoCompleteBox));
@ -528,6 +554,34 @@ namespace Avalonia.Controls
(o, v) => o.TextFilter = v, (o, v) => o.TextFilter = v,
unsetValue: AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith)); unsetValue: AutoCompleteSearch.GetFilter(AutoCompleteFilterMode.StartsWith));
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" />
/// dependency property.
/// </summary>
/// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemSelector" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<object>> ItemSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<object>>(
nameof(ItemSelector),
o => o.ItemSelector,
(o, v) => o.ItemSelector = v);
/// <summary>
/// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.
/// </summary>
/// <value>The identifier for the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.TextSelector" />
/// dependency property.</value>
public static readonly DirectProperty<AutoCompleteBox, AutoCompleteSelector<string>> TextSelectorProperty =
AvaloniaProperty.RegisterDirect<AutoCompleteBox, AutoCompleteSelector<string>>(
nameof(TextSelector),
o => o.TextSelector,
(o, v) => o.TextSelector = v);
/// <summary> /// <summary>
/// Identifies the /// Identifies the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" /> /// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
@ -1061,6 +1115,40 @@ namespace Avalonia.Controls
set { SetAndRaise(TextFilterProperty, ref _textFilter, value); } set { SetAndRaise(TextFilterProperty, ref _textFilter, value); }
} }
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />.
/// </value>
public AutoCompleteSelector<object> ItemSelector
{
get { return _itemSelector; }
set { SetAndRaise(ItemSelectorProperty, ref _itemSelector, value); }
}
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// in a text-based way.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="P:Avalonia.Controls.AutoCompleteBox.ItemsSource" />
/// in a text-based way.
/// </value>
public AutoCompleteSelector<string> TextSelector
{
get { return _textSelector; }
set { SetAndRaise(TextSelectorProperty, ref _textSelector, value); }
}
public Func<string, CancellationToken, Task<IEnumerable<object>>> AsyncPopulator public Func<string, CancellationToken, Task<IEnumerable<object>>> AsyncPopulator
{ {
get { return _asyncPopulator; } get { return _asyncPopulator; }
@ -2329,6 +2417,14 @@ namespace Avalonia.Controls
{ {
text = SearchText; text = SearchText;
} }
else if (TextSelector != null)
{
text = TextSelector(SearchText, FormatValue(newItem, true));
}
else if (ItemSelector != null)
{
text = ItemSelector(SearchText, newItem);
}
else else
{ {
text = FormatValue(newItem, true); text = FormatValue(newItem, true);

2
src/Avalonia.Controls/Button.cs

@ -1,6 +1,7 @@
using System; using System;
using System.Linq; using System.Linq;
using System.Windows.Input; using System.Windows.Input;
using Avalonia.Controls.Metadata;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -28,6 +29,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// A button control. /// A button control.
/// </summary> /// </summary>
[PseudoClasses(":pressed")]
public class Button : ContentControl public class Button : ContentControl
{ {
/// <summary> /// <summary>

2
src/Avalonia.Controls/ButtonSpinner.cs

@ -1,4 +1,5 @@
using System; using System;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
@ -15,6 +16,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a spinner control that includes two Buttons. /// Represents a spinner control that includes two Buttons.
/// </summary> /// </summary>
[PseudoClasses(":left", ":right")]
public class ButtonSpinner : Spinner public class ButtonSpinner : Spinner
{ {
/// <summary> /// <summary>

2
src/Avalonia.Controls/Calendar/CalendarButton.cs

@ -3,6 +3,7 @@
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved. // All other rights reserved.
using Avalonia.Controls.Metadata;
using Avalonia.Input; using Avalonia.Input;
using System; using System;
@ -12,6 +13,7 @@ namespace Avalonia.Controls.Primitives
/// Represents a button on a /// Represents a button on a
/// <see cref="T:Avalonia.Controls.Calendar" />. /// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary> /// </summary>
[PseudoClasses(":selected", ":inactive", ":btnfocused")]
public sealed class CalendarButton : Button public sealed class CalendarButton : Button
{ {
/// <summary> /// <summary>

9
src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -420,7 +420,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp -= Calendar_DayButtonMouseUp; _calendar.DayButtonMouseUp -= Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged -= Calendar_DisplayDateChanged; _calendar.DisplayDateChanged -= Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged -= Calendar_SelectedDatesChanged; _calendar.SelectedDatesChanged -= Calendar_SelectedDatesChanged;
_calendar.PointerPressed -= Calendar_PointerPressed; _calendar.PointerReleased -= Calendar_PointerReleased;
_calendar.KeyDown -= Calendar_KeyDown; _calendar.KeyDown -= Calendar_KeyDown;
} }
_calendar = e.NameScope.Find<Calendar>(ElementCalendar); _calendar = e.NameScope.Find<Calendar>(ElementCalendar);
@ -435,7 +435,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp += Calendar_DayButtonMouseUp; _calendar.DayButtonMouseUp += Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged += Calendar_DisplayDateChanged; _calendar.DisplayDateChanged += Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged; _calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
_calendar.PointerPressed += Calendar_PointerPressed; _calendar.PointerReleased += Calendar_PointerReleased;
_calendar.KeyDown += Calendar_KeyDown; _calendar.KeyDown += Calendar_KeyDown;
//_calendar.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged); //_calendar.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged);
//_calendar.IsTabStop = true; //_calendar.IsTabStop = true;
@ -831,9 +831,10 @@ namespace Avalonia.Controls
} }
} }
} }
private void Calendar_PointerPressed(object sender, PointerPressedEventArgs e) private void Calendar_PointerReleased(object sender, PointerReleasedEventArgs e)
{ {
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
if (e.InitialPressMouseButton == MouseButton.Left)
{ {
e.Handled = true; e.Handled = true;
} }

2
src/Avalonia.Controls/Calendar/CalendarDayButton.cs

@ -5,10 +5,12 @@
using System; using System;
using System.Globalization; using System.Globalization;
using Avalonia.Controls.Metadata;
using Avalonia.Input; using Avalonia.Input;
namespace Avalonia.Controls.Primitives namespace Avalonia.Controls.Primitives
{ {
[PseudoClasses(":pressed", ":disabled", ":selected", ":inactive", ":today", ":blackout", ":dayfocused")]
public sealed class CalendarDayButton : Button public sealed class CalendarDayButton : Button
{ {
/// <summary> /// <summary>

81
src/Avalonia.Controls/Calendar/CalendarItem.cs

@ -7,6 +7,7 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Globalization; using System.Globalization;
using Avalonia.Controls.Metadata;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -18,6 +19,7 @@ namespace Avalonia.Controls.Primitives
/// Represents the currently displayed month or year on a /// Represents the currently displayed month or year on a
/// <see cref="T:Avalonia.Controls.Calendar" />. /// <see cref="T:Avalonia.Controls.Calendar" />.
/// </summary> /// </summary>
[PseudoClasses(":calendardisabled")]
public sealed class CalendarItem : TemplatedControl public sealed class CalendarItem : TemplatedControl
{ {
/// <summary> /// <summary>
@ -34,11 +36,7 @@ namespace Avalonia.Controls.Primitives
private Button _headerButton; private Button _headerButton;
private Button _nextButton; private Button _nextButton;
private Button _previousButton; private Button _previousButton;
private Grid _monthView;
private Grid _yearView;
private ITemplate<IControl> _dayTitleTemplate; private ITemplate<IControl> _dayTitleTemplate;
private CalendarButton _lastCalendarButton;
private CalendarDayButton _lastCalendarDayButton;
private DateTime _currentMonth; private DateTime _currentMonth;
private bool _isMouseLeftButtonDown = false; private bool _isMouseLeftButtonDown = false;
@ -158,38 +156,12 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Gets the Grid that hosts the content when in month mode. /// Gets the Grid that hosts the content when in month mode.
/// </summary> /// </summary>
internal Grid MonthView internal Grid MonthView { get; set; }
{
get { return _monthView; }
private set
{
if (_monthView != null)
_monthView.PointerLeave -= MonthView_MouseLeave;
_monthView = value;
if (_monthView != null)
_monthView.PointerLeave += MonthView_MouseLeave;
}
}
/// <summary> /// <summary>
/// Gets the Grid that hosts the content when in year or decade mode. /// Gets the Grid that hosts the content when in year or decade mode.
/// </summary> /// </summary>
internal Grid YearView internal Grid YearView { get; set; }
{
get { return _yearView; }
private set
{
if (_yearView != null)
_yearView.PointerLeave -= YearView_MouseLeave;
_yearView = value;
if (_yearView != null)
_yearView.PointerLeave += YearView_MouseLeave;
}
}
private void PopulateGrids() private void PopulateGrids()
{ {
if (MonthView != null) if (MonthView != null)
@ -224,7 +196,6 @@ namespace Avalonia.Controls.Primitives
cell.CalendarDayButtonMouseDown += Cell_MouseLeftButtonDown; cell.CalendarDayButtonMouseDown += Cell_MouseLeftButtonDown;
cell.CalendarDayButtonMouseUp += Cell_MouseLeftButtonUp; cell.CalendarDayButtonMouseUp += Cell_MouseLeftButtonUp;
cell.PointerEnter += Cell_MouseEnter; cell.PointerEnter += Cell_MouseEnter;
cell.PointerLeave += Cell_MouseLeave;
cell.Click += Cell_Click; cell.Click += Cell_Click;
children.Add(cell); children.Add(cell);
} }
@ -254,7 +225,6 @@ namespace Avalonia.Controls.Primitives
month.CalendarLeftMouseButtonDown += Month_CalendarButtonMouseDown; month.CalendarLeftMouseButtonDown += Month_CalendarButtonMouseDown;
month.CalendarLeftMouseButtonUp += Month_CalendarButtonMouseUp; month.CalendarLeftMouseButtonUp += Month_CalendarButtonMouseUp;
month.PointerEnter += Month_MouseEnter; month.PointerEnter += Month_MouseEnter;
month.PointerLeave += Month_MouseLeave;
children.Add(month); children.Add(month);
} }
} }
@ -935,17 +905,7 @@ namespace Avalonia.Controls.Primitives
} }
} }
} }
internal void Cell_MouseLeave(object sender, PointerEventArgs e)
{
if (_isMouseLeftButtonDown)
{
CalendarDayButton b = (CalendarDayButton)sender;
// The button is in Pressed state. Change the state to normal.
if (e.Pointer.Captured == b)
e.Pointer.Capture(null);
_lastCalendarDayButton = b;
}
}
internal void Cell_MouseLeftButtonDown(object sender, PointerPressedEventArgs e) internal void Cell_MouseLeftButtonDown(object sender, PointerPressedEventArgs e)
{ {
if (Owner != null) if (Owner != null)
@ -1205,35 +1165,6 @@ namespace Avalonia.Controls.Primitives
} }
} }
private void Month_MouseLeave(object sender, PointerEventArgs e)
{
if (_isMouseLeftButtonDownYearView)
{
CalendarButton b = (CalendarButton)sender;
// The button is in Pressed state. Change the state to normal.
if (e.Pointer.Captured == b)
e.Pointer.Capture(null);
//b.ReleaseMouseCapture();
_lastCalendarButton = b;
}
}
private void MonthView_MouseLeave(object sender, PointerEventArgs e)
{
if (_lastCalendarDayButton != null)
{
e.Pointer.Capture(_lastCalendarDayButton);
}
}
private void YearView_MouseLeave(object sender, PointerEventArgs e)
{
if (_lastCalendarButton != null)
{
e.Pointer.Capture(_lastCalendarButton);
}
}
internal void UpdateDisabled(bool isEnabled) internal void UpdateDisabled(bool isEnabled)
{ {
PseudoClasses.Set(":calendardisabled", !isEnabled); PseudoClasses.Set(":calendardisabled", !isEnabled);

2
src/Avalonia.Controls/Chrome/CaptionButtons.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable #nullable enable
@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
/// <summary> /// <summary>
/// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled. /// Draws window minimize / maximize / close buttons in a <see cref="TitleBar"/> when managed client decorations are enabled.
/// </summary> /// </summary>
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class CaptionButtons : TemplatedControl public class CaptionButtons : TemplatedControl
{ {
private CompositeDisposable? _disposables; private CompositeDisposable? _disposables;

2
src/Avalonia.Controls/Chrome/TitleBar.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
#nullable enable #nullable enable
@ -9,6 +10,7 @@ namespace Avalonia.Controls.Chrome
/// <summary> /// <summary>
/// Draws a titlebar when managed client decorations are enabled. /// Draws a titlebar when managed client decorations are enabled.
/// </summary> /// </summary>
[PseudoClasses(":minimized", ":normal", ":maximized", ":fullscreen")]
public class TitleBar : TemplatedControl public class TitleBar : TemplatedControl
{ {
private CompositeDisposable? _disposables; private CompositeDisposable? _disposables;

4
src/Avalonia.Controls/ComboBox.cs

@ -257,7 +257,7 @@ namespace Avalonia.Controls
} }
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e) protected override void OnPointerReleased(PointerReleasedEventArgs e)
{ {
if (!e.Handled) if (!e.Handled)
{ {
@ -276,7 +276,7 @@ namespace Avalonia.Controls
} }
} }
base.OnPointerPressed(e); base.OnPointerReleased(e);
} }
/// <inheritdoc/> /// <inheritdoc/>

13
src/Avalonia.Controls/ContextMenu.cs

@ -62,6 +62,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<Rect?> PlacementRectProperty = public static readonly StyledProperty<Rect?> PlacementRectProperty =
AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect)); AvaloniaProperty.Register<Popup, Rect?>(nameof(PlacementRect));
/// <summary>
/// Defines the <see cref="WindowManagerAddShadowHint"/> property.
/// </summary>
public static readonly StyledProperty<bool> WindowManagerAddShadowHintProperty =
Popup.WindowManagerAddShadowHintProperty.AddOwner<ContextMenu>();
/// <summary> /// <summary>
/// Defines the <see cref="PlacementTarget"/> property. /// Defines the <see cref="PlacementTarget"/> property.
/// </summary> /// </summary>
@ -158,6 +164,12 @@ namespace Avalonia.Controls
set { SetValue(PlacementModeProperty, value); } set { SetValue(PlacementModeProperty, value); }
} }
public bool WindowManagerAddShadowHint
{
get { return GetValue(WindowManagerAddShadowHintProperty); }
set { SetValue(WindowManagerAddShadowHintProperty, value); }
}
/// <summary> /// <summary>
/// Gets or sets the the anchor rectangle within the parent that the context menu will be placed /// Gets or sets the the anchor rectangle within the parent that the context menu will be placed
/// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>. /// relative to when <see cref="PlacementMode"/> is <see cref="PlacementMode.AnchorAndGravity"/>.
@ -267,6 +279,7 @@ namespace Avalonia.Controls
PlacementTarget = PlacementTarget ?? control, PlacementTarget = PlacementTarget ?? control,
IsLightDismissEnabled = true, IsLightDismissEnabled = true,
OverlayDismissEventPassThrough = true, OverlayDismissEventPassThrough = true,
WindowManagerAddShadowHint = WindowManagerAddShadowHint,
}; };
_popup.Opened += PopupOpened; _popup.Opened += PopupOpened;

2
src/Avalonia.Controls/DataValidationErrors.cs

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reactive.Linq; using System.Reactive.Linq;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Data; using Avalonia.Data;
@ -14,6 +15,7 @@ namespace Avalonia.Controls
/// <remarks> /// <remarks>
/// You will probably only want to create instances inside of control templates. /// You will probably only want to create instances inside of control templates.
/// </remarks> /// </remarks>
[PseudoClasses(":error")]
public class DataValidationErrors : ContentControl public class DataValidationErrors : ContentControl
{ {
/// <summary> /// <summary>

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

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -11,6 +12,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// A control to allow the user to select a date /// A control to allow the user to select a date
/// </summary> /// </summary>
[PseudoClasses(":hasnodate")]
public class DatePicker : TemplatedControl public class DatePicker : TemplatedControl
{ {
/// <summary> /// <summary>

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

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

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

@ -1,4 +1,5 @@
using Avalonia.Controls.Primitives; using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using System; using System;
@ -9,6 +10,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// A control to allow the user to select a time /// A control to allow the user to select a time
/// </summary> /// </summary>
[PseudoClasses(":hasnotime")]
public class TimePicker : TemplatedControl public class TimePicker : TemplatedControl
{ {
/// <summary> /// <summary>

3
src/Avalonia.Controls/Expander.cs

@ -1,6 +1,6 @@
using Avalonia.Animation; using Avalonia.Animation;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Data;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -12,6 +12,7 @@ namespace Avalonia.Controls
Right Right
} }
[PseudoClasses(":expanded", ":up", ":down", ":left", ":right")]
public class Expander : HeaderedContentControl public class Expander : HeaderedContentControl
{ {
public static readonly StyledProperty<IPageTransition> ContentTransitionProperty = public static readonly StyledProperty<IPageTransition> ContentTransitionProperty =

6
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@ -47,11 +47,7 @@ namespace Avalonia.Controls.Generators
{ {
var container = item as T; var container = item as T;
if (item == null) if (container != null)
{
return null;
}
else if (container != null)
{ {
return container; return container;
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save