Browse Source

Merge branch 'master' into linux-ime-cjk

pull/5258/head
Nikita Tsukanov 5 years ago
committed by GitHub
parent
commit
91828f2621
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 31
      .github/ISSUE_TEMPLATE/bug_report.md
  2. 20
      .github/ISSUE_TEMPLATE/feature_request.md
  3. 6
      azure-pipelines.yml
  4. 2
      build/ApiDiff.props
  5. 1020
      native/Avalonia.Native/inc/key.h
  6. 12
      native/Avalonia.Native/src/OSX/Avalonia.Native.OSX.xcodeproj/project.pbxproj
  7. 7
      native/Avalonia.Native/src/OSX/KeyTransform.h
  8. 151
      native/Avalonia.Native/src/OSX/KeyTransform.mm
  9. 2
      native/Avalonia.Native/src/OSX/menu.h
  10. 65
      native/Avalonia.Native/src/OSX/menu.mm
  11. 8
      native/Avalonia.Native/src/OSX/window.mm
  12. 11
      readme.md
  13. 3
      samples/ControlCatalog.NetCore/Program.cs
  14. 4
      src/Avalonia.Base/ApiCompatBaseline.txt
  15. 24
      src/Avalonia.Base/AvaloniaProperty.cs
  16. 8
      src/Avalonia.Base/AvaloniaPropertyMetadata.cs
  17. 6
      src/Avalonia.Base/AvaloniaProperty`1.cs
  18. 6
      src/Avalonia.Base/DirectPropertyBase.cs
  19. 4
      src/Avalonia.Base/DirectPropertyMetadata`1.cs
  20. 5
      src/Avalonia.Base/Logging/LogArea.cs
  21. 2
      src/Avalonia.Base/Properties/AssemblyInfo.cs
  22. 4
      src/Avalonia.Base/StyledPropertyMetadata`1.cs
  23. 25
      src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
  24. 14
      src/Avalonia.Base/Utilities/NonPumpingLockHelper.cs
  25. 5
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  26. 21
      src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs
  27. 29
      src/Avalonia.Controls.DataGrid/Themes/Default.xaml
  28. 26
      src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs
  29. 26
      src/Avalonia.Controls/ApiCompatBaseline.txt
  30. 4
      src/Avalonia.Controls/Button.cs
  31. 10
      src/Avalonia.Controls/ContextMenu.cs
  32. 26
      src/Avalonia.Controls/HotkeyManager.cs
  33. 4
      src/Avalonia.Controls/MenuItem.cs
  34. 2
      src/Avalonia.Controls/NativeMenuItem.cs
  35. 4
      src/Avalonia.Controls/Platform/IWindowBaseImpl.cs
  36. 5
      src/Avalonia.Controls/TextBox.cs
  37. 20
      src/Avalonia.Controls/Window.cs
  38. 2
      src/Avalonia.Controls/WindowBase.cs
  39. 2
      src/Avalonia.DesignerSupport/Remote/PreviewerWindowImpl.cs
  40. 2
      src/Avalonia.DesignerSupport/Remote/Stubs.cs
  41. 3
      src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml
  42. 1
      src/Avalonia.Dialogs/ApiCompatBaseline.txt
  43. 2
      src/Avalonia.FreeDesktop/DBusHelper.cs
  44. 7
      src/Avalonia.Headless/HeadlessWindowImpl.cs
  45. 4
      src/Avalonia.Input/ApiCompatBaseline.txt
  46. 36
      src/Avalonia.Input/ICommandSource.cs
  47. 4
      src/Avalonia.Native/IAvnMenuItem.cs
  48. 152
      src/Avalonia.Native/OsxUnicodeKeys.cs
  49. 4
      src/Avalonia.Native/PopupImpl.cs
  50. 4
      src/Avalonia.Native/WindowImplBase.cs
  51. 211
      src/Avalonia.Native/avn.idl
  52. 3
      src/Avalonia.Styling/ApiCompatBaseline.txt
  53. 6
      src/Avalonia.Themes.Default/CaptionButtons.xaml
  54. 4
      src/Avalonia.Themes.Fluent/ApiCompatBaseline.txt
  55. 6
      src/Avalonia.Themes.Fluent/Controls/CaptionButtons.xaml
  56. 1
      src/Avalonia.Themes.Fluent/Controls/ContextMenu.xaml
  57. 2
      src/Avalonia.Themes.Fluent/Controls/MenuItem.xaml
  58. 5
      src/Avalonia.Visuals/ApiCompatBaseline.txt
  59. 1
      src/Avalonia.Visuals/Rendering/DeferredRenderer.cs
  60. 2
      src/Avalonia.Visuals/Visual.cs
  61. 2
      src/Avalonia.X11/X11Window.cs
  62. 23
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathParser.cs
  63. 100
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlBindingPathTransformer.cs
  64. 8
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlTransformSyntheticCompiledBindingMembers.cs
  65. 4
      src/Markup/Avalonia.Markup.Xaml/ApiCompatBaseline.txt
  66. 10
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindingExtension.cs
  67. 4
      src/Windows/Avalonia.Win32/Interop/UnmanagedMethods.cs
  68. 52
      src/Windows/Avalonia.Win32/NonPumpingSyncContext.cs
  69. 15
      src/Windows/Avalonia.Win32/NonPumpingWaitProvider.cs
  70. 3
      src/Windows/Avalonia.Win32/PopupImpl.cs
  71. 8
      src/Windows/Avalonia.Win32/Win32GlManager.cs
  72. 37
      src/Windows/Avalonia.Win32/Win32Platform.cs
  73. 2
      src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
  74. 14
      src/Windows/Avalonia.Win32/WindowImpl.cs
  75. 22
      tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs
  76. 16
      tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs
  77. 141
      tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs
  78. 2
      tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs
  79. 121
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  80. 2
      tests/Avalonia.UnitTests/MockWindowingPlatform.cs

31
.github/ISSUE_TEMPLATE/bug_report.md

@ -0,0 +1,31 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Go to '...'
2. Click on '....'
3. Scroll down to '....'
4. See error
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Desktop (please complete the following information):**
- OS: [e.g. Windows, Mac, Linux (State distribution)]
- Version [e.g. 0.10.0-rc1 or 0.9.12]
**Additional context**
Add any other context about the problem here.

20
.github/ISSUE_TEMPLATE/feature_request.md

@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

6
azure-pipelines.yml

@ -27,7 +27,7 @@ jobs:
variables:
SolutionDir: '$(Build.SourcesDirectory)'
pool:
vmImage: 'macOS-10.14'
vmImage: 'macOS-10.15'
steps:
- task: UseDotNet@2
displayName: 'Use .NET Core SDK 3.1.401'
@ -51,10 +51,10 @@ jobs:
inputs:
actions: 'build'
scheme: ''
sdk: 'macosx10.14'
sdk: 'macosx11.1'
configuration: 'Release'
xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
xcodeVersion: '10' # Options: 8, 9, default, specifyPath
xcodeVersion: '12' # Options: 8, 9, default, specifyPath
args: '-derivedDataPath ./'
- task: CmdLine@2

2
build/ApiDiff.props

@ -1,6 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ApiContractPackageVersion>0.10.0-preview6</ApiContractPackageVersion>
<ApiContractPackageVersion>0.10.0-rc1</ApiContractPackageVersion>
<NugetPackageName Condition="'$(PackageId)' != ''">$(PackageId)</NugetPackageName>
<NugetPackageName Condition="'$(PackageId)' == ''">Avalonia</NugetPackageName>
</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();

11
readme.md

@ -10,6 +10,8 @@ Avalonia is a cross-platform XAML-based UI framework providing a flexible stylin
<img src="https://user-images.githubusercontent.com/6759207/84751662-7c79da00-afc5-11ea-8780-dda28db70b76.png" width="700" />
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
> **Note:** The UI theme you see in the picture above is still work-in-progress and will be available in the upcoming Avalonia 0.10.0 release. However, you can connect to our nightly build feed and install latest pre-release versions of Avalonia NuGet packages, if you are willing to help out with the development and testing. See [Using nightly build feed](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) for more info.
To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
@ -31,15 +33,22 @@ Install-Package Avalonia.Desktop
Examples of UIs built with Avalonia
![image](https://user-images.githubusercontent.com/4672627/84707589-5b69a880-af35-11ea-87a6-7ad57a31d314.png)
([Synfonia](https://github.com/jmacato/Synfonia))
![image](https://user-images.githubusercontent.com/4672627/85069644-d8419000-b18a-11ea-8732-be9055bb61fd.PNG)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
![image](https://user-images.githubusercontent.com/4672627/85069659-dc6dad80-b18a-11ea-8375-39ef95315b5c.PNG)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
![image](https://user-images.githubusercontent.com/4672627/84708947-c3b98980-af37-11ea-8c9d-503334615bbf.png)
([Xaml Control Gallery](https://github.com/AvaloniaUI/xamlcontrolsgallery))
## JetBrains Rider
If you need to develop Avalonia app with JetBrains Rider you can use latest Rider [preview builds](https://www.jetbrains.com/rider/nextversion/).
[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
## Bleeding Edge Builds

3
samples/ControlCatalog.NetCore/Program.cs

@ -114,8 +114,7 @@ namespace ControlCatalog.NetCore
})
.With(new Win32PlatformOptions
{
EnableMultitouch = true,
AllowEglInitialization = true
EnableMultitouch = true
})
.UseSkia()
.UseManagedSystemDialogs()

4
src/Avalonia.Base/ApiCompatBaseline.txt

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

24
src/Avalonia.Base/AvaloniaProperty.cs

@ -17,9 +17,9 @@ namespace Avalonia
public static readonly object UnsetValue = new UnsetValueType();
private static int s_nextId;
private readonly PropertyMetadata _defaultMetadata;
private readonly Dictionary<Type, PropertyMetadata> _metadata;
private readonly Dictionary<Type, PropertyMetadata> _metadataCache = new Dictionary<Type, PropertyMetadata>();
private readonly AvaloniaPropertyMetadata _defaultMetadata;
private readonly Dictionary<Type, AvaloniaPropertyMetadata> _metadata;
private readonly Dictionary<Type, AvaloniaPropertyMetadata> _metadataCache = new Dictionary<Type, AvaloniaPropertyMetadata>();
private bool _hasMetadataOverrides;
@ -35,7 +35,7 @@ namespace Avalonia
string name,
Type valueType,
Type ownerType,
PropertyMetadata metadata,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool> notifying = null)
{
Contract.Requires<ArgumentNullException>(name != null);
@ -48,7 +48,7 @@ namespace Avalonia
throw new ArgumentException("'name' may not contain periods.");
}
_metadata = new Dictionary<Type, PropertyMetadata>();
_metadata = new Dictionary<Type, AvaloniaPropertyMetadata>();
Name = name;
PropertyType = valueType;
@ -69,12 +69,12 @@ namespace Avalonia
protected AvaloniaProperty(
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
{
Contract.Requires<ArgumentNullException>(source != null);
Contract.Requires<ArgumentNullException>(ownerType != null);
_metadata = new Dictionary<Type, PropertyMetadata>();
_metadata = new Dictionary<Type, AvaloniaPropertyMetadata>();
Name = source.Name;
PropertyType = source.PropertyType;
@ -419,7 +419,7 @@ namespace Avalonia
/// <returns>
/// The property metadata.
/// </returns>
public PropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
public AvaloniaPropertyMetadata GetMetadata<T>() where T : IAvaloniaObject
{
return GetMetadata(typeof(T));
}
@ -432,7 +432,7 @@ namespace Avalonia
/// The property metadata.
/// </returns>
///
public PropertyMetadata GetMetadata(Type type)
public AvaloniaPropertyMetadata GetMetadata(Type type)
{
if (!_hasMetadataOverrides)
{
@ -521,7 +521,7 @@ namespace Avalonia
/// </summary>
/// <param name="type">The type.</param>
/// <param name="metadata">The metadata.</param>
protected void OverrideMetadata(Type type, PropertyMetadata metadata)
protected void OverrideMetadata(Type type, AvaloniaPropertyMetadata metadata)
{
Contract.Requires<ArgumentNullException>(type != null);
Contract.Requires<ArgumentNullException>(metadata != null);
@ -542,14 +542,14 @@ namespace Avalonia
protected abstract IObservable<AvaloniaPropertyChangedEventArgs> GetChanged();
private PropertyMetadata GetMetadataWithOverrides(Type type)
private AvaloniaPropertyMetadata GetMetadataWithOverrides(Type type)
{
if (type is null)
{
throw new ArgumentNullException(nameof(type));
}
if (_metadataCache.TryGetValue(type, out PropertyMetadata result))
if (_metadataCache.TryGetValue(type, out AvaloniaPropertyMetadata result))
{
return result;
}

8
src/Avalonia.Base/PropertyMetadata.cs → src/Avalonia.Base/AvaloniaPropertyMetadata.cs

@ -5,15 +5,15 @@ namespace Avalonia
/// <summary>
/// Base class for avalonia property metadata.
/// </summary>
public class PropertyMetadata
public class AvaloniaPropertyMetadata
{
private BindingMode _defaultBindingMode;
/// <summary>
/// Initializes a new instance of the <see cref="PropertyMetadata"/> class.
/// Initializes a new instance of the <see cref="AvaloniaPropertyMetadata"/> class.
/// </summary>
/// <param name="defaultBindingMode">The default binding mode.</param>
public PropertyMetadata(
public AvaloniaPropertyMetadata(
BindingMode defaultBindingMode = BindingMode.Default)
{
_defaultBindingMode = defaultBindingMode;
@ -37,7 +37,7 @@ namespace Avalonia
/// <param name="baseMetadata">The base metadata to merge.</param>
/// <param name="property">The property to which the metadata is being applied.</param>
public virtual void Merge(
PropertyMetadata baseMetadata,
AvaloniaPropertyMetadata baseMetadata,
AvaloniaProperty property)
{
if (_defaultBindingMode == BindingMode.Default)

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

@ -23,7 +23,7 @@ namespace Avalonia
protected AvaloniaProperty(
string name,
Type ownerType,
PropertyMetadata metadata,
AvaloniaPropertyMetadata metadata,
Action<IAvaloniaObject, bool> notifying = null)
: base(name, typeof(TValue), ownerType, metadata, notifying)
{
@ -40,7 +40,7 @@ namespace Avalonia
protected AvaloniaProperty(
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
: this(source as AvaloniaProperty<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
@ -54,7 +54,7 @@ namespace Avalonia
protected AvaloniaProperty(
AvaloniaProperty<TValue> source,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
: base(source, ownerType, metadata)
{
_changed = source._changed;

6
src/Avalonia.Base/DirectPropertyBase.cs

@ -26,7 +26,7 @@ namespace Avalonia
protected DirectPropertyBase(
string name,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
: base(name, ownerType, metadata)
{
}
@ -41,7 +41,7 @@ namespace Avalonia
protected DirectPropertyBase(
AvaloniaProperty source,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
: this(source as DirectPropertyBase<TValue> ?? throw new InvalidOperationException(), ownerType, metadata)
{
}
@ -55,7 +55,7 @@ namespace Avalonia
protected DirectPropertyBase(
DirectPropertyBase<TValue> source,
Type ownerType,
PropertyMetadata metadata)
AvaloniaPropertyMetadata metadata)
: base(source, ownerType, metadata)
{
}

4
src/Avalonia.Base/DirectPropertyMetadata`1.cs

