Browse Source

Merge branch 'master' into fixes/HotKey_Command_Issues

pull/4737/head
Dan Walmsley 6 years ago
committed by GitHub
parent
commit
42c081f6bf
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      Avalonia.sln
  2. 2
      build/SharedVersion.props
  3. 1020
      native/Avalonia.Native/inc/key.h
  4. 12
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  5. 7
      native/Avalonia.Native/src/OSX/KeyTransform.h
  6. 151
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  7. 2
      native/Avalonia.Native/src/OSX/menu.h
  8. 65
      native/Avalonia.Native/src/OSX/menu.mm
  9. 8
      native/Avalonia.Native/src/OSX/window.mm
  10. 2
      samples/BindingDemo/App.xaml.cs
  11. 3
      samples/BindingDemo/BindingDemo.csproj
  12. 4
      samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
  13. 4
      samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs
  14. 12
      samples/BindingDemo/ViewModels/MainWindowViewModel.cs
  15. 8
      samples/BindingDemo/ViewModels/NestedCommandViewModel.cs
  16. 4
      samples/BindingDemo/ViewModels/TestItem.cs
  17. 4
      samples/ControlCatalog.Desktop/Program.cs
  18. 2
      samples/ControlCatalog.NetCore/Program.cs
  19. 2
      samples/ControlCatalog/ControlCatalog.csproj
  20. 1
      samples/ControlCatalog/Pages/LabelsPage.axaml.cs
  21. 2
      samples/ControlCatalog/Pages/ListBoxPage.xaml
  22. 1
      samples/ControlCatalog/Pages/MenuPage.xaml.cs
  23. 4
      samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs
  24. 4
      samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs
  25. 4
      samples/ControlCatalog/Pages/TabControlPage.xaml.cs
  26. 14
      samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs
  27. 6
      samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
  28. 27
      samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
  29. 28
      samples/ControlCatalog/ViewModels/MainWindowViewModel.cs
  30. 14
      samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
  31. 10
      samples/ControlCatalog/ViewModels/NotificationViewModel.cs
  32. 4
      samples/ControlCatalog/ViewModels/SplitViewPageViewModel.cs
  33. 16
      samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
  34. 66
      samples/MiniMvvm/MiniCommand.cs
  35. 6
      samples/MiniMvvm/MiniMvvm.csproj
  36. 108
      samples/MiniMvvm/PropertyChangedExtensions.cs
  37. 26
      samples/MiniMvvm/ViewModelBase.cs
  38. 1
      samples/Previewer/Previewer.csproj
  39. 2
      samples/RenderDemo/App.xaml
  40. 2
      samples/RenderDemo/App.xaml.cs
  41. 2
      samples/RenderDemo/MainWindow.xaml.cs
  42. 3
      samples/RenderDemo/RenderDemo.csproj
  43. 4
      samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs
  44. 17
      samples/RenderDemo/ViewModels/MainWindowViewModel.cs
  45. 2
      samples/Sandbox/App.axaml
  46. 2
      samples/Sandbox/Program.cs
  47. 1
      samples/Sandbox/Sandbox.csproj
  48. 2
      samples/VirtualizationDemo/Program.cs
  49. 4
      samples/VirtualizationDemo/ViewModels/ItemViewModel.cs
  50. 24
      samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
  51. 3
      samples/VirtualizationDemo/VirtualizationDemo.csproj
  52. 2
      samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj
  53. 4
      samples/interop/Direct3DInteropSample/MainWindowViewModel.cs
  54. 6
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  55. 4
      src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj
  56. 4
      src/Avalonia.Base/ApiCompatBaseline.txt
  57. 5
      src/Avalonia.Base/Logging/LogArea.cs
  58. 2
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  59. 25
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  60. 14
      src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
  61. 6
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  62. 29
      src/Avalonia.Controls.DataGrid/Themes/Default.xaml
  63. 29
      src/Avalonia.Controls/ApiCompatBaseline.txt
  64. 10
      src/Avalonia.Controls/ContextMenu.cs
  65. 4
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
  66. 5
      src/Avalonia.Controls/TextBox.cs
  67. 20
      src/Avalonia.Controls/Window.cs
  68. 2
      src/Avalonia.Controls/WindowBase.cs
  69. 2
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  70. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  71. 2
      src/Avalonia.FreeDesktop/DBusHelper.cs
  72. 7
      src/Avalonia.Headless/HeadlessWindowImpl.cs
  73. 6
      src/Avalonia.Layout/LayoutContext.cs
  74. 4
      src/Avalonia.Native/IAvnMenuItem.cs
  75. 152
      src/Avalonia.Native/OsxUnicodeKeys.cs
  76. 4
      src/Avalonia.Native/PopupImpl.cs
  77. 4
      src/Avalonia.Native/WindowImplBase.cs
  78. 211
      src/Avalonia.Native/avn.idl
  79. 6
      src/Avalonia.Themes.Default/CaptionButtons.xaml
  80. 5
      src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt
  81. 6
      src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
  82. 1
      src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml
  83. 2
      src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml
  84. 114
      src/Avalonia.Themes.Fluent/FluentTheme.cs
  85. 3
      src/Avalonia.Themes.Fluent/Properties/AssemblyInfo.cs
  86. 1
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  87. 2
      src/Avalonia.Visuals/Visual.cs
  88. 2
      src/Avalonia.X11/X11Window.cs
  89. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs
  90. 100
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs
  91. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs
  92. 5
      src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt
  93. 10
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
  94. 41
      src/Windows/Avalonia.Win32/ClipboardImpl.cs
  95. 4
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  96. 52
      src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
  97. 15
      src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs
  98. 3
      src/Windows/Avalonia.Win32/PopupImpl.cs
  99. 32
      src/Windows/Avalonia.Win32/Win32Platform.cs
  100. 2
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs

27
Avalonia.sln

@ -230,6 +230,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MicroComGenerator", "src\to
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.MicroCom", "src\Avalonia.MicroCom\Avalonia.MicroCom.csproj", "{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MiniMvvm", "samples\MiniMvvm\MiniMvvm.csproj", "{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}"
EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@ -2116,6 +2118,30 @@ Global
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhone.Build.0 = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{FE2F3E5E-1E34-4972-8DC1-5C2C588E5ECE}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|Any CPU.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhone.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhone.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|Any CPU.Build.0 = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.ActiveCfg = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhone.Build.0 = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -2176,6 +2202,7 @@ Global
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
{11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{AEC9031E-06EA-4A9E-9E7F-7D7C719404DD} = {4ED8B739-6F4E-4CD4-B993-545E6B5CE637}
{BC594FD5-4AF2-409E-A1E6-04123F54D7C5} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}

2
build/SharedVersion.props

@ -16,7 +16,7 @@
<PackageReleaseNotes>https://github.com/AvaloniaUI/Avalonia/releases</PackageReleaseNotes>
<RepositoryType>git</RepositoryType>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)\avalonia.snk</AssemblyOriginatorKeyFile>
<SignAssembly>false</SignAssembly>
<SignAssembly>true</SignAssembly>
<DefineConstants Condition="$(SignAssembly) == true">$(DefineConstants);SIGNED_BUILD</DefineConstants>
</PropertyGroup>

1020
native/Avalonia.Native/inc/key.h

File diff suppressed because it is too large

12
native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj

@ -8,19 +8,20 @@
/* Begin PBXBuildFile section */
1A002B9E232135EE00021753 /* app.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A002B9D232135EE00021753 /* app.mm */; };
1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
1A3E5EA823E9E83B00EDE661 /* rendertarget.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */; };
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */; };
1A1852DC23E05814008F0DED /* deadlock.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A1852DB23E05814008F0DED /* deadlock.mm */; };
1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
1A3E5EAE23E9FB1300EDE661 /* cgl.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A3E5EAD23E9FB1300EDE661 /* cgl.mm */; };
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */; };
1A465D10246AB61600C5858B /* dnd.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1A465D0F246AB61600C5858B /* dnd.mm */; };
1AFD334123E03C4F0042899B /* controlhost.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1AFD334023E03C4F0042899B /* controlhost.mm */; };
37155CE4233C00EB0034DCE9 /* menu.h in Headers */ = {isa = PBXBuildFile; fileRef = 37155CE3233C00EB0034DCE9 /* menu.h */; };
37A517B32159597E00FBA241 /* Screens.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37A517B22159597E00FBA241 /* Screens.mm */; };
37C09D8821580FE4006A6758 /* SystemDialogs.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37C09D8721580FE4006A6758 /* SystemDialogs.mm */; };
37DDA9B0219330F8002E132B /* AvnString.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37DDA9AF219330F8002E132B /* AvnString.mm */; };
37E2330F21583241000CB7E2 /* KeyTransform.mm in Sources */ = {isa = PBXBuildFile; fileRef = 37E2330E21583241000CB7E2 /* KeyTransform.mm */; };
520624B322973F4100C4DCEF /* menu.mm in Sources */ = {isa = PBXBuildFile; fileRef = 520624B222973F4100C4DCEF /* menu.mm */; };
522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 522D5958258159C1006F7F7A /* Carbon.framework */; };
5B21A982216530F500CEE36E /* cursor.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B21A981216530F500CEE36E /* cursor.mm */; };
5B8BD94F215BFEA6005ED2A7 /* clipboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */; };
AB00E4F72147CA920032A60A /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = AB00E4F62147CA920032A60A /* main.mm */; };
@ -32,13 +33,13 @@
/* Begin PBXFileReference section */
1A002B9D232135EE00021753 /* app.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = app.mm; sourceTree = "<group>"; };
1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = "<group>"; };
1A3E5EA723E9E83B00EDE661 /* rendertarget.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = rendertarget.mm; sourceTree = "<group>"; };
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOSurface.framework; path = System/Library/Frameworks/IOSurface.framework; sourceTree = SDKROOT; };
1A1852DB23E05814008F0DED /* deadlock.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = deadlock.mm; sourceTree = "<group>"; };
1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = "<group>"; };
1A3E5EAD23E9FB1300EDE661 /* cgl.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cgl.mm; sourceTree = "<group>"; };
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
1A465D0F246AB61600C5858B /* dnd.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = dnd.mm; sourceTree = "<group>"; };
1AFD334023E03C4F0042899B /* controlhost.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = controlhost.mm; sourceTree = "<group>"; };
37155CE3233C00EB0034DCE9 /* menu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = menu.h; sourceTree = "<group>"; };
379860FE214DA0C000CD0246 /* KeyTransform.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyTransform.h; sourceTree = "<group>"; };
37A4E71A2178846A00EACBCD /* headers */ = {isa = PBXFileReference; lastKnownFileType = folder; name = headers; path = ../../inc; sourceTree = "<group>"; };
@ -49,6 +50,7 @@
37DDA9B121933371002E132B /* AvnString.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AvnString.h; sourceTree = "<group>"; };
37E2330E21583241000CB7E2 /* KeyTransform.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = KeyTransform.mm; sourceTree = "<group>"; };
520624B222973F4100C4DCEF /* menu.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = menu.mm; sourceTree = "<group>"; };
522D5958258159C1006F7F7A /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
5B21A981216530F500CEE36E /* cursor.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = cursor.mm; sourceTree = "<group>"; };
5B8BD94E215BFEA6005ED2A7 /* clipboard.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = clipboard.mm; sourceTree = "<group>"; };
5BF943652167AD1D009CAE35 /* cursor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = cursor.h; sourceTree = "<group>"; };
@ -69,6 +71,7 @@
1A3E5EB023E9FE8300EDE661 /* QuartzCore.framework in Frameworks */,
1A3E5EAA23E9F26C00EDE661 /* IOSurface.framework in Frameworks */,
AB1E522C217613570091CD71 /* OpenGL.framework in Frameworks */,
522D5959258159C1006F7F7A /* Carbon.framework in Frameworks */,
AB661C1E2148230F00291242 /* AppKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -79,6 +82,7 @@
AB661C1C2148230E00291242 /* Frameworks */ = {
isa = PBXGroup;
children = (
522D5958258159C1006F7F7A /* Carbon.framework */,
1A3E5EAF23E9FE8300EDE661 /* QuartzCore.framework */,
1A3E5EA923E9F26C00EDE661 /* IOSurface.framework */,
AB1E522B217613570091CD71 /* OpenGL.framework */,

7
native/Avalonia.Native/src/OSX/KeyTransform.h

@ -1,9 +1,14 @@
#ifndef keytransform_h
#define keytransform_h
#include "common.h"
#include "key.h"
#include <map>
extern std::map<int, AvnKey> s_KeyMap;
extern std::map<AvnKey, int> s_AvnKeyMap;
extern std::map<int, const char*> s_QwertyKeyMap;
extern std::map<AvnKey, int> s_UnicodeKeyMap;
#endif

151
native/Avalonia.Native/src/OSX/KeyTransform.mm

@ -120,6 +120,138 @@ const int kVK_UpArrow = 0x7E;
//const int kVK_JIS_Eisu = 0x66;
const int kVK_JIS_Kana = 0x68;
// converts from AvaloniaKeys to UnicodeSpecial keys.
std::map<AvnKey, int> s_UnicodeKeyMap =
{
{ Up, NSUpArrowFunctionKey },
{ Down, NSDownArrowFunctionKey },
{ Left, NSLeftArrowFunctionKey },
{ Right, NSRightArrowFunctionKey },
{ F1, NSF1FunctionKey },
{ F2, NSF2FunctionKey },
{ F3, NSF3FunctionKey },
{ F4, NSF4FunctionKey },
{ F5, NSF5FunctionKey },
{ F6, NSF6FunctionKey },
{ F7, NSF7FunctionKey },
{ F8, NSF8FunctionKey },
{ F9, NSF9FunctionKey },
{ F10, NSF10FunctionKey },
{ F11, NSF11FunctionKey },
{ F12, NSF12FunctionKey },
{ F13, NSF13FunctionKey },
{ F14, NSF14FunctionKey },
{ F15, NSF15FunctionKey },
{ F16, NSF16FunctionKey },
{ F17, NSF17FunctionKey },
{ F18, NSF18FunctionKey },
{ F19, NSF19FunctionKey },
{ F20, NSF20FunctionKey },
{ F21, NSF21FunctionKey },
{ F22, NSF22FunctionKey },
{ F23, NSF23FunctionKey },
{ F24, NSF24FunctionKey },
{ Insert, NSInsertFunctionKey },
{ Delete, NSDeleteFunctionKey },
{ Home, NSHomeFunctionKey },
//{ Begin, NSBeginFunctionKey },
{ End, NSEndFunctionKey },
{ PageUp, NSPageUpFunctionKey },
{ PageDown, NSPageDownFunctionKey },
{ PrintScreen, NSPrintScreenFunctionKey },
{ Scroll, NSScrollLockFunctionKey },
//{ SysReq, NSSysReqFunctionKey },
//{ Break, NSBreakFunctionKey },
//{ Reset, NSResetFunctionKey },
//{ Stop, NSStopFunctionKey },
//{ Menu, NSMenuFunctionKey },
//{ UserFunction, NSUserFunctionKey },
//{ SystemFunction, NSSystemFunctionKey },
{ Print, NSPrintFunctionKey },
//{ ClearLine, NSClearLineFunctionKey },
//{ ClearDisplay, NSClearDisplayFunctionKey },
};
// Converts from Ansi virtual keys to Qwerty Keyboard map.
std::map<int, const char*> s_QwertyKeyMap =
{
{ 0, "a" },
{ 1, "s" },
{ 2, "d" },
{ 3, "f" },
{ 4, "h" },
{ 5, "g" },
{ 6, "z" },
{ 7, "x" },
{ 8, "c" },
{ 9, "v" },
{ 10, "§" },
{ 11, "b" },
{ 12, "q" },
{ 13, "w" },
{ 14, "e" },
{ 15, "r" },
{ 16, "y" },
{ 17, "t" },
{ 18, "1" },
{ 19, "2" },
{ 20, "3" },
{ 21, "4" },
{ 22, "6" },
{ 23, "5" },
{ 24, "=" },
{ 25, "9" },
{ 26, "7" },
{ 27, "-" },
{ 28, "8" },
{ 29, "0" },
{ 30, "]" },
{ 31, "o" },
{ 32, "u" },
{ 33, "[" },
{ 34, "i" },
{ 35, "p" },
{ 37, "l" },
{ 38, "j" },
{ 39, "'" },
{ 40, "k" },
{ 41, ";" },
{ 42, "\\" },
{ 43, "," },
{ 44, "/" },
{ 45, "n" },
{ 46, "m" },
{ 47, "." },
{ 49, " " },
{ 50, "`" },
{ 51, "" },
{ 52, "" },
{ 53, "" },
{ 65, "." },
{ 66, "" },
{ 67, "*" },
{ 69, "+" },
{ 70, "" },
{ 71, "" },
{ 72, "" },
{ 75, "/" },
{ 76, "" },
{ 77, "" },
{ 78, "-" },
{ 81, "=" },
{ 82, "0" },
{ 83, "1" },
{ 84, "2" },
{ 85, "3" },
{ 86, "4" },
{ 87, "5" },
{ 88, "6" },
{ 89, "7" },
{ 91, "8" },
{ 92, "9" }
};
// converts from ansi virtualkeys to AvnKeys.
std::map<int, AvnKey> s_KeyMap =
{
{kVK_ANSI_A, A},
@ -237,3 +369,22 @@ const int kVK_JIS_Kana = 0x68;
{kVK_UpArrow, Up},
{kVK_JIS_Kana, AvnKeyKanaMode},
};
static std::map<AvnKey, int> BuildAvnKeyMap ()
{
std::map<AvnKey, int> result;
for( auto it = s_KeyMap.begin(); it != s_KeyMap.end(); ++it )
{
int key = it->first;
AvnKey value = it->second;
result[value] = key;
}
return result;
}
// Converts AvnKeys to Ansi VirtualKeys
std::map<AvnKey, int> s_AvnKeyMap = BuildAvnKeyMap();

2
native/Avalonia.Native/src/OSX/menu.h

@ -45,7 +45,7 @@ public:
virtual HRESULT SetTitle (char* utf8String) override;
virtual HRESULT SetGesture (char* key, AvnInputModifiers modifiers) override;
virtual HRESULT SetGesture (AvnKey key, AvnInputModifiers modifiers) override;
virtual HRESULT SetAction (IAvnPredicateCallback* predicate, IAvnActionCallback* callback) override;

65
native/Avalonia.Native/src/OSX/menu.mm

@ -2,6 +2,9 @@
#include "common.h"
#include "menu.h"
#include "window.h"
#include "KeyTransform.h"
#include <CoreFoundation/CoreFoundation.h>
#include <Carbon/Carbon.h> /* For kVK_ constants, and TIS functions. */
@implementation AvnMenu
{
@ -122,23 +125,57 @@ HRESULT AvnAppMenuItem::SetTitle (char* utf8String)
}
}
HRESULT AvnAppMenuItem::SetGesture (char* key, AvnInputModifiers modifiers)
HRESULT AvnAppMenuItem::SetGesture (AvnKey key, AvnInputModifiers modifiers)
{
@autoreleasepool
{
NSEventModifierFlags flags = 0;
if (modifiers & Control)
flags |= NSEventModifierFlagControl;
if (modifiers & Shift)
flags |= NSEventModifierFlagShift;
if (modifiers & Alt)
flags |= NSEventModifierFlagOption;
if (modifiers & Windows)
flags |= NSEventModifierFlagCommand;
[_native setKeyEquivalent:[NSString stringWithUTF8String:(const char*)key]];
[_native setKeyEquivalentModifierMask:flags];
if(key != AvnKeyNone)
{
NSEventModifierFlags flags = 0;
if (modifiers & Control)
flags |= NSEventModifierFlagControl;
if (modifiers & Shift)
flags |= NSEventModifierFlagShift;
if (modifiers & Alt)
flags |= NSEventModifierFlagOption;
if (modifiers & Windows)
flags |= NSEventModifierFlagCommand;
auto it = s_UnicodeKeyMap.find(key);
if(it != s_UnicodeKeyMap.end())
{
auto keyString= [NSString stringWithFormat:@"%C", (unsigned short)it->second];
[_native setKeyEquivalent: keyString];
[_native setKeyEquivalentModifierMask:flags];
return S_OK;
}
else
{
auto it = s_AvnKeyMap.find(key); // check if a virtual key is mapped.
if(it != s_AvnKeyMap.end())
{
auto it1 = s_QwertyKeyMap.find(it->second); // convert virtual key to qwerty string.
if(it1 != s_QwertyKeyMap.end())
{
[_native setKeyEquivalent: [NSString stringWithUTF8String: it1->second]];
[_native setKeyEquivalentModifierMask:flags];
return S_OK;
}
}
}
}
// Nothing matched... clear.
[_native setKeyEquivalent: @""];
[_native setKeyEquivalentModifierMask: 0];
return S_OK;
}

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

@ -106,13 +106,13 @@ public:
return Window;
}
virtual HRESULT Show() override
virtual HRESULT Show(bool activate) override
{
@autoreleasepool
{
SetPosition(lastPositionSet);
UpdateStyle();
if(ShouldTakeFocusOnShow())
if(ShouldTakeFocusOnShow() && activate)
{
[Window makeKeyAndOrderFront:Window];
[NSApp activateIgnoringOtherApps:YES];
@ -561,11 +561,11 @@ private:
}
}
virtual HRESULT Show () override
virtual HRESULT Show (bool activate) override
{
@autoreleasepool
{
WindowBaseImpl::Show();
WindowBaseImpl::Show(activate);
HideOrShowTrafficLights();

2
samples/BindingDemo/App.xaml.cs

@ -1,7 +1,6 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace BindingDemo
{
@ -25,7 +24,6 @@ namespace BindingDemo
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
}
}

3
samples/BindingDemo/BindingDemo.csproj

@ -6,12 +6,11 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
<Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />

4
samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs

@ -1,9 +1,9 @@
using ReactiveUI;
using MiniMvvm;
using System;
namespace BindingDemo.ViewModels
{
public class ExceptionErrorViewModel : ReactiveObject
public class ExceptionErrorViewModel : ViewModelBase
{
private int _lessThan10;

4
samples/BindingDemo/ViewModels/IndeiErrorViewModel.cs

@ -1,11 +1,11 @@
using ReactiveUI;
using MiniMvvm;
using System;
using System.ComponentModel;
using System.Collections;
namespace BindingDemo.ViewModels
{
public class IndeiErrorViewModel : ReactiveObject, INotifyDataErrorInfo
public class IndeiErrorViewModel : ViewModelBase, INotifyDataErrorInfo
{
private int _maximum = 10;
private int _value;

12
samples/BindingDemo/ViewModels/MainWindowViewModel.cs

@ -5,14 +5,14 @@ using System.Reactive;
using System.Reactive.Linq;
using System.Threading.Tasks;
using System.Threading;
using ReactiveUI;
using MiniMvvm;
using Avalonia.Controls;
using Avalonia.Metadata;
using Avalonia.Controls.Selection;
namespace BindingDemo.ViewModels
{
public class MainWindowViewModel : ReactiveObject
public class MainWindowViewModel : ViewModelBase
{
private string _booleanString = "True";
private double _doubleValue = 5.0;
@ -32,13 +32,13 @@ namespace BindingDemo.ViewModels
Selection = new SelectionModel<TestItem> { SingleSelect = false };
ShuffleItems = ReactiveCommand.Create(() =>
ShuffleItems = MiniCommand.Create(() =>
{
var r = new Random();
Items.Move(r.Next(Items.Count), 1);
});
StringValueCommand = ReactiveCommand.Create<object>(param =>
StringValueCommand = MiniCommand.Create<object>(param =>
{
BooleanFlag = !BooleanFlag;
StringValue = param.ToString();
@ -60,7 +60,7 @@ namespace BindingDemo.ViewModels
public ObservableCollection<TestItem> Items { get; }
public SelectionModel<TestItem> Selection { get; }
public ReactiveCommand<Unit, Unit> ShuffleItems { get; }
public MiniCommand ShuffleItems { get; }
public string BooleanString
{
@ -93,7 +93,7 @@ namespace BindingDemo.ViewModels
}
public IObservable<DateTimeOffset> CurrentTimeObservable { get; }
public ReactiveCommand<object, Unit> StringValueCommand { get; }
public MiniCommand StringValueCommand { get; }
public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();

8
samples/BindingDemo/ViewModels/NestedCommandViewModel.cs

@ -1,18 +1,18 @@
using ReactiveUI;
using System;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using MiniMvvm;
namespace BindingDemo.ViewModels
{
public class NestedCommandViewModel : ReactiveObject
public class NestedCommandViewModel : ViewModelBase
{
public NestedCommandViewModel()
{
Command = ReactiveCommand.Create(() => { });
Command = MiniCommand.Create(() => { });
}
public ICommand Command { get; }

4
samples/BindingDemo/ViewModels/TestItem.cs

@ -1,8 +1,8 @@
using ReactiveUI;
using MiniMvvm;
namespace BindingDemo.ViewModels
{
public class TestItem : ReactiveObject
public class TestItem : ViewModelBase
{
private string _stringValue = "String Value";
private string _detail;

4
samples/ControlCatalog.Desktop/Program.cs

@ -3,7 +3,6 @@ using System.Linq;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
using Avalonia.ReactiveUI;
namespace ControlCatalog
{
@ -19,8 +18,7 @@ namespace ControlCatalog
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.LogToTrace()
.UsePlatformDetect()
.UseReactiveUI();
.UsePlatformDetect();
private static void ConfigureAssetAssembly(AppBuilder builder)
{

2
samples/ControlCatalog.NetCore/Program.cs

@ -10,7 +10,6 @@ using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Dialogs;
using Avalonia.Headless;
using Avalonia.LogicalTree;
using Avalonia.ReactiveUI;
using Avalonia.Threading;
namespace ControlCatalog.NetCore
@ -118,7 +117,6 @@ namespace ControlCatalog.NetCore
AllowEglInitialization = true
})
.UseSkia()
.UseReactiveUI()
.UseManagedSystemDialogs()
.LogToTrace();

2
samples/ControlCatalog/ControlCatalog.csproj

@ -24,8 +24,8 @@
<ItemGroup>
<ProjectReference Include="..\..\packages\Avalonia\Avalonia.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\build\BuildTargets.targets" />

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

@ -2,7 +2,6 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.Models;
using ReactiveUI;
namespace ControlCatalog.Pages
{

2
samples/ControlCatalog/Pages/ListBoxPage.xaml

@ -20,6 +20,6 @@
<ListBox Items="{Binding Items}"
Selection="{Binding Selection}"
AutoScrollToSelectedItem="{Binding AutoScrollToSelectedItem}"
SelectionMode="{Binding SelectionMode}"/>
SelectionMode="{Binding SelectionMode^}"/>
</DockPanel>
</UserControl>

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

@ -6,7 +6,6 @@ using System.Windows.Input;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using ControlCatalog.ViewModels;
using ReactiveUI;
namespace ControlCatalog.Pages
{

4
samples/ControlCatalog/Pages/NumericUpDownPage.xaml.cs

@ -6,7 +6,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.Pages
{
@ -26,7 +26,7 @@ namespace ControlCatalog.Pages
}
public class NumbersPageViewModel : ReactiveObject
public class NumbersPageViewModel : ViewModelBase
{
private IList<FormatObject> _formats;
private FormatObject _selectedFormat;

4
samples/ControlCatalog/Pages/ScrollViewerPage.xaml.cs

@ -2,11 +2,11 @@ using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Markup.Xaml;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.Pages
{
public class ScrollViewerPageViewModel : ReactiveObject
public class ScrollViewerPageViewModel : ViewModelBase
{
private bool _allowAutoHide;
private ScrollBarVisibility _horizontalScrollVisibility;

4
samples/ControlCatalog/Pages/TabControlPage.xaml.cs

@ -6,7 +6,7 @@ using Avalonia.Markup.Xaml;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.Pages
{
@ -56,7 +56,7 @@ namespace ControlCatalog.Pages
return new Bitmap(assets.Open(new Uri(uri)));
}
private class PageViewModel : ReactiveObject
private class PageViewModel : ViewModelBase
{
private Dock _tabPlacement;

14
samples/ControlCatalog/ViewModels/ContextMenuPageViewModel.cs

@ -3,7 +3,7 @@ using System.Reactive;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.VisualTree;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
@ -12,9 +12,9 @@ namespace ControlCatalog.ViewModels
public Control View { get; set; }
public ContextMenuPageViewModel()
{
OpenCommand = ReactiveCommand.CreateFromTask(Open);
SaveCommand = ReactiveCommand.Create(Save);
OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent);
OpenCommand = MiniCommand.CreateFromTask(Open);
SaveCommand = MiniCommand.Create(Save);
OpenRecentCommand = MiniCommand.Create<string>(OpenRecent);
MenuItems = new[]
{
@ -44,9 +44,9 @@ namespace ControlCatalog.ViewModels
}
public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
public ReactiveCommand<Unit, Unit> OpenCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<string, Unit> OpenRecentCommand { get; }
public MiniCommand OpenCommand { get; }
public MiniCommand SaveCommand { get; }
public MiniCommand OpenRecentCommand { get; }
public async Task Open()
{

6
samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs

@ -2,11 +2,11 @@
using System.Collections.ObjectModel;
using System.Linq;
using Avalonia.Media;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class ItemsRepeaterPageViewModel : ReactiveObject
public class ItemsRepeaterPageViewModel : ViewModelBase
{
private int _newItemIndex = 1;
private int _newGenerationIndex = 0;
@ -59,7 +59,7 @@ namespace ControlCatalog.ViewModels
}));
}
public class Item : ReactiveObject
public class Item : ViewModelBase
{
private double _height = double.NaN;

27
samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs

@ -4,18 +4,18 @@ using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class ListBoxPageViewModel : ReactiveObject
public class ListBoxPageViewModel : ViewModelBase
{
private bool _multiple;
private bool _toggle;
private bool _alwaysSelected;
private bool _autoScrollToSelectedItem = true;
private int _counter;
private ObservableAsPropertyHelper<SelectionMode> _selectionMode;
private IObservable<SelectionMode> _selectionMode;
public ListBoxPageViewModel()
{
@ -29,14 +29,13 @@ namespace ControlCatalog.ViewModels
x => x.Toggle,
x => x.AlwaysSelected,
(m, t, a) =>
(m ? SelectionMode.Multiple : 0) |
(t ? SelectionMode.Toggle : 0) |
(a ? SelectionMode.AlwaysSelected : 0))
.ToProperty(this, x => x.SelectionMode);
(m ? Avalonia.Controls.SelectionMode.Multiple : 0) |
(t ? Avalonia.Controls.SelectionMode.Toggle : 0) |
(a ? Avalonia.Controls.SelectionMode.AlwaysSelected : 0));
AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
AddItemCommand = MiniCommand.Create(() => Items.Add(GenerateItem()));
RemoveItemCommand = ReactiveCommand.Create(() =>
RemoveItemCommand = MiniCommand.Create(() =>
{
var items = Selection.SelectedItems.ToList();
@ -46,7 +45,7 @@ namespace ControlCatalog.ViewModels
}
});
SelectRandomItemCommand = ReactiveCommand.Create(() =>
SelectRandomItemCommand = MiniCommand.Create(() =>
{
var random = new Random();
@ -60,7 +59,7 @@ namespace ControlCatalog.ViewModels
public ObservableCollection<string> Items { get; }
public SelectionModel<string> Selection { get; }
public SelectionMode SelectionMode => _selectionMode.Value;
public IObservable<SelectionMode> SelectionMode => _selectionMode;
public bool Multiple
{
@ -86,9 +85,9 @@ namespace ControlCatalog.ViewModels
set => this.RaiseAndSetIfChanged(ref _autoScrollToSelectedItem, value);
}
public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
public MiniCommand AddItemCommand { get; }
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
private string GenerateItem() => $"Item {_counter++.ToString()}";
}

28
samples/ControlCatalog/ViewModels/MainWindowViewModel.cs

@ -5,11 +5,11 @@ using Avalonia.Controls.Notifications;
using Avalonia.Dialogs;
using Avalonia.Platform;
using System;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
class MainWindowViewModel : ReactiveObject
class MainWindowViewModel : ViewModelBase
{
private IManagedNotificationManager _notificationManager;
@ -27,22 +27,22 @@ namespace ControlCatalog.ViewModels
{
_notificationManager = notificationManager;
ShowCustomManagedNotificationCommand = ReactiveCommand.Create(() =>
ShowCustomManagedNotificationCommand = MiniCommand.Create(() =>
{
NotificationManager.Show(new NotificationViewModel(NotificationManager) { Title = "Hey There!", Message = "Did you know that Avalonia now supports Custom In-Window Notifications?" });
});
ShowManagedNotificationCommand = ReactiveCommand.Create(() =>
ShowManagedNotificationCommand = MiniCommand.Create(() =>
{
NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Welcome", "Avalonia now supports Notifications.", NotificationType.Information));
});
ShowNativeNotificationCommand = ReactiveCommand.Create(() =>
ShowNativeNotificationCommand = MiniCommand.Create(() =>
{
NotificationManager.Show(new Avalonia.Controls.Notifications.Notification("Error", "Native Notifications are not quite ready. Coming soon.", NotificationType.Error));
});
AboutCommand = ReactiveCommand.CreateFromTask(async () =>
AboutCommand = MiniCommand.CreateFromTask(async () =>
{
var dialog = new AboutAvaloniaDialog();
@ -51,12 +51,12 @@ namespace ControlCatalog.ViewModels
await dialog.ShowDialog(mainWindow);
});
ExitCommand = ReactiveCommand.Create(() =>
ExitCommand = MiniCommand.Create(() =>
{
(App.Current.ApplicationLifetime as IClassicDesktopStyleApplicationLifetime).Shutdown();
});
ToggleMenuItemCheckedCommand = ReactiveCommand.Create(() =>
ToggleMenuItemCheckedCommand = MiniCommand.Create(() =>
{
IsMenuItemChecked = !IsMenuItemChecked;
});
@ -153,16 +153,16 @@ namespace ControlCatalog.ViewModels
set { this.RaiseAndSetIfChanged(ref _isMenuItemChecked, value); }
}
public ReactiveCommand<Unit, Unit> ShowCustomManagedNotificationCommand { get; }
public MiniCommand ShowCustomManagedNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> ShowManagedNotificationCommand { get; }
public MiniCommand ShowManagedNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> ShowNativeNotificationCommand { get; }
public MiniCommand ShowNativeNotificationCommand { get; }
public ReactiveCommand<Unit, Unit> AboutCommand { get; }
public MiniCommand AboutCommand { get; }
public ReactiveCommand<Unit, Unit> ExitCommand { get; }
public MiniCommand ExitCommand { get; }
public ReactiveCommand<Unit, Unit> ToggleMenuItemCheckedCommand { get; }
public MiniCommand ToggleMenuItemCheckedCommand { get; }
}
}

14
samples/ControlCatalog/ViewModels/MenuPageViewModel.cs

@ -4,7 +4,7 @@ using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.VisualTree;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
@ -13,9 +13,9 @@ namespace ControlCatalog.ViewModels
public Control View { get; set; }
public MenuPageViewModel()
{
OpenCommand = ReactiveCommand.CreateFromTask(Open);
SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false));
OpenRecentCommand = ReactiveCommand.Create<string>(OpenRecent);
OpenCommand = MiniCommand.CreateFromTask(Open);
SaveCommand = MiniCommand.Create(Save);
OpenRecentCommand = MiniCommand.Create<string>(OpenRecent);
var recentItems = new[]
{
@ -65,9 +65,9 @@ namespace ControlCatalog.ViewModels
public IReadOnlyList<MenuItemViewModel> MenuItems { get; set; }
public IReadOnlyList<MenuItemViewModel> RecentItems { get; set; }
public ReactiveCommand<Unit, Unit> OpenCommand { get; }
public ReactiveCommand<Unit, Unit> SaveCommand { get; }
public ReactiveCommand<string, Unit> OpenRecentCommand { get; }
public MiniCommand OpenCommand { get; }
public MiniCommand SaveCommand { get; }
public MiniCommand OpenRecentCommand { get; }
public async Task Open()
{

10
samples/ControlCatalog/ViewModels/NotificationViewModel.cs

@ -1,6 +1,6 @@
using System.Reactive;
using Avalonia.Controls.Notifications;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
@ -8,12 +8,12 @@ namespace ControlCatalog.ViewModels
{
public NotificationViewModel(INotificationManager manager)
{
YesCommand = ReactiveCommand.Create(() =>
YesCommand = MiniCommand.Create(() =>
{
manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today."));
});
NoCommand = ReactiveCommand.Create(() =>
NoCommand = MiniCommand.Create(() =>
{
manager.Show(new Avalonia.Controls.Notifications.Notification("Avalonia Notifications", "Start adding notifications to your app today. To find out more visit..."));
});
@ -22,9 +22,9 @@ namespace ControlCatalog.ViewModels
public string Title { get; set; }
public string Message { get; set; }
public ReactiveCommand<Unit, Unit> YesCommand { get; }
public MiniCommand YesCommand { get; }
public ReactiveCommand<Unit, Unit> NoCommand { get; }
public MiniCommand NoCommand { get; }
}
}

4
samples/ControlCatalog/ViewModels/SplitViewPageViewModel.cs

@ -1,10 +1,10 @@
using System;
using Avalonia.Controls;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class SplitViewPageViewModel : ReactiveObject
public class SplitViewPageViewModel : ViewModelBase
{
private bool _isLeft = true;
private int _displayMode = 3; //CompactOverlay

16
samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs

@ -3,11 +3,11 @@ using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using ReactiveUI;
using MiniMvvm;
namespace ControlCatalog.ViewModels
{
public class TreeViewPageViewModel : ReactiveObject
public class TreeViewPageViewModel : ViewModelBase
{
private readonly Node _root;
private SelectionMode _selectionMode;
@ -19,16 +19,16 @@ namespace ControlCatalog.ViewModels
Items = _root.Children;
SelectedItems = new ObservableCollection<Node>();
AddItemCommand = ReactiveCommand.Create(AddItem);
RemoveItemCommand = ReactiveCommand.Create(RemoveItem);
SelectRandomItemCommand = ReactiveCommand.Create(SelectRandomItem);
AddItemCommand = MiniCommand.Create(AddItem);
RemoveItemCommand = MiniCommand.Create(RemoveItem);
SelectRandomItemCommand = MiniCommand.Create(SelectRandomItem);
}
public ObservableCollection<Node> Items { get; }
public ObservableCollection<Node> SelectedItems { get; }
public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
public MiniCommand AddItemCommand { get; }
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
public SelectionMode SelectionMode
{

66
samples/MiniMvvm/MiniCommand.cs

@ -0,0 +1,66 @@
using System;
using System.Threading.Tasks;
using System.Windows.Input;
namespace MiniMvvm
{
public sealed class MiniCommand<T> : MiniCommand, ICommand
{
private readonly Action<T> _cb;
private bool _busy;
private Func<T, Task> _acb;
public MiniCommand(Action<T> cb)
{
_cb = cb;
}
public MiniCommand(Func<T, Task> cb)
{
_acb = cb;
}
private bool Busy
{
get => _busy;
set
{
_busy = value;
CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}
}
public override event EventHandler CanExecuteChanged;
public override bool CanExecute(object parameter) => !_busy;
public override async void Execute(object parameter)
{
if(Busy)
return;
try
{
Busy = true;
if (_cb != null)
_cb((T)parameter);
else
await _acb((T)parameter);
}
finally
{
Busy = false;
}
}
}
public abstract class MiniCommand : ICommand
{
public static MiniCommand Create(Action cb) => new MiniCommand<object>(_ => cb());
public static MiniCommand Create<TArg>(Action<TArg> cb) => new MiniCommand<TArg>(cb);
public static MiniCommand CreateFromTask(Func<Task> cb) => new MiniCommand<object>(_ => cb());
public abstract bool CanExecute(object parameter);
public abstract void Execute(object parameter);
public abstract event EventHandler CanExecuteChanged;
}
}

6
samples/MiniMvvm/MiniMvvm.csproj

@ -0,0 +1,6 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<Import Project="..\..\build\Rx.props" />
</Project>

108
samples/MiniMvvm/PropertyChangedExtensions.cs

@ -0,0 +1,108 @@
using System;
using System.ComponentModel;
using System.Linq.Expressions;
using System.Reactive.Linq;
using System.Reflection;
namespace MiniMvvm
{
public static class PropertyChangedExtensions
{
class PropertyObservable<T> : IObservable<T>
{
private readonly INotifyPropertyChanged _target;
private readonly PropertyInfo _info;
public PropertyObservable(INotifyPropertyChanged target, PropertyInfo info)
{
_target = target;
_info = info;
}
class Subscription : IDisposable
{
private readonly INotifyPropertyChanged _target;
private readonly PropertyInfo _info;
private readonly IObserver<T> _observer;
public Subscription(INotifyPropertyChanged target, PropertyInfo info, IObserver<T> observer)
{
_target = target;
_info = info;
_observer = observer;
_target.PropertyChanged += OnPropertyChanged;
_observer.OnNext((T)_info.GetValue(_target));
}
private void OnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == _info.Name)
_observer.OnNext((T)_info.GetValue(_target));
}
public void Dispose()
{
_target.PropertyChanged -= OnPropertyChanged;
_observer.OnCompleted();
}
}
public IDisposable Subscribe(IObserver<T> observer)
{
return new Subscription(_target, _info, observer);
}
}
public static IObservable<TRes> WhenAnyValue<TModel, TRes>(this TModel model,
Expression<Func<TModel, TRes>> expr) where TModel : INotifyPropertyChanged
{
var l = (LambdaExpression)expr;
var ma = (MemberExpression)l.Body;
var prop = (PropertyInfo)ma.Member;
return new PropertyObservable<TRes>(model, prop);
}
public static IObservable<TRes> WhenAnyValue<TModel, T1, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Func<T1, TRes> cb
) where TModel : INotifyPropertyChanged
{
return model.WhenAnyValue(v1).Select(cb);
}
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Func<T1, T2, TRes> cb
) where TModel : INotifyPropertyChanged =>
Observable.CombineLatest(
model.WhenAnyValue(v1),
model.WhenAnyValue(v2),
cb);
public static IObservable<ValueTuple<T1, T2>> WhenAnyValue<TModel, T1, T2>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2
) where TModel : INotifyPropertyChanged =>
model.WhenAnyValue(v1, v2, (a1, a2) => (a1, a2));
public static IObservable<TRes> WhenAnyValue<TModel, T1, T2, T3, TRes>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Expression<Func<TModel, T3>> v3,
Func<T1, T2, T3, TRes> cb
) where TModel : INotifyPropertyChanged =>
Observable.CombineLatest(
model.WhenAnyValue(v1),
model.WhenAnyValue(v2),
model.WhenAnyValue(v3),
cb);
public static IObservable<ValueTuple<T1, T2, T3>> WhenAnyValue<TModel, T1, T2, T3>(this TModel model,
Expression<Func<TModel, T1>> v1,
Expression<Func<TModel, T2>> v2,
Expression<Func<TModel, T3>> v3
) where TModel : INotifyPropertyChanged =>
model.WhenAnyValue(v1, v2, v3, (a1, a2, a3) => (a1, a2, a3));
}
}

26
samples/MiniMvvm/ViewModelBase.cs

@ -0,0 +1,26 @@
using System.Collections.Generic;
using System.ComponentModel;
using System.Reactive.Joins;
using System.Runtime.CompilerServices;
namespace MiniMvvm
{
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected bool RaiseAndSetIfChanged<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
RaisePropertyChanged(propertyName);
return true;
}
return false;
}
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}

1
samples/Previewer/Previewer.csproj

@ -8,7 +8,6 @@
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<EmbeddedResource Include="**\*.xaml" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />

2
samples/RenderDemo/App.xaml

@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="RenderDemo.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentLight.xaml"/>
<FluentTheme/>
<StyleInclude Source="avares://RenderDemo/SideBar.xaml"/>
</Application.Styles>
</Application>

2
samples/RenderDemo/App.xaml.cs

@ -1,7 +1,6 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace RenderDemo
{
@ -32,7 +31,6 @@ namespace RenderDemo
OverlayPopups = true,
})
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
}
}

2
samples/RenderDemo/MainWindow.xaml.cs

@ -3,7 +3,7 @@ using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using RenderDemo.ViewModels;
using ReactiveUI;
using MiniMvvm;
namespace RenderDemo
{

3
samples/RenderDemo/RenderDemo.csproj

@ -9,12 +9,11 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
<Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />

4
samples/RenderDemo/ViewModels/AnimationsPageViewModel.cs

@ -1,10 +1,10 @@
using System;
using ReactiveUI;
using MiniMvvm;
using Avalonia.Animation;
namespace RenderDemo.ViewModels
{
public class AnimationsPageViewModel : ReactiveObject
public class AnimationsPageViewModel : ViewModelBase
{
private bool _isPlaying = true;

17
samples/RenderDemo/ViewModels/MainWindowViewModel.cs

@ -1,11 +1,10 @@
using System.Reactive;
using System.Threading.Tasks;
using ReactiveUI;
using MiniMvvm;
namespace RenderDemo.ViewModels
{
public class MainWindowViewModel : ReactiveObject
public class MainWindowViewModel : ViewModelBase
{
private bool drawDirtyRects = false;
private bool drawFps = true;
@ -14,9 +13,9 @@ namespace RenderDemo.ViewModels
public MainWindowViewModel()
{
ToggleDrawDirtyRects = ReactiveCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = ReactiveCommand.Create(() => DrawFps = !DrawFps);
ResizeWindow = ReactiveCommand.CreateFromTask(ResizeWindowAsync);
ToggleDrawDirtyRects = MiniCommand.Create(() => DrawDirtyRects = !DrawDirtyRects);
ToggleDrawFps = MiniCommand.Create(() => DrawFps = !DrawFps);
ResizeWindow = MiniCommand.CreateFromTask(ResizeWindowAsync);
}
public bool DrawDirtyRects
@ -43,9 +42,9 @@ namespace RenderDemo.ViewModels
set => this.RaiseAndSetIfChanged(ref height, value);
}
public ReactiveCommand<Unit, bool> ToggleDrawDirtyRects { get; }
public ReactiveCommand<Unit, bool> ToggleDrawFps { get; }
public ReactiveCommand<Unit, Unit> ResizeWindow { get; }
public MiniCommand ToggleDrawDirtyRects { get; }
public MiniCommand ToggleDrawFps { get; }
public MiniCommand ResizeWindow { get; }
private async Task ResizeWindowAsync()
{

2
samples/Sandbox/App.axaml

@ -3,6 +3,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Sandbox.App">
<Application.Styles>
<StyleInclude Source="avares://Avalonia.Themes.Fluent/FluentDark.xaml"/>
<FluentTheme Mode="Dark"/>
</Application.Styles>
</Application>

2
samples/Sandbox/Program.cs

@ -1,5 +1,4 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace Sandbox
{
@ -9,7 +8,6 @@ namespace Sandbox
{
AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace()
.StartWithClassicDesktopLifetime(args);
}

1
samples/Sandbox/Sandbox.csproj

@ -8,7 +8,6 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\src\Avalonia.Controls.DataGrid\Avalonia.Controls.DataGrid.csproj" />
</ItemGroup>

2
samples/VirtualizationDemo/Program.cs

@ -1,5 +1,4 @@
using Avalonia;
using Avalonia.ReactiveUI;
namespace VirtualizationDemo
{
@ -8,7 +7,6 @@ namespace VirtualizationDemo
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseReactiveUI()
.LogToTrace();
public static int Main(string[] args)

4
samples/VirtualizationDemo/ViewModels/ItemViewModel.cs

@ -1,9 +1,9 @@
using System;
using ReactiveUI;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels
{
internal class ItemViewModel : ReactiveObject
internal class ItemViewModel : ViewModelBase
{
private string _prefix;
private int _index;

24
samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs

@ -5,13 +5,13 @@ using System.Reactive;
using Avalonia.Collections;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ReactiveUI;
using Avalonia.Layout;
using Avalonia.Controls.Selection;
using MiniMvvm;
namespace VirtualizationDemo.ViewModels
{
internal class MainWindowViewModel : ReactiveObject
internal class MainWindowViewModel : ViewModelBase
{
private int _itemCount = 200;
private string _newItemString = "New Item";
@ -26,15 +26,15 @@ namespace VirtualizationDemo.ViewModels
public MainWindowViewModel()
{
this.WhenAnyValue(x => x.ItemCount).Subscribe(ResizeItems);
RecreateCommand = ReactiveCommand.Create(() => Recreate());
RecreateCommand = MiniCommand.Create(() => Recreate());
AddItemCommand = ReactiveCommand.Create(() => AddItem());
AddItemCommand = MiniCommand.Create(() => AddItem());
RemoveItemCommand = ReactiveCommand.Create(() => Remove());
RemoveItemCommand = MiniCommand.Create(() => Remove());
SelectFirstCommand = ReactiveCommand.Create(() => SelectItem(0));
SelectFirstCommand = MiniCommand.Create(() => SelectItem(0));
SelectLastCommand = ReactiveCommand.Create(() => SelectItem(Items.Count - 1));
SelectLastCommand = MiniCommand.Create(() => SelectItem(Items.Count - 1));
}
public string NewItemString
@ -90,11 +90,11 @@ namespace VirtualizationDemo.ViewModels
public IEnumerable<ItemVirtualizationMode> VirtualizationModes =>
Enum.GetValues(typeof(ItemVirtualizationMode)).Cast<ItemVirtualizationMode>();
public ReactiveCommand<Unit, Unit> AddItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RecreateCommand { get; private set; }
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectFirstCommand { get; private set; }
public ReactiveCommand<Unit, Unit> SelectLastCommand { get; private set; }
public MiniCommand AddItemCommand { get; private set; }
public MiniCommand RecreateCommand { get; private set; }
public MiniCommand RemoveItemCommand { get; private set; }
public MiniCommand SelectFirstCommand { get; private set; }
public MiniCommand SelectLastCommand { get; private set; }
public void RandomizeSize()
{

3
samples/VirtualizationDemo/VirtualizationDemo.csproj

@ -6,12 +6,11 @@
<ItemGroup>
<ProjectReference Include="..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj" />
<ProjectReference Include="..\..\src\Linux\Avalonia.LinuxFramebuffer\Avalonia.LinuxFramebuffer.csproj" />
<ProjectReference Include="..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\build\SampleApp.props" />
<Import Project="..\..\build\EmbedXaml.props" />
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\ReactiveUI.props" />
<Import Condition="'$(TargetFramework)'=='net461'" Project="..\..\build\NetFX.props" />
<Import Project="..\..\build\ReferenceCoreLibraries.props" />
<Import Project="..\..\build\BuildTargets.targets" />

2
samples/interop/Direct3DInteropSample/Direct3DInteropSample.csproj

@ -22,9 +22,9 @@
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj" />
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj" />
<ProjectReference Include="..\..\MiniMvvm\MiniMvvm.csproj" />
</ItemGroup>
<Import Project="..\..\..\build\Rx.props" />
<Import Project="..\..\..\build\ReferenceCoreLibraries.props" />

4
samples/interop/Direct3DInteropSample/MainWindowViewModel.cs

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ReactiveUI;
using MiniMvvm;
namespace Direct3DInteropSample
{
public class MainWindowViewModel : ReactiveObject
public class MainWindowViewModel : ViewModelBase
{
private double _rotationX;

6
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@ -136,10 +136,6 @@
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>
@ -190,4 +186,4 @@
<Import Project="..\..\..\build\Rx.props" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Import Project="..\..\..\build\LegacyProject.targets" />
</Project>
</Project>

4
src/Android/Avalonia.AndroidTestApplication/Avalonia.AndroidTestApplication.csproj

@ -127,10 +127,6 @@
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Visuals\Avalonia.Visuals.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.Visuals</Name>

4
src/Avalonia.Base/ApiCompatBaseline.txt

@ -1,4 +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.
MembersMustExist : Member 'public void Avalonia.Threading.AvaloniaSynchronizationContext..ctor(Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider)' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Threading.AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider' does not exist in the implementation but it does exist in the contract.
Total Issues: 2

5
src/Avalonia.Base/Logging/LogArea.cs

@ -34,5 +34,10 @@ namespace Avalonia.Logging
/// The log event comes from the control system.
/// </summary>
public const string Control = "Control";
/// <summary>
/// The log event comes from Win32Platform.
/// </summary>
public const string Win32Platform = nameof(Win32Platform);
}
}

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

@ -11,10 +11,12 @@ using Avalonia.Metadata;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
[assembly: InternalsVisibleTo("Avalonia.Visuals, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
#else
[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.UnitTests")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")]
[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")]
[assembly: InternalsVisibleTo("Avalonia.Visuals")]
#endif

25
src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs

@ -9,20 +9,6 @@ namespace Avalonia.Threading
/// </summary>
public class AvaloniaSynchronizationContext : SynchronizationContext
{
public interface INonPumpingPlatformWaitProvider
{
int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
}
private readonly INonPumpingPlatformWaitProvider _waitProvider;
public AvaloniaSynchronizationContext(INonPumpingPlatformWaitProvider waitProvider)
{
_waitProvider = waitProvider;
if (_waitProvider != null)
SetWaitNotificationRequired();
}
/// <summary>
/// Controls if SynchronizationContext should be installed in InstallIfNeeded. Used by Designer.
/// </summary>
@ -38,8 +24,7 @@ namespace Avalonia.Threading
return;
}
SetSynchronizationContext(new AvaloniaSynchronizationContext(AvaloniaLocator.Current
.GetService<INonPumpingPlatformWaitProvider>()));
SetSynchronizationContext(new AvaloniaSynchronizationContext());
}
/// <inheritdoc/>
@ -57,12 +42,6 @@ namespace Avalonia.Threading
Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait();
}
[PrePrepareMethod]
public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
if (_waitProvider != null)
return _waitProvider.Wait(waitHandles, waitAll, millisecondsTimeout);
return base.Wait(waitHandles, waitAll, millisecondsTimeout);
}
}
}

14
src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs

@ -0,0 +1,14 @@
using System;
namespace Avalonia.Utilities
{
public class NonPumpingLockHelper
{
public interface IHelperImpl
{
IDisposable Use();
}
public static IDisposable Use() => AvaloniaLocator.Current.GetService<IHelperImpl>()?.Use();
}
}

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

@ -1,5 +1 @@
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
Total Issues: 0

29
src/Avalonia.Controls.DataGrid/Themes/Default.xaml

@ -137,12 +137,37 @@
</Style>
<Style Selector="DataGridRowHeader">
<Setter Property="Focusable" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Grid x:Name="PART_Root"
RowDefinitions="*,*,Auto"
ColumnDefinitions="Auto,*">
RowDefinitions="*,*,Auto"
ColumnDefinitions="Auto,*">
<Border Grid.RowSpan="3"
Grid.ColumnSpan="2"
BorderBrush="{TemplateBinding SeparatorBrush}"
BorderThickness="0,0,1,0">
<Grid Background="{TemplateBinding Background}">
<Rectangle x:Name="RowInvalidVisualElement"
Stretch="Fill" />
<Rectangle x:Name="BackgroundRectangle"
Stretch="Fill" />
</Grid>
</Border>
<Rectangle x:Name="HorizontalSeparator"
Grid.Row="2"
Grid.ColumnSpan="2"
Height="1"
Margin="1,0,1,0"
HorizontalAlignment="Stretch"
Fill="{TemplateBinding SeparatorBrush}"
IsVisible="{TemplateBinding AreSeparatorsVisible}" />
<ContentPresenter Grid.RowSpan="2"
Grid.Column="1"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding Content}" />
</Grid>
</ControlTemplate>
</Setter>

29
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -1,26 +1,5 @@
Compat issues with assembly Avalonia.Controls:
TypesMustExist : Type 'Avalonia.Controls.IndexPath' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.ISelectedItemInfo' does not exist in the implementation but it does exist in the contract.
TypesMustExist : Type 'Avalonia.Controls.ISelectionModel' 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.ListBox.SelectionProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.ListBox.Selection.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(Avalonia.Controls.ISelectionModel)' 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.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.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 void Avalonia.Controls.TreeView.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime.Args.get()' is present in the implementation but not 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 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: 24
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show()' is present in the contract but not in the implementation.
MembersMustExist : Member 'public void Avalonia.Platform.IWindowBaseImpl.Show()' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Platform.IWindowBaseImpl.Show(System.Boolean)' is present in the implementation but not in the contract.
Total Issues: 3

10
src/Avalonia.Controls/ContextMenu.cs

@ -233,6 +233,16 @@ namespace Avalonia.Controls
}
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == WindowManagerAddShadowHintProperty && _popup != null)
{
_popup.WindowManagerAddShadowHint = change.NewValue.GetValueOrDefault<bool>();
}
}
/// <summary>
/// Opens the menu.
/// </summary>

4
src/Avalonia.Controls/Platform/IWindowBaseImpl.cs

@ -5,9 +5,9 @@ namespace Avalonia.Platform
public interface IWindowBaseImpl : ITopLevelImpl
{
/// <summary>
/// Shows the top level.
/// Shows the window.
/// </summary>
void Show();
void Show(bool activate);
/// <summary>
/// Hides the window.

5
src/Avalonia.Controls/TextBox.cs

@ -867,7 +867,10 @@ namespace Avalonia.Controls
{
var point = e.GetPosition(_presenter);
point = new Point(MathUtilities.Clamp(point.X, 0, _presenter.Bounds.Width - 1), MathUtilities.Clamp(point.Y, 0, _presenter.Bounds.Height - 1));
point = new Point(
MathUtilities.Clamp(point.X, 0, Math.Max(_presenter.Bounds.Width - 1, 0)),
MathUtilities.Clamp(point.Y, 0, Math.Max(_presenter.Bounds.Height - 1, 0)));
CaretIndex = SelectionEnd = _presenter.GetCaretIndex(point);
}
}

20
src/Avalonia.Controls/Window.cs

@ -129,6 +129,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty<SystemDecorations> SystemDecorationsProperty =
AvaloniaProperty.Register<Window, SystemDecorations>(nameof(SystemDecorations), SystemDecorations.Full);
/// <summary>
/// Defines the <see cref="ShowActivated"/> property.
/// </summary>
public static readonly StyledProperty<bool> ShowActivatedProperty =
AvaloniaProperty.Register<Window, bool>(nameof(ShowActivated), true);
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
@ -352,13 +358,21 @@ namespace Avalonia.Controls
/// <summary>
/// Sets the system decorations (title bar, border, etc)
/// </summary>
///
public SystemDecorations SystemDecorations
{
get { return GetValue(SystemDecorationsProperty); }
set { SetValue(SystemDecorationsProperty, value); }
}
/// <summary>
/// Gets or sets a value that indicates whether a window is activated when first shown.
/// </summary>
public bool ShowActivated
{
get { return GetValue(ShowActivatedProperty); }
set { SetValue(ShowActivatedProperty, value); }
}
/// <summary>
/// Enables or disables the taskbar icon
/// </summary>
@ -650,7 +664,7 @@ namespace Avalonia.Controls
Owner = parent;
parent?.AddChild(this, false);
PlatformImpl?.Show();
PlatformImpl?.Show(ShowActivated);
Renderer?.Start();
SetWindowStartupLocation(Owner?.PlatformImpl);
}
@ -720,7 +734,7 @@ namespace Avalonia.Controls
PlatformImpl?.SetParent(owner.PlatformImpl);
Owner = owner;
owner.AddChild(this, true);
PlatformImpl?.Show();
PlatformImpl?.Show(ShowActivated);
Renderer?.Start();

2
src/Avalonia.Controls/WindowBase.cs

@ -162,7 +162,7 @@ namespace Avalonia.Controls
LayoutManager.ExecuteInitialLayoutPass();
_hasExecutedInitialLayoutPass = true;
}
PlatformImpl?.Show();
PlatformImpl?.Show(true);
Renderer?.Start();
OnOpened(EventArgs.Empty);
}

2
src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs

@ -20,7 +20,7 @@ namespace Avalonia.DesignerSupport.Remote
ClientSize = new Size(1, 1);
}
public void Show()
public void Show(bool activate)
{
}

2
src/Avalonia.DesignerSupport/Remote/Stubs.cs

@ -77,7 +77,7 @@ namespace Avalonia.DesignerSupport.Remote
{
}
public void Show()
public void Show(bool activate)
{
}

2
src/Avalonia.FreeDesktop/DBusHelper.cs

@ -43,7 +43,7 @@ namespace Avalonia.FreeDesktop
public void Initialized()
{
lock (_lock)
_ctx = new AvaloniaSynchronizationContext(null);
_ctx = new AvaloniaSynchronizationContext();
}
}
public static Connection Connection { get; private set; }

7
src/Avalonia.Headless/HeadlessWindowImpl.cs

@ -75,9 +75,10 @@ namespace Avalonia.Headless
public Action Closed { get; set; }
public IMouseDevice MouseDevice { get; }
public void Show()
public void Show(bool activate)
{
Dispatcher.UIThread.Post(() => Activated?.Invoke(), DispatcherPriority.Input);
if (activate)
Dispatcher.UIThread.Post(() => Activated?.Invoke(), DispatcherPriority.Input);
}
public void Hide()
@ -148,7 +149,7 @@ namespace Avalonia.Headless
public void ShowDialog(IWindowImpl parent)
{
Show();
Show(true);
}
public void SetSystemDecorations(bool enabled)

6
src/Avalonia.Layout/LayoutContext.cs

@ -14,7 +14,11 @@ namespace Avalonia.Layout
/// <summary>
/// Gets or sets an object that represents the state of a layout.
/// </summary>
public object LayoutState { get; set; }
public object LayoutState
{
get => LayoutStateCore;
set => LayoutStateCore = value;
}
/// <summary>
/// Implements the behavior of <see cref="LayoutState"/> in a derived or custom LayoutContext.

4
src/Avalonia.Native/IAvnMenuItem.cs

@ -55,9 +55,9 @@ namespace Avalonia.Native.Interop.Impl
private void UpdateGesture(Input.KeyGesture gesture)
{
var text = gesture == null ? "" : OsxUnicodeKeys.ConvertOSXSpecialKeyCodes(gesture.Key);
var modifiers = gesture == null ? AvnInputModifiers.AvnInputModifiersNone : (AvnInputModifiers)gesture.KeyModifiers;
SetGesture(text, modifiers);
var key = gesture == null ? AvnKey.AvnKeyNone : (AvnKey)gesture.Key;
SetGesture(key, modifiers);
}
private void UpdateAction(NativeMenuItem item)

152
src/Avalonia.Native/OsxUnicodeKeys.cs

@ -1,152 +0,0 @@
using System.Collections.Generic;
using Avalonia.Input;
namespace Avalonia.Native.Interop
{
internal static class OsxUnicodeKeys
{
enum OsxUnicodeSpecialKey
{
NSUpArrowFunctionKey = 0xF700,
NSDownArrowFunctionKey = 0xF701,
NSLeftArrowFunctionKey = 0xF702,
NSRightArrowFunctionKey = 0xF703,
NSF1FunctionKey = 0xF704,
NSF2FunctionKey = 0xF705,
NSF3FunctionKey = 0xF706,
NSF4FunctionKey = 0xF707,
NSF5FunctionKey = 0xF708,
NSF6FunctionKey = 0xF709,
NSF7FunctionKey = 0xF70A,
NSF8FunctionKey = 0xF70B,
NSF9FunctionKey = 0xF70C,
NSF10FunctionKey = 0xF70D,
NSF11FunctionKey = 0xF70E,
NSF12FunctionKey = 0xF70F,
NSF13FunctionKey = 0xF710,
NSF14FunctionKey = 0xF711,
NSF15FunctionKey = 0xF712,
NSF16FunctionKey = 0xF713,
NSF17FunctionKey = 0xF714,
NSF18FunctionKey = 0xF715,
NSF19FunctionKey = 0xF716,
NSF20FunctionKey = 0xF717,
NSF21FunctionKey = 0xF718,
NSF22FunctionKey = 0xF719,
NSF23FunctionKey = 0xF71A,
NSF24FunctionKey = 0xF71B,
NSF25FunctionKey = 0xF71C,
NSF26FunctionKey = 0xF71D,
NSF27FunctionKey = 0xF71E,
NSF28FunctionKey = 0xF71F,
NSF29FunctionKey = 0xF720,
NSF30FunctionKey = 0xF721,
NSF31FunctionKey = 0xF722,
NSF32FunctionKey = 0xF723,
NSF33FunctionKey = 0xF724,
NSF34FunctionKey = 0xF725,
NSF35FunctionKey = 0xF726,
NSInsertFunctionKey = 0xF727,
NSDeleteFunctionKey = 0xF728,
NSHomeFunctionKey = 0xF729,
NSBeginFunctionKey = 0xF72A,
NSEndFunctionKey = 0xF72B,
NSPageUpFunctionKey = 0xF72C,
NSPageDownFunctionKey = 0xF72D,
NSPrintScreenFunctionKey = 0xF72E,
NSScrollLockFunctionKey = 0xF72F,
NSPauseFunctionKey = 0xF730,
NSSysReqFunctionKey = 0xF731,
NSBreakFunctionKey = 0xF732,
NSResetFunctionKey = 0xF733,
NSStopFunctionKey = 0xF734,
NSMenuFunctionKey = 0xF735,
NSUserFunctionKey = 0xF736,
NSSystemFunctionKey = 0xF737,
NSPrintFunctionKey = 0xF738,
NSClearLineFunctionKey = 0xF739,
NSClearDisplayFunctionKey = 0xF73A,
NSInsertLineFunctionKey = 0xF73B,
NSDeleteLineFunctionKey = 0xF73C,
NSInsertCharFunctionKey = 0xF73D,
NSDeleteCharFunctionKey = 0xF73E,
NSPrevFunctionKey = 0xF73F,
NSNextFunctionKey = 0xF740,
NSSelectFunctionKey = 0xF741,
NSExecuteFunctionKey = 0xF742,
NSUndoFunctionKey = 0xF743,
NSRedoFunctionKey = 0xF744,
NSFindFunctionKey = 0xF745,
NSHelpFunctionKey = 0xF746,
NSModeSwitchFunctionKey = 0xF747
}
private static Dictionary<Key, OsxUnicodeSpecialKey> s_osxKeys = new Dictionary<Key, OsxUnicodeSpecialKey>
{
{Key.Up, OsxUnicodeSpecialKey.NSUpArrowFunctionKey },
{Key.Down, OsxUnicodeSpecialKey.NSDownArrowFunctionKey },
{Key.Left, OsxUnicodeSpecialKey.NSLeftArrowFunctionKey },
{Key.Right, OsxUnicodeSpecialKey.NSRightArrowFunctionKey },
{ Key.F1, OsxUnicodeSpecialKey.NSF1FunctionKey },
{ Key.F2, OsxUnicodeSpecialKey.NSF2FunctionKey },
{ Key.F3, OsxUnicodeSpecialKey.NSF3FunctionKey },
{ Key.F4, OsxUnicodeSpecialKey.NSF4FunctionKey },
{ Key.F5, OsxUnicodeSpecialKey.NSF5FunctionKey },
{ Key.F6, OsxUnicodeSpecialKey.NSF6FunctionKey },
{ Key.F7, OsxUnicodeSpecialKey.NSF7FunctionKey },
{ Key.F8, OsxUnicodeSpecialKey.NSF8FunctionKey },
{ Key.F9, OsxUnicodeSpecialKey.NSF9FunctionKey },
{ Key.F10, OsxUnicodeSpecialKey.NSF10FunctionKey },
{ Key.F11, OsxUnicodeSpecialKey.NSF11FunctionKey },
{ Key.F12, OsxUnicodeSpecialKey.NSF12FunctionKey },
{ Key.F13, OsxUnicodeSpecialKey.NSF13FunctionKey },
{ Key.F14, OsxUnicodeSpecialKey.NSF14FunctionKey },
{ Key.F15, OsxUnicodeSpecialKey.NSF15FunctionKey },
{ Key.F16, OsxUnicodeSpecialKey.NSF16FunctionKey },
{ Key.F17, OsxUnicodeSpecialKey.NSF17FunctionKey },
{ Key.F18, OsxUnicodeSpecialKey.NSF18FunctionKey },
{ Key.F19, OsxUnicodeSpecialKey.NSF19FunctionKey },
{ Key.F20, OsxUnicodeSpecialKey.NSF20FunctionKey },
{ Key.F21, OsxUnicodeSpecialKey.NSF21FunctionKey },
{ Key.F22, OsxUnicodeSpecialKey.NSF22FunctionKey },
{ Key.F23, OsxUnicodeSpecialKey.NSF23FunctionKey },
{ Key.F24, OsxUnicodeSpecialKey.NSF24FunctionKey },
{ Key.Insert, OsxUnicodeSpecialKey.NSInsertFunctionKey },
{ Key.Delete, OsxUnicodeSpecialKey.NSDeleteFunctionKey },
{ Key.Home, OsxUnicodeSpecialKey.NSHomeFunctionKey },
//{ Key.Begin, OsxUnicodeSpecialKey.NSBeginFunctionKey },
{ Key.End, OsxUnicodeSpecialKey.NSEndFunctionKey },
{ Key.PageUp, OsxUnicodeSpecialKey.NSPageUpFunctionKey },
{ Key.PageDown, OsxUnicodeSpecialKey.NSPageDownFunctionKey },
{ Key.PrintScreen, OsxUnicodeSpecialKey.NSPrintScreenFunctionKey },
{ Key.Scroll, OsxUnicodeSpecialKey.NSScrollLockFunctionKey },
//{ Key.SysReq, OsxUnicodeSpecialKey.NSSysReqFunctionKey },
//{ Key.Break, OsxUnicodeSpecialKey.NSBreakFunctionKey },
//{ Key.Reset, OsxUnicodeSpecialKey.NSResetFunctionKey },
//{ Key.Stop, OsxUnicodeSpecialKey.NSStopFunctionKey },
//{ Key.Menu, OsxUnicodeSpecialKey.NSMenuFunctionKey },
//{ Key.UserFunction, OsxUnicodeSpecialKey.NSUserFunctionKey },
//{ Key.SystemFunction, OsxUnicodeSpecialKey.NSSystemFunctionKey },
{ Key.Print, OsxUnicodeSpecialKey.NSPrintFunctionKey },
//{ Key.ClearLine, OsxUnicodeSpecialKey.NSClearLineFunctionKey },
//{ Key.ClearDisplay, OsxUnicodeSpecialKey.NSClearDisplayFunctionKey },
};
public static string ConvertOSXSpecialKeyCodes(Key key)
{
if (s_osxKeys.ContainsKey(key))
{
return ((char)s_osxKeys[key]).ToString();
}
else
{
if (key >= Key.D0 && key <= Key.D9)
{
return key.ToString().Replace("D", "");
}
return key.ToString().ToLower();
}
}
}
}

4
src/Avalonia.Native/PopupImpl.cs

@ -60,14 +60,14 @@ namespace Avalonia.Native
}
}
public override void Show()
public override void Show(bool activate)
{
var parent = _parent;
while (parent is PopupImpl p)
parent = p._parent;
if (parent is WindowImpl w)
w.Native.TakeFocusFromChildren();
base.Show();
base.Show(false);
}
public override IPopupImpl CreatePopup() => new PopupImpl(_factory, _opts, _glFeature, this);

4
src/Avalonia.Native/WindowImplBase.cs

@ -351,9 +351,9 @@ namespace Avalonia.Native
}
public virtual void Show()
public virtual void Show(bool activate)
{
_native.Show();
_native.Show(activate.AsComBool());
}

211
src/Avalonia.Native/avn.idl

@ -3,10 +3,215 @@
@clr-map bool int
@cpp-preamble @@
#include "com.h"
#include "key.h"
#include "stddef.h"
@@
enum AvnKey
{
AvnKeyNone = 0,
AvnKeyCancel = 1,
AvnKeyBack = 2,
AvnKeyTab = 3,
AvnKeyLineFeed = 4,
AvnKeyClear = 5,
AvnKeyReturn = 6,
AvnKeyEnter = 6,
AvnKeyPause = 7,
AvnKeyCapsLock = 8,
AvnKeyCapital = 8,
AvnKeyHangulMode = 9,
AvnKeyKanaMode = 9,
AvnKeyJunjaMode = 10,
AvnKeyFinalMode = 11,
AvnKeyKanjiMode = 12,
HanjaMode = 12,
Escape = 13,
ImeConvert = 14,
ImeNonConvert = 15,
ImeAccept = 16,
ImeModeChange = 17,
Space = 18,
PageUp = 19,
Prior = 19,
PageDown = 20,
Next = 20,
End = 21,
Home = 22,
Left = 23,
Up = 24,
Right = 25,
Down = 26,
Select = 27,
Print = 28,
Execute = 29,
Snapshot = 30,
PrintScreen = 30,
Insert = 31,
Delete = 32,
Help = 33,
D0 = 34,
D1 = 35,
D2 = 36,
D3 = 37,
D4 = 38,
D5 = 39,
D6 = 40,
D7 = 41,
D8 = 42,
D9 = 43,
A = 44,
B = 45,
C = 46,
D = 47,
E = 48,
F = 49,
G = 50,
H = 51,
I = 52,
J = 53,
AvnKeyK = 54,
L = 55,
M = 56,
N = 57,
O = 58,
P = 59,
Q = 60,
R = 61,
S = 62,
T = 63,
U = 64,
V = 65,
W = 66,
X = 67,
Y = 68,
Z = 69,
LWin = 70,
RWin = 71,
Apps = 72,
Sleep = 73,
NumPad0 = 74,
NumPad1 = 75,
NumPad2 = 76,
NumPad3 = 77,
NumPad4 = 78,
NumPad5 = 79,
NumPad6 = 80,
NumPad7 = 81,
NumPad8 = 82,
NumPad9 = 83,
Multiply = 84,
Add = 85,
Separator = 86,
Subtract = 87,
Decimal = 88,
Divide = 89,
F1 = 90,
F2 = 91,
F3 = 92,
F4 = 93,
F5 = 94,
F6 = 95,
F7 = 96,
F8 = 97,
F9 = 98,
F10 = 99,
F11 = 100,
F12 = 101,
F13 = 102,
F14 = 103,
F15 = 104,
F16 = 105,
F17 = 106,
F18 = 107,
F19 = 108,
F20 = 109,
F21 = 110,
F22 = 111,
F23 = 112,
F24 = 113,
NumLock = 114,
Scroll = 115,
LeftShift = 116,
RightShift = 117,
LeftCtrl = 118,
RightCtrl = 119,
LeftAlt = 120,
RightAlt = 121,
BrowserBack = 122,
BrowserForward = 123,
BrowserRefresh = 124,
BrowserStop = 125,
BrowserSearch = 126,
BrowserFavorites = 127,
BrowserHome = 128,
VolumeMute = 129,
VolumeDown = 130,
VolumeUp = 131,
MediaNextTrack = 132,
MediaPreviousTrack = 133,
MediaStop = 134,
MediaPlayPause = 135,
LaunchMail = 136,
SelectMedia = 137,
LaunchApplication1 = 138,
LaunchApplication2 = 139,
OemSemicolon = 140,
Oem1 = 140,
OemPlus = 141,
OemComma = 142,
OemMinus = 143,
OemPeriod = 144,
OemQuestion = 145,
Oem2 = 145,
OemTilde = 146,
Oem3 = 146,
AbntC1 = 147,
AbntC2 = 148,
OemOpenBrackets = 149,
Oem4 = 149,
OemPipe = 150,
Oem5 = 150,
OemCloseBrackets = 151,
Oem6 = 151,
OemQuotes = 152,
Oem7 = 152,
Oem8 = 153,
OemBackslash = 154,
Oem102 = 154,
ImeProcessed = 155,
System = 156,
OemAttn = 157,
DbeAlphanumeric = 157,
OemFinish = 158,
DbeKatakana = 158,
DbeHiragana = 159,
OemCopy = 159,
DbeSbcsChar = 160,
OemAuto = 160,
DbeDbcsChar = 161,
OemEnlw = 161,
OemBackTab = 162,
DbeRoman = 162,
DbeNoRoman = 163,
Attn = 163,
CrSel = 164,
DbeEnterWordRegisterMode = 164,
ExSel = 165,
DbeEnterImeConfigureMode = 165,
EraseEof = 166,
DbeFlushString = 166,
Play = 167,
DbeCodeInput = 167,
DbeNoCodeInput = 168,
Zoom = 168,
NoName = 169,
DbeDetermineString = 169,
DbeEnterDialogConversionMode = 170,
Pa1 = 170,
OemClear = 171,
DeadCharProcessed = 172,
};
enum SystemDecorations {
SystemDecorationsNone = 0,
SystemDecorationsBorderOnly = 1,
@ -225,7 +430,7 @@ interface IAvnString : IUnknown
[uuid(e5aca675-02b7-4129-aa79-d6e417210bda)]
interface IAvnWindowBase : IUnknown
{
HRESULT Show();
HRESULT Show(bool activate);
HRESULT Hide();
HRESULT Close();
HRESULT Activate();
@ -468,7 +673,7 @@ interface IAvnMenuItem : IUnknown
{
HRESULT SetSubMenu(IAvnMenu* menu);
HRESULT SetTitle(char* utf8String);
HRESULT SetGesture(char* utf8String, AvnInputModifiers modifiers);
HRESULT SetGesture(AvnKey key, AvnInputModifiers modifiers);
HRESULT SetAction(IAvnPredicateCallback* predicate, IAvnActionCallback* callback);
HRESULT SetIsChecked(bool isChecked);
HRESULT SetToggleType(AvnMenuItemToggleType toggleType);

6
src/Avalonia.Themes.Default/CaptionButtons.xaml

@ -4,7 +4,7 @@
<Setter Property="MaxHeight" Value="30" />
<Setter Property="Template">
<ControlTemplate>
<StackPanel Spacing="2" Margin="0 0 7 0" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal">
<StackPanel Spacing="2" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Panel">
<Setter Property="Width" Value="45" />
@ -57,10 +57,14 @@
<Style Selector="CaptionButtons:maximized Panel#PART_RestoreButton Path">
<Setter Property="Data" Value="M2048 410h-410v-410h-1638v1638h410v410h1638v-1638zM1434 1434h-1229v-1229h1229v1229zM1843 1843h-1229v-205h1024v-1024h205v1229z" />
</Style>
<Style Selector="CaptionButtons Panel#PART_FullScreenButton Path">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="CaptionButtons Panel#PART_FullScreenButton Path">
<Setter Property="Data" Value="M2048 2048v-819h-205v469l-1493 -1493h469v-205h-819v819h205v-469l1493 1493h-469v205h819z" />
</Style>
<Style Selector="CaptionButtons:fullscreen Panel#PART_FullScreenButton Path">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="M205 1024h819v-819h-205v469l-674 -674l-145 145l674 674h-469v205zM1374 1229h469v-205h-819v819h205v-469l674 674l145 -145z" />
</Style>
<Style Selector="CaptionButtons:fullscreen Panel#PART_RestoreButton, CaptionButtons:fullscreen Panel#PART_MinimiseButton">

5
src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt

@ -1,3 +1,4 @@
Compat issues with assembly Avalonia.Themes.Fluent:
TypesMustExist : Type 'Avalonia.Themes.Fluent.FluentTheme' does not exist in the implementation but it does exist in the contract.
Total Issues: 1
CannotRemoveBaseTypeOrInterface : Type 'Avalonia.Themes.Fluent.FluentTheme' does not inherit from base type 'Avalonia.Styling.Styles' in the implementation but it does in the contract.
MembersMustExist : Member 'public void Avalonia.Themes.Fluent.FluentTheme..ctor()' does not exist in the implementation but it does exist in the contract.
Total Issues: 2

6
src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml

@ -3,7 +3,7 @@
<Setter Property="MaxHeight" Value="30" />
<Setter Property="Template">
<ControlTemplate>
<StackPanel Spacing="2" Margin="0 0 7 0" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal">
<StackPanel Spacing="2" VerticalAlignment="Stretch" TextBlock.FontSize="10" Orientation="Horizontal">
<StackPanel.Styles>
<Style Selector="Panel">
<Setter Property="Width" Value="45" />
@ -56,10 +56,14 @@
<Style Selector="CaptionButtons:maximized Panel#PART_RestoreButton Path">
<Setter Property="Data" Value="M2048 410h-410v-410h-1638v1638h410v410h1638v-1638zM1434 1434h-1229v-1229h1229v1229zM1843 1843h-1229v-205h1024v-1024h205v1229z" />
</Style>
<Style Selector="CaptionButtons Panel#PART_FullScreenButton Path">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="CaptionButtons Panel#PART_FullScreenButton Path">
<Setter Property="Data" Value="M2048 2048v-819h-205v469l-1493 -1493h469v-205h-819v819h205v-469l1493 1493h-469v205h819z" />
</Style>
<Style Selector="CaptionButtons:fullscreen Panel#PART_FullScreenButton Path">
<Setter Property="IsVisible" Value="True" />
<Setter Property="Data" Value="M205 1024h819v-819h-205v469l-674 -674l-145 145l674 674h-469v205zM1374 1229h469v-205h-819v819h205v-469l674 674l145 -145z" />
</Style>
<Style Selector="CaptionButtons:fullscreen Panel#PART_RestoreButton, CaptionButtons:fullscreen Panel#PART_MinimiseButton">

1
src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml

@ -39,6 +39,7 @@
<Setter Property="HorizontalAlignment" Value="Stretch" />
<Setter Property="TextBlock.FontSize" Value="{DynamicResource ContentControlFontSize}" />
<Setter Property="TextBlock.FontWeight" Value="Normal" />
<Setter Property="WindowManagerAddShadowHint" Value="False" />
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}"

2
src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml

@ -110,7 +110,7 @@
</Grid>
</Border>
<Popup Name="PART_Popup"
WindowManagerAddShadowHint="True"
WindowManagerAddShadowHint="False"
PlacementMode="Right"
HorizontalOffset="{StaticResource MenuFlyoutSubItemPopupHorizontalOffset}"
IsLightDismissEnabled="True"

114
src/Avalonia.Themes.Fluent/FluentTheme.cs

@ -0,0 +1,114 @@
using System;
using System.Collections.Generic;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Styling;
#nullable enable
namespace Avalonia.Themes.Fluent
{
public enum FluentThemeMode
{
Light,
Dark,
}
/// <summary>
/// Includes the fluent theme in an application.
/// </summary>
public class FluentTheme : IStyle, IResourceProvider
{
private readonly Uri _baseUri;
private IStyle[]? _loaded;
private bool _isLoading;
/// <summary>
/// Initializes a new instance of the <see cref="FluentTheme"/> class.
/// </summary>
/// <param name="baseUri">The base URL for the XAML context.</param>
public FluentTheme(Uri baseUri)
{
_baseUri = baseUri;
}
/// <summary>
/// Initializes a new instance of the <see cref="FluentTheme"/> class.
/// </summary>
/// <param name="serviceProvider">The XAML service provider.</param>
public FluentTheme(IServiceProvider serviceProvider)
{
_baseUri = ((IUriContext)serviceProvider.GetService(typeof(IUriContext))).BaseUri;
}
/// <summary>
/// Gets or sets the mode of the fluent theme (light, dark).
/// </summary>
public FluentThemeMode Mode { get; set; }
public IResourceHost? Owner => (Loaded as IResourceProvider)?.Owner;
/// <summary>
/// Gets the loaded style.
/// </summary>
public IStyle Loaded
{
get
{
if (_loaded == null)
{
_isLoading = true;
var loaded = (IStyle)AvaloniaXamlLoader.Load(GetUri(), _baseUri);
_loaded = new[] { loaded };
_isLoading = false;
}
return _loaded?[0]!;
}
}
bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false;
IReadOnlyList<IStyle> IStyle.Children => _loaded ?? Array.Empty<IStyle>();
public event EventHandler OwnerChanged
{
add
{
if (Loaded is IResourceProvider rp)
{
rp.OwnerChanged += value;
}
}
remove
{
if (Loaded is IResourceProvider rp)
{
rp.OwnerChanged -= value;
}
}
}
public SelectorMatchResult TryAttach(IStyleable target, IStyleHost? host) => Loaded.TryAttach(target, host);
public bool TryGetResource(object key, out object? value)
{
if (!_isLoading && Loaded is IResourceProvider p)
{
return p.TryGetResource(key, out value);
}
value = null;
return false;
}
void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner);
void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner);
private Uri GetUri() => Mode switch
{
FluentThemeMode.Dark => new Uri("avares://Avalonia.Themes.Fluent/FluentDark.xaml", UriKind.Absolute),
_ => new Uri("avares://Avalonia.Themes.Fluent/FluentLight.xaml", UriKind.Absolute),
};
}
}

3
src/Avalonia.Themes.Fluent/Properties/AssemblyInfo.cs

@ -0,0 +1,3 @@
using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Themes.Fluent")]

1
src/Avalonia.Visuals/Rendering/DeferredRenderer.cs

@ -607,6 +607,7 @@ namespace Avalonia.Rendering
private bool? UpdateScene()
{
Dispatcher.UIThread.VerifyAccess();
using var noPump = NonPumpingLockHelper.Use();
lock (_sceneLock)
{
if (_disposed)

2
src/Avalonia.Visuals/Visual.cs

@ -485,7 +485,7 @@ namespace Avalonia
BindingPriority.LocalValue);
}
protected override sealed void LogBindingError(AvaloniaProperty property, Exception e)
protected internal sealed override void LogBindingError(AvaloniaProperty property, Exception e)
{
// Don't log a binding error unless the control is attached to a logical or visual tree.
// In theory this should only need to check for logical tree attachment, but in practise

2
src/Avalonia.X11/X11Window.cs

@ -823,7 +823,7 @@ namespace Avalonia.X11
XSetTransientForHint(_x11.Display, _handle, parent.Handle.Handle);
}
public void Show()
public void Show(bool activate)
{
_wasMappedAtLeastOnce = true;
XMapWindow(_x11.Display, _handle);

23
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs

@ -72,16 +72,16 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
v.Property is AvaloniaSyntheticCompiledBindingProperty prop
&& prop.Name == SyntheticCompiledBindingPropertyName.ElementName);
var sourceProperty = syntheticCompiledBindingProperties
.FirstOrDefault(v =>
v.Property is AvaloniaSyntheticCompiledBindingProperty prop
&& prop.Name == SyntheticCompiledBindingPropertyName.Source);
var relativeSourceProperty = syntheticCompiledBindingProperties
.FirstOrDefault(v =>
v.Property is AvaloniaSyntheticCompiledBindingProperty prop
&& prop.Name == SyntheticCompiledBindingPropertyName.RelativeSource);
var sourceProperty = binding.Children.OfType<XamlAstXamlPropertyValueNode>()
.FirstOrDefault(v =>
v.Property is XamlAstClrProperty prop
&& prop.Name == "Source");
if (elementNameProperty?.Values[0] is XamlAstTextNode elementName)
{
convertedNode = new BindingExpressionGrammar.NameNode { Name = elementName.Text };
@ -91,14 +91,9 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
throw new XamlParseException($"Invalid ElementName '{elementNameProperty.Values[0]}'.", elementNameProperty.Values[0]);
}
if (sourceProperty?.Values[0] != null)
if (sourceProperty != null && convertedNode != null)
{
if (convertedNode != null)
{
throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
}
convertedNode = new RawSourceBindingExpressionNode(sourceProperty?.Values[0]);
throw new XamlParseException("Only one of ElementName, Source, or RelativeSource specified as a binding source. Only one property is allowed.", binding);
}
if (GetRelativeSourceObjectFromAssignment(
@ -223,10 +218,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
binding.Children.Remove(elementNameProperty);
}
if (sourceProperty != null)
{
binding.Children.Remove(sourceProperty);
}
if (relativeSourceProperty != null)
{
binding.Children.Remove(relativeSourceProperty);

100
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs

@ -1,8 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using XamlX;
using XamlX.Ast;
using XamlX.Transform;
using XamlX.TypeSystem;
@ -15,14 +13,102 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
if (node is XamlAstConstructableObjectNode binding && binding.Type.GetClrType().Equals(context.GetAvaloniaTypes().CompiledBindingExtension))
{
IXamlType startType;
var parentDataContextNode = context.ParentNodes().OfType<AvaloniaXamlIlDataContextTypeMetadataNode>().FirstOrDefault();
if (parentDataContextNode is null)
IXamlType startType = null;
var sourceProperty = binding.Children.OfType<XamlPropertyAssignmentNode>().FirstOrDefault(c => c.Property.Name == "Source");
if ((sourceProperty?.Values.Count ?? 0) == 1)
{
throw new XamlX.XamlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", binding);
var sourceValue = sourceProperty.Values[0];
switch (sourceValue)
{
case XamlAstTextNode textNode:
startType = textNode.Type?.GetClrType();
break;
case XamlMarkupExtensionNode extension:
startType = extension.Type?.GetClrType();
//let's try to infer StaticResource type from parent resources in xaml
if (extension.Value.Type.GetClrType().FullName == "Avalonia.Markup.Xaml.MarkupExtensions.StaticResourceExtension" &&
extension.Value is XamlAstConstructableObjectNode cn &&
cn.Arguments.Count == 1 && cn.Arguments[0] is XamlAstTextNode keyNode)
{
bool matchProperty(IXamlAstNode node, IXamlType styledElementType, string propertyName)
{
return (node is XamlPropertyAssignmentNode p &&
p.Property.DeclaringType == styledElementType && p.Property.Name == propertyName)
||
(node is XamlManipulationGroupNode m && m.Children.Count > 0 &&
m.Children[0] is XamlPropertyAssignmentNode pm &&
pm.Property.DeclaringType == styledElementType && pm.Property.Name == propertyName);
}
string getResourceValue_xKey(XamlPropertyAssignmentNode node)
=> node.Values.Count == 2 && node.Values[0] is XamlAstTextNode t ? t.Text : "";
IXamlType getResourceValue_Type(XamlPropertyAssignmentNode node, IXamlType xamlType)
=> node.Values.Count == 2 ? node.Values[1].Type.GetClrType() : xamlType;
IEnumerable<XamlPropertyAssignmentNode> getResourceValues(IXamlAstNode node)
{
if (node is XamlPropertyAssignmentNode propertyNode)
{
if (propertyNode.Values.Count == 1 &&
propertyNode.Values[0] is XamlAstConstructableObjectNode obj &&
obj.Type.GetClrType().FullName == "Avalonia.Controls.ResourceDictionary")
{
foreach (var r in obj.Children.SelectMany(c => getResourceValues(c)))
{
yield return r;
}
}
else
{
yield return propertyNode;
}
}
else if (node is XamlManipulationGroupNode m)
{
foreach (var r in m.Children.OfType<XamlPropertyAssignmentNode>())
{
yield return r;
}
}
}
string key = keyNode.Text;
var styledElement = context.GetAvaloniaTypes().StyledElement;
var resource = context.ParentNodes()
.OfType<XamlAstConstructableObjectNode>()
.Where(o => styledElement.IsAssignableFrom(o.Type.GetClrType()))
.Select(o => o.Children.FirstOrDefault(p => matchProperty(p, styledElement, "Resources")))
.Where(r => r != null)
.SelectMany(r => getResourceValues(r))
.FirstOrDefault(r => getResourceValue_xKey(r) == key);
if (resource != null)
{
startType = getResourceValue_Type(resource, startType);
}
}
break;
case XamlStaticExtensionNode staticExtension:
startType = staticExtension.Type?.GetClrType();
break;
}
}
startType = parentDataContextNode.DataContextType;
if (startType == null)
{
var parentDataContextNode = context.ParentNodes().OfType<AvaloniaXamlIlDataContextTypeMetadataNode>().FirstOrDefault();
if (parentDataContextNode is null)
{
throw new XamlX.XamlParseException("Cannot parse a compiled binding without an explicit x:DataType directive to give a starting data type for bindings.", binding);
}
startType = parentDataContextNode.DataContextType;
}
XamlIlBindingPathHelper.UpdateCompiledBindingExtension(context, binding, startType);
}

8
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs

@ -25,11 +25,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
return new AvaloniaSyntheticCompiledBindingProperty(node,
SyntheticCompiledBindingPropertyName.RelativeSource);
}
else if (prop.Name == "Source")
{
return new AvaloniaSyntheticCompiledBindingProperty(node,
SyntheticCompiledBindingPropertyName.Source);
}
}
return node;
@ -39,8 +34,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
enum SyntheticCompiledBindingPropertyName
{
ElementName,
RelativeSource,
Source
RelativeSource
}
class AvaloniaSyntheticCompiledBindingProperty : XamlAstNode, IXamlAstPropertyReference

5
src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt

@ -1,4 +1 @@
Compat issues with assembly Avalonia.Markup.Xaml:
MembersMustExist : Member 'public Avalonia.Data.Binding Avalonia.Markup.Xaml.Templates.TreeDataTemplate.ItemsSource.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Markup.Xaml.Templates.TreeDataTemplate.ItemsSource.set(Avalonia.Data.Binding)' does not exist in the implementation but it does exist in the contract.
Total Issues: 2
Total Issues: 0

10
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs

@ -32,6 +32,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
Mode = Mode,
Priority = Priority,
StringFormat = StringFormat,
Source = Source,
DefaultAnchor = new WeakReference(GetDefaultAnchor(provider))
};
}
@ -52,6 +53,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
protected override ExpressionObserver CreateExpressionObserver(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor, bool enableDataValidation)
{
if (Source != null)
{
return CreateSourceObserver(
Source,
Path.BuildExpression(enableDataValidation));
}
if (Path.RawSource != null)
{
return CreateSourceObserver(
@ -77,5 +85,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
[ConstructorArgument("path")]
public CompiledBindingPath Path { get; set; }
public object Source { get; set; }
}
}

41
src/Windows/Avalonia.Win32/ClipboardImpl.cs

@ -12,10 +12,17 @@ namespace Avalonia.Win32
{
internal class ClipboardImpl : IClipboard
{
private const int OleRetryCount = 10;
private const int OleRetryDelay = 100;
private async Task<IDisposable> OpenClipboard()
{
var i = OleRetryCount;
while (!UnmanagedMethods.OpenClipboard(IntPtr.Zero))
{
if (--i == 0)
throw new TimeoutException("Timeout opening clipboard.");
await Task.Delay(100);
}
@ -72,20 +79,32 @@ namespace Avalonia.Win32
{
Dispatcher.UIThread.VerifyAccess();
var wrapper = new DataObject(data);
var i = OleRetryCount;
while (true)
{
if (UnmanagedMethods.OleSetClipboard(wrapper) == 0)
var hr = UnmanagedMethods.OleSetClipboard(wrapper);
if (hr == 0)
break;
await Task.Delay(100);
if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
}
}
public async Task<string[]> GetFormatsAsync()
{
Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;
while (true)
{
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
if (hr == 0)
{
var wrapper = new OleDataObject(dataObject);
var formats = wrapper.GetDataFormats().ToArray();
@ -93,16 +112,23 @@ namespace Avalonia.Win32
return formats;
}
await Task.Delay(100);
if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
}
}
public async Task<object> GetDataAsync(string format)
{
Dispatcher.UIThread.VerifyAccess();
var i = OleRetryCount;
while (true)
{
if (UnmanagedMethods.OleGetClipboard(out var dataObject) == 0)
var hr = UnmanagedMethods.OleGetClipboard(out var dataObject);
if (hr == 0)
{
var wrapper = new OleDataObject(dataObject);
var rv = wrapper.Get(format);
@ -110,7 +136,10 @@ namespace Avalonia.Win32
return rv;
}
await Task.Delay(100);
if (--i == 0)
Marshal.ThrowExceptionForHR(hr);
await Task.Delay(OleRetryDelay);
}
}
}

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

@ -931,8 +931,8 @@ namespace Avalonia.Win32.Interop
[DllImport("user32.dll", EntryPoint = "MapVirtualKeyW")]
public static extern uint MapVirtualKey(uint uCode, uint uMapType);
[DllImport("user32.dll", EntryPoint = "GetMessageW")]
public static extern sbyte GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("user32.dll", EntryPoint = "GetMessageW", SetLastError = true)]
public static extern int GetMessage(out MSG lpMsg, IntPtr hWnd, uint wMsgFilterMin, uint wMsgFilterMax);
[DllImport("user32.dll")]
public static extern int GetMessageTime();

52
src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs

@ -0,0 +1,52 @@
using System;
using System.Runtime.ConstrainedExecution;
using System.Threading;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
internal class NonPumpingSyncContext : SynchronizationContext, IDisposable
{
private readonly SynchronizationContext _inner;
private NonPumpingSyncContext(SynchronizationContext inner)
{
_inner = inner;
SetWaitNotificationRequired();
SetSynchronizationContext(this);
}
public override void Post(SendOrPostCallback d, object state) => _inner.Post(d, state);
public override void Send(SendOrPostCallback d, object state) => _inner.Send(d, state);
[PrePrepareMethod]
public override int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return UnmanagedMethods.WaitForMultipleObjectsEx(waitHandles.Length, waitHandles, waitAll,
millisecondsTimeout, false);
}
public void Dispose() => SetSynchronizationContext(_inner);
public static IDisposable Use()
{
var current = Current;
if (current == null)
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
return null;
}
if (current is NonPumpingSyncContext)
return null;
return new NonPumpingSyncContext(current);
}
internal class HelperImpl : NonPumpingLockHelper.IHelperImpl
{
IDisposable NonPumpingLockHelper.IHelperImpl.Use() => NonPumpingSyncContext.Use();
}
}
}

15
src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs

@ -1,15 +0,0 @@
using System;
using Avalonia.Threading;
using Avalonia.Win32.Interop;
namespace Avalonia.Win32
{
internal class NonPumpingWaitProvider : AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider
{
public int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)
{
return UnmanagedMethods.WaitForMultipleObjectsEx(waitHandles.Length, waitHandles, waitAll,
millisecondsTimeout, false);
}
}
}

3
src/Windows/Avalonia.Win32/PopupImpl.cs

@ -17,8 +17,9 @@ namespace Avalonia.Win32
[ThreadStatic]
private static IntPtr s_parentHandle;
public override void Show()
public override void Show(bool activate)
{
// Popups are always shown non-activated.
UnmanagedMethods.ShowWindow(Handle.Handle, UnmanagedMethods.ShowWindowCommand.ShowNoActivate);
// We need to steal focus if it's held by a child window of our toplevel window

32
src/Windows/Avalonia.Win32/Win32Platform.cs

@ -16,6 +16,7 @@ using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
@ -110,7 +111,7 @@ namespace Avalonia.Win32
.Bind<IWindowingPlatform>().ToConstant(s_instance)
.Bind<PlatformHotkeyConfiguration>().ToSingleton<PlatformHotkeyConfiguration>()
.Bind<IPlatformIconLoader>().ToConstant(s_instance)
.Bind<AvaloniaSynchronizationContext.INonPumpingPlatformWaitProvider>().ToConstant(new NonPumpingWaitProvider())
.Bind<NonPumpingLockHelper.IHelperImpl>().ToConstant(new NonPumpingSyncContext.HelperImpl())
.Bind<IMountedVolumeInfoProvider>().ToConstant(new WindowsMountedVolumeInfoProvider());
Win32GlManager.Initialize();
@ -129,21 +130,34 @@ namespace Avalonia.Win32
public void ProcessMessage()
{
UnmanagedMethods.MSG msg;
UnmanagedMethods.GetMessage(out msg, IntPtr.Zero, 0, 0);
UnmanagedMethods.TranslateMessage(ref msg);
UnmanagedMethods.DispatchMessage(ref msg);
if (UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0) > -1)
{
UnmanagedMethods.TranslateMessage(ref msg);
UnmanagedMethods.DispatchMessage(ref msg);
}
else
{
Logging.Logger.TryGet(Logging.LogEventLevel.Error, Logging.LogArea.Win32Platform)
?.Log(this, "Unmanaged error in {0}. Error Code: {1}", nameof(ProcessMessage), Marshal.GetLastWin32Error());
}
}
public void RunLoop(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
var result = 0;
while (!cancellationToken.IsCancellationRequested
&& (result = UnmanagedMethods.GetMessage(out var msg, IntPtr.Zero, 0, 0)) > 0)
{
UnmanagedMethods.MSG msg;
UnmanagedMethods.GetMessage(out msg, IntPtr.Zero, 0, 0);
UnmanagedMethods.TranslateMessage(ref msg);
UnmanagedMethods.DispatchMessage(ref msg);
}
if (result < 0)
{
Logging.Logger.TryGet(Logging.LogEventLevel.Error, Logging.LogArea.Win32Platform)
?.Log(this, "Unmanaged error in {0}. Error Code: {1}", nameof(RunLoop), Marshal.GetLastWin32Error());
}
}
public IDisposable StartTimer(DispatcherPriority priority, TimeSpan interval, Action callback)
@ -229,7 +243,7 @@ namespace Avalonia.Win32
public IWindowImpl CreateEmbeddableWindow()
{
var embedded = new EmbeddedWindowImpl();
embedded.Show();
embedded.Show(true);
return embedded;
}

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

@ -348,6 +348,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_PAINT:
{
using(NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
if (BeginPaint(_hwnd, out PAINTSTRUCT ps) != IntPtr.Zero)
@ -365,6 +366,7 @@ namespace Avalonia.Win32
case WindowsMessage.WM_SIZE:
{
using(NonPumpingSyncContext.Use())
using (_rendererLock.Lock())
{
// Do nothing here, just block until the pending frame render is completed on the render thread

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

Loading…
Cancel
Save