@ -5,7 +5,7 @@ namespace Avalonia
/// <summary>
/// Metadata for direct avalonia properties.
/// </summary>
public class DirectPropertyMetadata<TValue> : PropertyMetadata, IDirectPropertyMetadata
public class DirectPropertyMetadata<TValue> : AvaloniaPropertyMetadata, IDirectPropertyMetadata
{
/// <summary>
/// Initializes a new instance of the <see cref="StyledPropertyMetadata{TValue}"/> class.
@ -47,7 +47,7 @@ namespace Avalonia
object IDirectPropertyMetadata.UnsetValue => UnsetValue;
/// <inheritdoc/>
public override void Merge(PropertyMetadata baseMetadata, AvaloniaProperty property)
public override void Merge(AvaloniaPropertyMetadata baseMetadata, AvaloniaProperty property)
{
base.Merge(baseMetadata, property);

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

4
src/Avalonia.Base/StyledPropertyMetadata`1.cs

@ -6,7 +6,7 @@ namespace Avalonia
/// <summary>
/// Metadata for styled avalonia properties.
/// </summary>
public class StyledPropertyMetadata<TValue> : PropertyMetadata, IStyledPropertyMetadata
public class StyledPropertyMetadata<TValue> : AvaloniaPropertyMetadata, IStyledPropertyMetadata
{
private Optional<TValue> _defaultValue;
@ -39,7 +39,7 @@ namespace Avalonia
object IStyledPropertyMetadata.DefaultValue => DefaultValue;
/// <inheritdoc/>
public override void Merge(PropertyMetadata baseMetadata, AvaloniaProperty property)
public override void Merge(AvaloniaPropertyMetadata baseMetadata, AvaloniaProperty property)
{
base.Merge(baseMetadata, property);

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();
}
}

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

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

21
src/Avalonia.Controls.DataGrid/Primitives/DataGridRowsPresenter.cs

@ -22,6 +22,22 @@ namespace Avalonia.Controls.Primitives
}
private double _measureHeightOffset = 0;
private double _effectiveViewPortHeight = 0;
public DataGridRowsPresenter()
{
EffectiveViewportChanged += OnEffectiveViewportChanged;
}
private void OnEffectiveViewportChanged(object sender, Layout.EffectiveViewportChangedEventArgs e)
{
if (_effectiveViewPortHeight != e.EffectiveViewport.Height)
{
_effectiveViewPortHeight = e.EffectiveViewport.Height;
InvalidateMeasure();
}
}
private double CalculateEstimatedAvailableHeight(Size availableSize)
{
if(!Double.IsPositiveInfinity(availableSize.Height))
@ -108,6 +124,11 @@ namespace Avalonia.Controls.Primitives
/// </returns>
protected override Size MeasureOverride(Size availableSize)
{
if (double.IsInfinity(availableSize.Height))
{
availableSize = availableSize.WithHeight(_effectiveViewPortHeight);
}
if (availableSize.Height == 0 || OwningGrid == null)
{
return base.MeasureOverride(availableSize);

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>

26
src/Avalonia.Controls.DataGrid/Utils/ReflectionHelper.cs

@ -352,19 +352,37 @@ namespace Avalonia.Controls.Utils
return null;
}
PropertyInfo indexer = null;
string stringIndex = propertyPath.Substring(1, propertyPath.Length - 2);
indexer = FindIndexerInMembers(type.GetDefaultMembers(), stringIndex, out index);
var indexer = FindIndexerInMembers(type.GetDefaultMembers(), stringIndex, out index);
if (indexer != null)
{
// We found the indexer, so return it.
return indexer;
}
if (typeof(IList).IsAssignableFrom(type))
var elementType = type.GetElementType();
if (elementType == null)
{
var genericArguments = type.GetGenericArguments();
if (genericArguments.Length == 1)
{
elementType = genericArguments[0];
}
}
if (elementType != null)
{
// If the object is of type IList, try to use its default indexer.
indexer = FindIndexerInMembers(typeof(IList).GetDefaultMembers(), stringIndex, out index);
if (typeof(IList<>).MakeGenericType(elementType) is Type genericList
&& genericList.IsAssignableFrom(type))
{
indexer = FindIndexerInMembers(genericList.GetDefaultMembers(), stringIndex, out index);
}
if (typeof(IReadOnlyList<>).MakeGenericType(elementType) is Type genericReadOnlyList
&& genericReadOnlyList.IsAssignableFrom(type))
{
indexer = FindIndexerInMembers(genericReadOnlyList.GetDefaultMembers(), stringIndex, out index);
}
}
return indexer;

26
src/Avalonia.Controls/ApiCompatBaseline.txt

@ -1,26 +0,0 @@
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

4
src/Avalonia.Controls/Button.cs

@ -30,7 +30,7 @@ namespace Avalonia.Controls
/// A button control.
/// </summary>
[PseudoClasses(":pressed")]
public class Button : ContentControl
public class Button : ContentControl, ICommandSource
{
/// <summary>
/// Defines the <see cref="ClickMode"/> property.
@ -492,5 +492,7 @@ namespace Avalonia.Controls
{
PseudoClasses.Set(":pressed", isPressed);
}
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e);
}
}

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>

26
src/Avalonia.Controls/HotkeyManager.cs

@ -12,18 +12,21 @@ namespace Avalonia.Controls
class HotkeyCommandWrapper : ICommand
{
public HotkeyCommandWrapper(IControl control)
public HotkeyCommandWrapper(ICommandSource control)
{
Control = control;
CommandSource = control;
}
public readonly IControl Control;
public readonly ICommandSource CommandSource;
private ICommand GetCommand() => Control.GetValue(Button.CommandProperty);
private ICommand GetCommand() => CommandSource.Command;
public bool CanExecute(object parameter) => GetCommand()?.CanExecute(parameter) ?? false;
public bool CanExecute(object parameter) =>
CommandSource.Command?.CanExecute(CommandSource.CommandParameter) == true
&& CommandSource.IsEffectivelyEnabled;
public void Execute(object parameter) => GetCommand()?.Execute(parameter);
public void Execute(object parameter) =>
GetCommand()?.Execute(CommandSource.CommandParameter);
#pragma warning disable 67 // Event not used
public event EventHandler CanExecuteChanged;
@ -44,7 +47,7 @@ namespace Avalonia.Controls
public Manager(IControl control)
{
_control = control;
_wrapper = new HotkeyCommandWrapper(_control);
_wrapper = new HotkeyCommandWrapper(_control as ICommandSource);
}
public void Init()
@ -84,7 +87,7 @@ namespace Avalonia.Controls
{
if (_root != null && _hotkey != null)
{
_binding = new KeyBinding() {Gesture = _hotkey, Command = _wrapper};
_binding = new KeyBinding() { Gesture = _hotkey, Command = _wrapper };
_root.KeyBindings.Add(_binding);
}
}
@ -102,8 +105,13 @@ namespace Avalonia.Controls
HotKeyProperty.Changed.Subscribe(args =>
{
var control = args.Sender as IControl;
if (args.OldValue != null|| control == null)
if (args.OldValue != null || control == null || !(control is ICommandSource))
{
Logging.Logger.TryGet(Logging.LogEventLevel.Warning, Logging.LogArea.Control)?.
Log(control, $"The element {args.Sender.GetType().Name} does not support binding a HotKey ({args.NewValue}).");
return;
}
new Manager(control).Init();
});
}

4
src/Avalonia.Controls/MenuItem.cs

@ -22,7 +22,7 @@ namespace Avalonia.Controls
/// A menu item control.
/// </summary>
[PseudoClasses(":separator", ":icon", ":open", ":pressed", ":selected")]
public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable
public class MenuItem : HeaderedSelectingItemsControl, IMenuItem, ISelectable, ICommandSource
{
/// <summary>
/// Defines the <see cref="Command"/> property.
@ -609,6 +609,8 @@ namespace Avalonia.Controls
SelectedItem = null;
}
void ICommandSource.CanExecuteChanged(object sender, EventArgs e) => this.CanExecuteChanged(sender, e);
/// <summary>
/// A dependency resolver which returns a <see cref="MenuItemAccessKeyHandler"/>.
/// </summary>

2
src/Avalonia.Controls/NativeMenuItem.cs

@ -150,7 +150,7 @@ namespace Avalonia.Controls
void CanExecuteChanged()
{
IsEnabled = _command?.CanExecute(null) ?? true;
IsEnabled = _command?.CanExecute(CommandParameter) ?? true;
}
public bool HasClickHandlers => Click != null;

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

@ -872,7 +872,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)
{
}

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

@ -12,6 +12,9 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.DefaultTheme.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Accents.BaseLight.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Controls.DataGrid.Themes.Default.xaml?assembly=Avalonia.Controls.DataGrid"/>
<Style Selector="DataGrid ContextMenu">
<Setter Property="Foreground" Value="Black"/>
</Style>
</Window.Styles>
<views:MainView/>

1
src/Avalonia.Dialogs/ApiCompatBaseline.txt

@ -1 +0,0 @@
Total Issues: 0

2
src/Avalonia.FreeDesktop/DBusHelper.cs

@ -44,7 +44,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)

4
src/Avalonia.Input/ApiCompatBaseline.txt

@ -1,4 +0,0 @@
Compat issues with assembly Avalonia.Input:
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Input.IInputElement.IsKeyboardFocusWithin' is present in the implementation but not in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public System.Boolean Avalonia.Input.IInputElement.IsKeyboardFocusWithin.get()' is present in the implementation but not in the contract.
Total Issues: 2

36
src/Avalonia.Input/ICommandSource.cs

@ -0,0 +1,36 @@
using System.Windows.Input;
namespace Avalonia.Input
{
///<summary>
/// An interface for classes that know how to invoke a Command.
///</summary>
public interface ICommandSource
{
/// <summary>
/// The command that will be executed when the class is "invoked."
/// Classes that implement this interface should enable or disable based on the command's CanExecute return value.
/// The property may be implemented as read-write if desired.
/// </summary>
ICommand Command { get; }
/// <summary>
/// The parameter that will be passed to the command when executing the command.
/// The property may be implemented as read-write if desired.
/// </summary>
object CommandParameter { get; }
/// <summary>
/// Bor the bheavior CanExecuteChanged
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void CanExecuteChanged(object sender, System.EventArgs e);
/// <summary>
/// Gets a value indicating whether this control and all its parents are enabled.
/// </summary>
bool IsEffectivelyEnabled { get; }
}
}

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);

3
src/Avalonia.Styling/ApiCompatBaseline.txt

@ -1,3 +0,0 @@
Compat issues with assembly Avalonia.Styling:
MembersMustExist : Member 'public System.IObservable<System.Object> Avalonia.Controls.ResourceNodeExtensions.GetResourceObservable(Avalonia.IStyledElement, System.Object, System.Func<System.Object, System.Object>)' does not exist in the implementation but it does exist in the contract.
Total Issues: 1

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">

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

@ -1,4 +0,0 @@
Compat issues with assembly Avalonia.Themes.Fluent:
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"

5
src/Avalonia.Visuals/ApiCompatBaseline.txt

@ -1,5 +0,0 @@
Compat issues with assembly Avalonia.Visuals:
MembersMustExist : Member 'public Avalonia.StyledProperty<System.Collections.Generic.IReadOnlyList<System.Double>> Avalonia.StyledProperty<System.Collections.Generic.IReadOnlyList<System.Double>> Avalonia.Media.DashStyle.DashesProperty' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public System.Collections.Generic.IReadOnlyList<System.Double> Avalonia.Media.DashStyle.Dashes.get()' does not exist in the implementation but it does exist in the contract.
MembersMustExist : Member 'public void Avalonia.Media.DashStyle.Dashes.set(System.Collections.Generic.IReadOnlyList<System.Double>)' does not exist in the implementation but it does exist in the contract.
Total Issues: 3

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

@ -809,7 +809,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

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

@ -1,4 +0,0 @@
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

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; }
}
}

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

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

@ -20,13 +20,17 @@ namespace Avalonia.Win32
return wgl;
}
if (opts?.AllowEglInitialization == true)
if (opts?.AllowEglInitialization == true ||
((!opts?.AllowEglInitialization.HasValue ?? false) &&
Win32Platform.WindowsVersion > new Version(6, 1)))
{
var egl = EglPlatformOpenGlInterface.TryCreate(() => new AngleWin32EglDisplay());
if (egl is { } &&
opts?.UseWindowsUIComposition == true)
opts?.UseWindowsUIComposition == true)
{
WinUICompositorConnection.TryCreateAndRegister(egl);
}
return egl;
}

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

@ -16,6 +16,8 @@ using Avalonia.OpenGL.Egl;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.Utilities;
using Avalonia.Win32;
using Avalonia.Win32.Input;
using Avalonia.Win32.Interop;
using static Avalonia.Win32.Interop.UnmanagedMethods;
@ -38,7 +40,9 @@ namespace Avalonia
public class Win32PlatformOptions
{
public bool UseDeferredRendering { get; set; } = true;
public bool AllowEglInitialization { get; set; } = true;
public bool? AllowEglInitialization { get; set; }
public bool? EnableMultitouch { get; set; }
public bool OverlayPopups { get; set; }
public bool UseWgl { get; set; }
@ -110,7 +114,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 +133,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 +246,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

14
src/Windows/Avalonia.Win32/WindowImpl.cs

@ -243,7 +243,7 @@ namespace Avalonia.Win32
{
if (IsWindowVisible(_hwnd))
{
ShowWindow(value);
ShowWindow(value, true);
}
else
{
@ -567,10 +567,11 @@ namespace Avalonia.Win32
UnmanagedMethods.ShowWindow(_hwnd, ShowWindowCommand.Hide);
}
public virtual void Show()
public virtual void Show(bool activate)
{
SetWindowLongPtr(_hwnd, (int)WindowLongParam.GWL_HWNDPARENT, _parent != null ? _parent._hwnd : IntPtr.Zero);
ShowWindow(_showWindowState);
ShowWindow(_showWindowState, activate);
}
public Action GotInputWhenDisabled { get; set; }
@ -908,7 +909,7 @@ namespace Avalonia.Win32
ExtendClientAreaToDecorationsChanged?.Invoke(_isClientAreaExtended);
}
private void ShowWindow(WindowState state)
private void ShowWindow(WindowState state, bool activate)
{
ShowWindowCommand? command;
@ -918,7 +919,7 @@ namespace Avalonia.Win32
{
case WindowState.Minimized:
newWindowProperties.IsFullScreen = false;
command = ShowWindowCommand.Minimize;
command = activate ? ShowWindowCommand.Minimize : ShowWindowCommand.ShowMinNoActive;
break;
case WindowState.Maximized:
newWindowProperties.IsFullScreen = false;
@ -927,7 +928,8 @@ namespace Avalonia.Win32
case WindowState.Normal:
newWindowProperties.IsFullScreen = false;
command = ShowWindowCommand.Restore;
command = IsWindowVisible(_hwnd) ? ShowWindowCommand.Restore :
activate ? ShowWindowCommand.Normal : ShowWindowCommand.ShowNoActivate;
break;
case WindowState.FullScreen:

22
tests/Avalonia.Base.UnitTests/AvaloniaPropertyTests.cs

@ -27,7 +27,7 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void GetMetadata_Returns_Supplied_Value()
{
var metadata = new PropertyMetadata();
var metadata = new AvaloniaPropertyMetadata();
var target = new TestProperty<string>("test", typeof(Class1), metadata);
Assert.Same(metadata, target.GetMetadata<Class1>());
@ -36,7 +36,7 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void GetMetadata_Returns_Supplied_Value_For_Derived_Class()
{
var metadata = new PropertyMetadata();
var metadata = new AvaloniaPropertyMetadata();
var target = new TestProperty<string>("test", typeof(Class1), metadata);
Assert.Same(metadata, target.GetMetadata<Class2>());
@ -45,7 +45,7 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void GetMetadata_Returns_Supplied_Value_For_Unrelated_Class()
{
var metadata = new PropertyMetadata();
var metadata = new AvaloniaPropertyMetadata();
var target = new TestProperty<string>("test", typeof(Class3), metadata);
Assert.Same(metadata, target.GetMetadata<Class2>());
@ -54,8 +54,8 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void GetMetadata_Returns_Overridden_Value()
{
var metadata = new PropertyMetadata();
var overridden = new PropertyMetadata();
var metadata = new AvaloniaPropertyMetadata();
var overridden = new AvaloniaPropertyMetadata();
var target = new TestProperty<string>("test", typeof(Class1), metadata);
target.OverrideMetadata<Class2>(overridden);
@ -66,9 +66,9 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void OverrideMetadata_Should_Merge_Values()
{
var metadata = new PropertyMetadata(BindingMode.TwoWay);
var metadata = new AvaloniaPropertyMetadata(BindingMode.TwoWay);
var notify = (Action<IAvaloniaObject, bool>)((a, b) => { });
var overridden = new PropertyMetadata();
var overridden = new AvaloniaPropertyMetadata();
var target = new TestProperty<string>("test", typeof(Class1), metadata);
target.OverrideMetadata<Class2>(overridden);
@ -129,19 +129,19 @@ namespace Avalonia.Base.UnitTests
[Fact]
public void PropertyMetadata_BindingMode_Default_Returns_OneWay()
{
var data = new PropertyMetadata(defaultBindingMode: BindingMode.Default);
var data = new AvaloniaPropertyMetadata(defaultBindingMode: BindingMode.Default);
Assert.Equal(BindingMode.OneWay, data.DefaultBindingMode);
}
private class TestProperty<TValue> : AvaloniaProperty<TValue>
{
public TestProperty(string name, Type ownerType, PropertyMetadata metadata = null)
: base(name, ownerType, metadata ?? new PropertyMetadata())
public TestProperty(string name, Type ownerType, AvaloniaPropertyMetadata metadata = null)
: base(name, ownerType, metadata ?? new AvaloniaPropertyMetadata())
{
}
public void OverrideMetadata<T>(PropertyMetadata metadata)
public void OverrideMetadata<T>(AvaloniaPropertyMetadata metadata)
{
OverrideMetadata(typeof(T), metadata);
}

16
tests/Avalonia.Controls.UnitTests/ContextMenuTests.cs

@ -79,7 +79,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
popupImpl.Setup(x => x.Show()).Verifiable();
popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
var sut = new ContextMenu();
@ -99,7 +99,7 @@ namespace Avalonia.Controls.UnitTests
_mouse.Click(target);
Assert.False(sut.IsOpen);
popupImpl.Verify(x => x.Show(), Times.Once);
popupImpl.Verify(x => x.Show(true), Times.Once);
popupImpl.Verify(x => x.Hide(), Times.Once);
}
}
@ -109,7 +109,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
popupImpl.Setup(x => x.Show()).Verifiable();
popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
var sut = new ContextMenu();
@ -130,7 +130,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(sut.IsOpen);
popupImpl.Verify(x => x.Hide(), Times.Once);
popupImpl.Verify(x => x.Show(), Times.Exactly(2));
popupImpl.Verify(x => x.Show(true), Times.Exactly(2));
}
}
@ -177,7 +177,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
popupImpl.Setup(x => x.Show()).Verifiable();
popupImpl.Setup(x => x.Show(true)).Verifiable();
bool eventCalled = false;
var sut = new ContextMenu();
@ -193,7 +193,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(eventCalled);
Assert.False(sut.IsOpen);
popupImpl.Verify(x => x.Show(), Times.Never);
popupImpl.Verify(x => x.Show(true), Times.Never);
}
}
@ -297,7 +297,7 @@ namespace Avalonia.Controls.UnitTests
{
using (Application())
{
popupImpl.Setup(x => x.Show()).Verifiable();
popupImpl.Setup(x => x.Show(true)).Verifiable();
popupImpl.Setup(x => x.Hide()).Verifiable();
bool eventCalled = false;
@ -321,7 +321,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(eventCalled);
Assert.True(sut.IsOpen);
popupImpl.Verify(x => x.Show(), Times.Once());
popupImpl.Verify(x => x.Show(true), Times.Once());
popupImpl.Verify(x => x.Hide(), Times.Never);
}
}

141
tests/Avalonia.Controls.UnitTests/Utils/HotKeyManagerTests.cs

@ -5,6 +5,9 @@ using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Styling;
using Xunit;
using System;
using Avalonia.Input.Raw;
using Factory = System.Func<int, System.Action<object>, Avalonia.Controls.Window, Avalonia.AvaloniaObject>;
namespace Avalonia.Controls.UnitTests.Utils
{
@ -54,6 +57,127 @@ namespace Avalonia.Controls.UnitTests.Utils
}
}
[Theory]
[MemberData(nameof(ElementsFactory))]
public void HotKeyManager_Should_Use_CommandParameter(string factoryName, Factory factory)
{
using (AvaloniaLocator.EnterScope())
{
var styler = new Mock<Styler>();
var target = new KeyboardDevice();
var commandResult = 0;
var expectedParameter = 1;
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object);
var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
var action = new Action<object>(parameter =>
{
if (parameter is int value)
{
commandResult = value;
}
});
var root = new Window();
var element = factory(expectedParameter, action, root);
root.Template = CreateWindowTemplate();
root.ApplyTemplate();
root.Presenter.ApplyTemplate();
HotKeyManager.SetHotKey(element, gesture);
target.ProcessRawEvent(new RawKeyEventArgs(target,
0,
root,
RawKeyEventType.KeyDown,
Key.A,
RawInputModifiers.Control));
Assert.True(expectedParameter == commandResult, $"{factoryName} HotKey did not carry the CommandParameter.");
}
}
[Theory]
[MemberData(nameof(ElementsFactory))]
public void HotKeyManager_Should_Do_Not_Executed_When_IsEnabled_False(string factoryName, Factory factory)
{
using (AvaloniaLocator.EnterScope())
{
var styler = new Mock<Styler>();
var target = new KeyboardDevice();
var isExecuted = false;
AvaloniaLocator.CurrentMutable
.Bind<IWindowingPlatform>().ToConstant(new WindowingPlatformMock())
.Bind<IStyler>().ToConstant(styler.Object);
var gesture = new KeyGesture(Key.A, KeyModifiers.Control);
var action = new Action<object>(parameter =>
{
isExecuted = true;
});
var root = new Window();
var element = factory(0, action, root) as InputElement;
element.IsEnabled = false;
root.Template = CreateWindowTemplate();
root.ApplyTemplate();
root.Presenter.ApplyTemplate();
HotKeyManager.SetHotKey(element, gesture);
target.ProcessRawEvent(new RawKeyEventArgs(target,
0,
root,
RawKeyEventType.KeyDown,
Key.A,
RawInputModifiers.Control));
Assert.True(isExecuted == false, $"{factoryName} Execution raised when IsEnabled is false.");
}
}
public static TheoryData<string, Factory> ElementsFactory =>
new TheoryData<string, Factory>()
{
{nameof(Button), MakeButton},
{nameof(MenuItem),MakeMenu},
};
private static AvaloniaObject MakeMenu(int expectedParameter, Action<object> action, Window root)
{
var menuitem = new MenuItem()
{
Command = new Command(action),
CommandParameter = expectedParameter,
};
var rootMenu = new Menu();
rootMenu.Items = new[] { menuitem };
root.Content = rootMenu;
return menuitem;
}
private static AvaloniaObject MakeButton(int expectedParameter, Action<object> action, Window root)
{
var button = new Button()
{
Command = new Command(action),
CommandParameter = expectedParameter,
};
root.Content = button;
return button;
}
private FuncControlTemplate CreateWindowTemplate()
{
return new FuncControlTemplate<Window>((parent, scope) =>
@ -65,5 +189,22 @@ namespace Avalonia.Controls.UnitTests.Utils
}.RegisterInNameScope(scope);
});
}
class Command : System.Windows.Input.ICommand
{
private readonly Action<object> _execeute;
#pragma warning disable 67 // Event not used
public event EventHandler CanExecuteChanged;
#pragma warning restore 67 // Event not used
public Command(Action<object> execeute)
{
_execeute = execeute;
}
public bool CanExecute(object parameter) => true;
public void Execute(object parameter) => _execeute?.Invoke(parameter);
}
}
}

2
tests/Avalonia.Controls.UnitTests/WindowBaseTests.cs

@ -137,7 +137,7 @@ namespace Avalonia.Controls.UnitTests
var target = new TestWindowBase(windowImpl.Object);
target.IsVisible = true;
windowImpl.Verify(x => x.Show());
windowImpl.Verify(x => x.Show(true));
}
}

121
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -10,6 +10,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Data.Converters;
using Avalonia.Data.Core;
using Avalonia.Markup.Data;
using Avalonia.Media;
using Avalonia.UnitTests;
using XamlX;
using Xunit;
@ -536,7 +537,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
[Fact]
public void ResolvesSourceBindingLongForm()
public void Binds_To_Source()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
@ -559,6 +560,124 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
}
}
[Fact]
public void Binds_To_Source_StaticResource()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
x:CompileBindings='True'>
<Window.Resources>
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
</Window.Resources>
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
[Fact]
public void Binds_To_Source_StaticResource1()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
x:CompileBindings='True'>
<Window.Resources>
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
<x:String x:Key='otherObjectKey'>test</x:String>
</Window.Resources>
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
[Fact]
public void Binds_To_Source_StaticResource_In_ResourceDictionary()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
x:DataType='local:TestDataContext' x:CompileBindings='True'>
<Window.Resources>
<ResourceDictionary>
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
</ResourceDictionary>
</Window.Resources>
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
[Fact]
public void Binds_To_Source_StaticResource_In_ResourceDictionary1()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
x:DataType='local:TestDataContext' x:CompileBindings='True'>
<Window.Resources>
<ResourceDictionary>
<local:TestDataContext x:Key='dataKey' StringProperty='foobar'/>
<x:String x:Key='otherObjectKey'>test</x:String>
</ResourceDictionary>
</Window.Resources>
<TextBlock Name='textBlock' Text='{Binding StringProperty, Source={StaticResource dataKey}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
Assert.Equal("foobar", textBlock.Text);
}
}
[Fact]
public void Binds_To_Source_xStatic()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='using:Avalonia.Markup.Xaml.UnitTests.MarkupExtensions'
x:CompileBindings='True'>
<ContentControl Name='contentControl' Content='{Binding Color, Source={x:Static Brushes.Red}}'/>
</Window>";
var window = (Window)AvaloniaRuntimeXamlLoader.Load(xaml);
var contentControl = window.FindControl<ContentControl>("contentControl");
Assert.Equal(Brushes.Red.Color, contentControl.Content);
}
}
[Fact]
public void CompilesBindingWhenRequested()
{

2
tests/Avalonia.UnitTests/MockWindowingPlatform.cs

@ -58,7 +58,7 @@ namespace Avalonia.UnitTests
windowImpl.Object.Resized?.Invoke(clientSize);
});
windowImpl.Setup(x => x.Show()).Callback(() =>
windowImpl.Setup(x => x.Show(true)).Callback(() =>
{
windowImpl.Object.Activated?.Invoke();
});

Loading…
Cancel
Save