Browse Source

Merge branch 'master' into pr/715

pull/722/head
Steven Kirk 10 years ago
parent
commit
1436f7e9ed
  1. 85
      Avalonia.sln
  2. 5
      samples/BindingTest/BindingTest.csproj
  3. 14
      samples/BindingTest/MainWindow.xaml
  4. 17
      samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs
  5. 4
      samples/BindingTest/ViewModels/ExceptionErrorViewModel.cs
  6. 73
      samples/BindingTest/ViewModels/IndeiErrorViewModel.cs
  7. 5
      samples/BindingTest/ViewModels/MainWindowViewModel.cs
  8. 12
      samples/ControlCatalog/ControlCatalog.csproj
  9. 24
      samples/ControlCatalog/MainView.xaml
  10. 19
      samples/ControlCatalog/MainView.xaml.cs
  11. 28
      samples/ControlCatalog/MainWindow.xaml
  12. 2
      samples/ControlCatalog/MainWindow.xaml.cs
  13. 2
      samples/ControlCatalog/Pages/CanvasPage.xaml
  14. 6
      samples/interop/GtkInteropDemo/App.config
  15. 160
      samples/interop/GtkInteropDemo/GtkInteropDemo.csproj
  16. 26
      samples/interop/GtkInteropDemo/GtkInteropDemo.v2.ncrunchproject
  17. 30
      samples/interop/GtkInteropDemo/MainWindow.cs
  18. 24
      samples/interop/GtkInteropDemo/Program.cs
  19. 36
      samples/interop/GtkInteropDemo/Properties/AssemblyInfo.cs
  20. 71
      samples/interop/GtkInteropDemo/Properties/Resources.Designer.cs
  21. 117
      samples/interop/GtkInteropDemo/Properties/Resources.resx
  22. 30
      samples/interop/GtkInteropDemo/Properties/Settings.Designer.cs
  23. 7
      samples/interop/GtkInteropDemo/Properties/Settings.settings
  24. 6
      samples/interop/WindowsInteropTest/App.config
  25. 119
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs
  26. 23
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs
  27. 120
      samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.resx
  28. 21
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml
  29. 31
      samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs
  30. 22
      samples/interop/WindowsInteropTest/Program.cs
  31. 36
      samples/interop/WindowsInteropTest/Properties/AssemblyInfo.cs
  32. 71
      samples/interop/WindowsInteropTest/Properties/Resources.Designer.cs
  33. 117
      samples/interop/WindowsInteropTest/Properties/Resources.resx
  34. 30
      samples/interop/WindowsInteropTest/Properties/Settings.Designer.cs
  35. 7
      samples/interop/WindowsInteropTest/Properties/Settings.settings
  36. 76
      samples/interop/WindowsInteropTest/SelectorForm.Designer.cs
  37. 30
      samples/interop/WindowsInteropTest/SelectorForm.cs
  38. 120
      samples/interop/WindowsInteropTest/SelectorForm.resx
  39. 190
      samples/interop/WindowsInteropTest/WindowsInteropTest.csproj
  40. 26
      samples/interop/WindowsInteropTest/WindowsInteropTest.v2.ncrunchproject
  41. 2
      src/Android/Avalonia.Android/AndroidPlatform.cs
  42. 7
      src/Avalonia.Base/Avalonia.Base.csproj
  43. 267
      src/Avalonia.Base/AvaloniaObject.cs
  44. 11
      src/Avalonia.Base/AvaloniaObjectExtensions.cs
  45. 9
      src/Avalonia.Base/AvaloniaProperty.cs
  46. 85
      src/Avalonia.Base/Data/BindingChainNullException.cs
  47. 59
      src/Avalonia.Base/Data/BindingError.cs
  48. 282
      src/Avalonia.Base/Data/BindingNotification.cs
  49. 5
      src/Avalonia.Base/Data/BindingOperations.cs
  50. 4
      src/Avalonia.Base/Data/IBinding.cs
  51. 17
      src/Avalonia.Base/Data/IValidationStatus.cs
  52. 6
      src/Avalonia.Base/Data/IndexerBinding.cs
  53. 44
      src/Avalonia.Base/Data/ObjectValidationStatus.cs
  54. 11
      src/Avalonia.Base/DirectProperty.cs
  55. 20
      src/Avalonia.Base/DirectPropertyMetadata`1.cs
  56. 5
      src/Avalonia.Base/IDirectPropertyMetadata.cs
  57. 7
      src/Avalonia.Base/IPriorityValueOwner.cs
  58. 26
      src/Avalonia.Base/PriorityBindingEntry.cs
  59. 13
      src/Avalonia.Base/PriorityLevel.cs
  60. 39
      src/Avalonia.Base/PriorityValue.cs
  61. 3
      src/Avalonia.Base/PropertyMetadata.cs
  62. 23
      src/Avalonia.Base/Utilities/ExceptionUtilities.cs
  63. 41
      src/Avalonia.Base/Utilities/TypeUtilities.cs
  64. 54
      src/Avalonia.Base/Utilities/WeakObservable.cs
  65. 39
      src/Avalonia.Controls/AppBuilderBase.cs
  66. 4
      src/Avalonia.Controls/Avalonia.Controls.csproj
  67. 1
      src/Avalonia.Controls/Canvas.cs
  68. 9
      src/Avalonia.Controls/Control.cs
  69. 73
      src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs
  70. 11
      src/Avalonia.Controls/ItemsControl.cs
  71. 15
      src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs
  72. 2
      src/Avalonia.Controls/Platform/IWindowingPlatform.cs
  73. 8
      src/Avalonia.Controls/Platform/PlatformManager.cs
  74. 29
      src/Avalonia.Controls/Primitives/Popup.cs
  75. 2
      src/Avalonia.Controls/Primitives/PopupRoot.cs
  76. 1
      src/Avalonia.Controls/Properties/AssemblyInfo.cs
  77. 101
      src/Avalonia.Controls/TextBox.cs
  78. 23
      src/Avalonia.Controls/ToolTip.cs
  79. 26
      src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v2.ncrunchproject
  80. 110
      src/Avalonia.SceneGraph/Media/PathMarkupParser.cs
  81. 2
      src/Avalonia.Themes.Default/Accents/BaseLight.xaml
  82. 5
      src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj
  83. 5
      src/Avalonia.Themes.Default/DefaultTheme.xaml
  84. 8
      src/Avalonia.Themes.Default/DropDown.xaml
  85. 17
      src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml
  86. 34
      src/Avalonia.Themes.Default/TextBox.xaml
  87. 22
      src/Gtk/Avalonia.Cairo/CairoPlatform.cs
  88. 23
      src/Gtk/Avalonia.Cairo/RenderTarget.cs
  89. 8
      src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj
  90. 70
      src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs
  91. 77
      src/Gtk/Avalonia.Gtk/Embedding/GtkAvaloniaControlHost.cs
  92. 5
      src/Gtk/Avalonia.Gtk/GtkPlatform.cs
  93. 4
      src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs
  94. 374
      src/Gtk/Avalonia.Gtk/WindowImpl.cs
  95. 310
      src/Gtk/Avalonia.Gtk/WindowImplBase.cs
  96. 91
      src/Gtk/Avalonia.Gtk/Windows.cs
  97. 59
      src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
  98. 3
      src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs
  99. 3
      src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs
  100. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/BindingExtension.cs

85
Avalonia.sln

@ -163,6 +163,12 @@ Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Avalonia.RenderTests", "tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VirtualizationTest", "samples\VirtualizationTest\VirtualizationTest.csproj", "{FBCAF3D0-2808-4934-8E96-3F607594517B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Interop", "Interop", "{A0CC0258-D18C-4AB3-854F-7101680FC3F9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WindowsInteropTest", "samples\interop\WindowsInteropTest\WindowsInteropTest.csproj", "{C7A69145-60B6-4882-97D6-A3921DD43978}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GtkInteropDemo", "samples\interop\GtkInteropDemo\GtkInteropDemo.csproj", "{BD7F352C-6DC1-4740-BAF2-2D34A038728C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avalonia.DotNetFrameworkRuntime", "src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj", "{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}"
EndProject
Global
@ -2240,6 +2246,82 @@ Global
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|Mono.Build.0 = Release|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|x86.ActiveCfg = Release|Any CPU
{FBCAF3D0-2808-4934-8E96-3F607594517B}.Release|x86.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|Any CPU.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|iPhone.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|Mono.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|x86.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.AppStore|x86.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|iPhone.Build.0 = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|Mono.ActiveCfg = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|x86.ActiveCfg = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Debug|x86.Build.0 = Debug|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|Any CPU.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhone.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhone.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|Mono.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.ActiveCfg = Release|Any CPU
{C7A69145-60B6-4882-97D6-A3921DD43978}.Release|x86.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|Mono.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Ad-Hoc|x86.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Any CPU.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhone.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|Mono.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.AppStore|x86.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.ActiveCfg = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhone.Build.0 = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.ActiveCfg = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|Mono.Build.0 = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.ActiveCfg = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Debug|x86.Build.0 = Debug|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Any CPU.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhone.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|Mono.Build.0 = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.ActiveCfg = Release|Any CPU
{BD7F352C-6DC1-4740-BAF2-2D34A038728C}.Release|x86.Build.0 = Release|Any CPU
{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
{4A1ABB09-9047-4BD5-A4AD-A055E52C5EE0}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
@ -2332,5 +2414,8 @@ Global
{F1381F98-4D24-409A-A6C5-1C5B1E08BB08} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{48840EDD-24BF-495D-911E-2EB12AE75D3B} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{FBCAF3D0-2808-4934-8E96-3F607594517B} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{A0CC0258-D18C-4AB3-854F-7101680FC3F9} = {9B9E3891-2366-4253-A952-D08BCEB71098}
{C7A69145-60B6-4882-97D6-A3921DD43978} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{BD7F352C-6DC1-4740-BAF2-2D34A038728C} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
EndGlobalSection
EndGlobal

5
samples/BindingTest/BindingTest.csproj

@ -50,6 +50,7 @@
<Private>True</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.Core" />
<Reference Include="System.Reactive.Core, Version=3.0.0.0, Culture=neutral, PublicKeyToken=94bc3704cddfc263, processorArchitecture=MSIL">
<HintPath>..\..\packages\System.Reactive.Core.3.0.0\lib\net45\System.Reactive.Core.dll</HintPath>
@ -80,7 +81,9 @@
<Compile Include="TestItemView.xaml.cs">
<DependentUpon>TestItemView.xaml</DependentUpon>
</Compile>
<Compile Include="ViewModels\ExceptionPropertyErrorViewModel.cs" />
<Compile Include="ViewModels\DataAnnotationsErrorViewModel.cs" />
<Compile Include="ViewModels\IndeiErrorViewModel.cs" />
<Compile Include="ViewModels\ExceptionErrorViewModel.cs" />
<Compile Include="ViewModels\MainWindowViewModel.cs" />
<Compile Include="ViewModels\TestItem.cs" />
</ItemGroup>

14
samples/BindingTest/MainWindow.xaml

@ -70,9 +70,19 @@
</TabItem>
<TabItem Header="Property Validation">
<StackPanel Orientation="Horizontal">
<StackPanel Margin="18" Gap="4" Width="200" DataContext="{Binding ExceptionPropertyValidation}">
<StackPanel Margin="18" Gap="4" MinWidth="200" DataContext="{Binding ExceptionDataValidation}">
<TextBlock FontSize="16" Text="Exception Validation"/>
<TextBox Watermark="Less Than 10" UseFloatingWatermark="True" Text="{Binding Path=LessThan10, EnableValidation=True}"/>
<TextBox Watermark="Less Than 10" UseFloatingWatermark="True" Text="{Binding Path=LessThan10}"/>
</StackPanel>
<StackPanel Margin="18" Gap="4" MinWidth="200" DataContext="{Binding IndeiDataValidation}">
<TextBlock FontSize="16" Text="INotifyDataErrorInfo Validation"/>
<TextBox Watermark="Maximum" UseFloatingWatermark="True" Text="{Binding Path=Maximum}"/>
<TextBox Watermark="Value" UseFloatingWatermark="True" Text="{Binding Path=Value}"/>
</StackPanel>
<StackPanel Margin="18" Gap="4" MinWidth="200" DataContext="{Binding DataAnnotationsValidation}">
<TextBlock FontSize="16" Text="Data Annotations Validation"/>
<TextBox Watermark="Phone #" UseFloatingWatermark="True" Text="{Binding PhoneNumber}"/>
<TextBox Watermark="Less Than 10" UseFloatingWatermark="True" Text="{Binding Path=LessThan10}"/>
</StackPanel>
</StackPanel>
</TabItem>

17
samples/BindingTest/ViewModels/DataAnnotationsErrorViewModel.cs

@ -0,0 +1,17 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.ComponentModel.DataAnnotations;
namespace BindingTest.ViewModels
{
public class DataAnnotationsErrorViewModel
{
[Phone]
[MaxLength(10)]
public string PhoneNumber { get; set; }
[Range(0, 9)]
public int LessThan10 { get; set; }
}
}

4
samples/BindingTest/ViewModels/ExceptionPropertyErrorViewModel.cs → samples/BindingTest/ViewModels/ExceptionErrorViewModel.cs

@ -6,7 +6,7 @@ using System;
namespace BindingTest.ViewModels
{
public class ExceptionPropertyErrorViewModel : ReactiveObject
public class ExceptionErrorViewModel : ReactiveObject
{
private int _lessThan10;
@ -21,7 +21,7 @@ namespace BindingTest.ViewModels
}
else
{
throw new InvalidOperationException("Value must be less than 10.");
throw new ArgumentOutOfRangeException("Value must be less than 10.");
}
}
}

73
samples/BindingTest/ViewModels/IndeiErrorViewModel.cs

@ -0,0 +1,73 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using ReactiveUI;
using System;
using System.ComponentModel;
using System.Collections;
namespace BindingTest.ViewModels
{
public class IndeiErrorViewModel : ReactiveObject, INotifyDataErrorInfo
{
private int _maximum = 10;
private int _value;
private string _valueError;
public IndeiErrorViewModel()
{
this.WhenAnyValue(x => x.Maximum, x => x.Value)
.Subscribe(_ => UpdateErrors());
}
public bool HasErrors
{
get { throw new NotImplementedException(); }
}
public int Maximum
{
get { return _maximum; }
set { this.RaiseAndSetIfChanged(ref _maximum, value); }
}
public int Value
{
get { return _value; }
set { this.RaiseAndSetIfChanged(ref _value, value); }
}
public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
public IEnumerable GetErrors(string propertyName)
{
switch (propertyName)
{
case nameof(Value):
return new[] { _valueError };
default:
return null;
}
}
private void UpdateErrors()
{
if (Value <= Maximum)
{
if (_valueError != null)
{
_valueError = null;
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value)));
}
}
else
{
if (_valueError == null)
{
_valueError = "Value must be less than Maximum";
ErrorsChanged?.Invoke(this, new DataErrorsChangedEventArgs(nameof(Value)));
}
}
}
}
}

5
samples/BindingTest/ViewModels/MainWindowViewModel.cs

@ -69,7 +69,8 @@ namespace BindingTest.ViewModels
public ReactiveCommand<object> StringValueCommand { get; }
public ExceptionPropertyErrorViewModel ExceptionPropertyValidation { get; }
= new ExceptionPropertyErrorViewModel();
public DataAnnotationsErrorViewModel DataAnnotationsValidation { get; } = new DataAnnotationsErrorViewModel();
public ExceptionErrorViewModel ExceptionDataValidation { get; } = new ExceptionErrorViewModel();
public IndeiErrorViewModel IndeiDataValidation { get; } = new IndeiErrorViewModel();
}
}

12
samples/ControlCatalog/ControlCatalog.csproj

@ -38,7 +38,7 @@
<EmbeddedResource Include="App.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="MainWindow.xaml">
<EmbeddedResource Include="MainView.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
<EmbeddedResource Include="Pages\BorderPage.xaml">
@ -88,6 +88,9 @@
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
</Compile>
<Compile Include="MainView.xaml.cs">
<DependentUpon>MainView.xaml</DependentUpon>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
</Compile>
@ -215,6 +218,13 @@
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>
</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

24
samples/ControlCatalog/MainView.xaml

@ -0,0 +1,24 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<TabControl Classes="sidebar">
<TabControl.Transition>
<CrossFade Duration="0.25"/>
</TabControl.Transition>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
<TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
<TabItem Header="CheckBox"><pages:CheckBoxPage/></TabItem>
<TabItem Header="DropDown"><pages:DropDownPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image"><pages:ImagePage/></TabItem>
<TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
<TabItem Header="Menu"><pages:MenuPage/></TabItem>
<TabItem Header="RadioButton"><pages:RadioButtonPage/></TabItem>
<TabItem Header="Slider"><pages:SliderPage/></TabItem>
<TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>
<TabItem Header="ToolTip"><pages:ToolTipPage/></TabItem>
<TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
</TabControl>
</UserControl>

19
samples/ControlCatalog/MainView.xaml.cs

@ -0,0 +1,19 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace ControlCatalog
{
public class MainView : UserControl
{
public MainView()
{
this.InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}
}

28
samples/ControlCatalog/MainWindow.xaml

@ -1,26 +1,6 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:pages="clr-namespace:ControlCatalog.Pages;assembly=ControlCatalog"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
<Window xmlns="https://github.com/avaloniaui" MinWidth="500" MinHeight="300"
Title="Avalonia Control Gallery"
Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog">
<TabControl Classes="sidebar">
<TabControl.Transition>
<CrossFade Duration="0.25"/>
</TabControl.Transition>
<TabItem Header="Border"><pages:BorderPage/></TabItem>
<TabItem Header="Button"><pages:ButtonPage/></TabItem>
<TabItem Header="Canvas"><pages:CanvasPage/></TabItem>
<TabItem Header="Carousel"><pages:CarouselPage/></TabItem>
<TabItem Header="CheckBox"><pages:CheckBoxPage/></TabItem>
<TabItem Header="DropDown"><pages:DropDownPage/></TabItem>
<TabItem Header="Expander"><pages:ExpanderPage/></TabItem>
<TabItem Header="Image"><pages:ImagePage/></TabItem>
<TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
<TabItem Header="Menu"><pages:MenuPage/></TabItem>
<TabItem Header="RadioButton"><pages:RadioButtonPage/></TabItem>
<TabItem Header="Slider"><pages:SliderPage/></TabItem>
<TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>
<TabItem Header="ToolTip"><pages:ToolTipPage/></TabItem>
<TabItem Header="TreeView"><pages:TreeViewPage/></TabItem>
</TabControl>
Icon="resm:ControlCatalog.Assets.test_icon.ico?assembly=ControlCatalog"
xmlns:local="clr-namespace:ControlCatalog;assembly=ControlCatalog">
<local:MainView/>
</Window>

2
samples/ControlCatalog/MainWindow.xaml.cs

@ -20,6 +20,8 @@ namespace ControlCatalog
var theme = new Avalonia.Themes.Default.DefaultTheme();
theme.FindResource("Button");
AvaloniaXamlLoader.Load(this);
PointerPressed += delegate { Measure(new Size(1, 1)); };
}
}
}

2
samples/ControlCatalog/Pages/CanvasPage.xaml

@ -13,7 +13,7 @@
</LinearGradientBrush>
</Rectangle.OpacityMask> </Rectangle>
<Ellipse Fill="Green" Width="58" Height="58" Canvas.Left="88" Canvas.Top="100"/>
<Path Fill="Orange" Data="M 0,0 c 50,0 50,-50 c 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
<Path Fill="Orange" Data="M 0,0 c 0,0 50,0 50,-50 c 0,0 50,0 50,50 h -50 v 50 l -50,-50 Z" Canvas.Left="30" Canvas.Top="250"/>
<Path Fill="OrangeRed" Canvas.Left="180" Canvas.Top="250">
<Path.Data>
<PathGeometry>

6
samples/interop/GtkInteropDemo/App.config

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>

160
samples/interop/GtkInteropDemo/GtkInteropDemo.csproj

@ -0,0 +1,160 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{BD7F352C-6DC1-4740-BAF2-2D34A038728C}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>GtkInteropDemo</RootNamespace>
<AssemblyName>GtkInteropDemo</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<UseVSHostingProcess>false</UseVSHostingProcess>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="atk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="gdk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="glib-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="gtk-sharp, Version=2.12.0.0, Culture=neutral, PublicKeyToken=35e10195dab3c99f, processorArchitecture=MSIL" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xml" />
</ItemGroup>
<ItemGroup>
<Compile Include="MainWindow.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Avalonia.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
<Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
<Name>Avalonia.DotNetFrameworkRuntime</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Avalonia.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Gtk\Avalonia.Cairo\Avalonia.Cairo.csproj">
<Project>{fb05ac90-89ba-4f2f-a924-f37875fb547c}</Project>
<Name>Avalonia.Cairo</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Gtk\Avalonia.Gtk\Avalonia.Gtk.csproj">
<Project>{54f237d5-a70a-4752-9656-0c70b1a7b047}</Project>
<Name>Avalonia.Gtk</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia.Desktop\Avalonia.Skia.Desktop.csproj">
<Project>{925dd807-b651-475f-9f7c-cbeb974ce43d}</Project>
<Name>Avalonia.Skia.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj">
<Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
<Name>ControlCatalog</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

26
samples/interop/GtkInteropDemo/GtkInteropDemo.v2.ncrunchproject

@ -0,0 +1,26 @@
<ProjectConfiguration>
<AutoDetectNugetBuildDependencies>true</AutoDetectNugetBuildDependencies>
<BuildPriority>1000</BuildPriority>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<AllowCodeAnalysis>false</AllowCodeAnalysis>
<IgnoreThisComponentCompletely>true</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>false</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<DetectStackOverflow>true</DetectStackOverflow>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<UseBuildPlatform />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
</ProjectConfiguration>

30
samples/interop/GtkInteropDemo/MainWindow.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Diagnostics;
using Avalonia.Gtk.Embedding;
using ControlCatalog;
using Gtk;
namespace GtkInteropDemo
{
class MainWindow : Window
{
public MainWindow() : base("Gtk Embedding Demo")
{
var root = new HBox();
var left = new VBox();
left.Add(new Button("I'm GTK button"));
left.Add(new Calendar());
root.PackEnd(left, false, false, 0);
var host = new GtkAvaloniaControlHost() {Content = new MainView()};
host.SetSizeRequest(600, 600);
root.PackStart(host, true, true, 0);
Add(root);
ShowAll();
}
}
}

24
samples/interop/GtkInteropDemo/Program.cs

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using ControlCatalog;
namespace GtkInteropDemo
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
AppBuilder.Configure<App>().UseGtk().UseCairo().SetupWithoutStarting();
new MainWindow().Show();
Gtk.Application.Run();
}
}
}

36
samples/interop/GtkInteropDemo/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("GtkInteropDemo")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("GtkInteropDemo")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("bd7f352c-6dc1-4740-baf2-2d34a038728c")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

71
samples/interop/GtkInteropDemo/Properties/Resources.Designer.cs

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GtkInteropDemo.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("GtkInteropDemo.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

117
samples/interop/GtkInteropDemo/Properties/Resources.resx

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
samples/interop/GtkInteropDemo/Properties/Settings.Designer.cs

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace GtkInteropDemo.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

7
samples/interop/GtkInteropDemo/Properties/Settings.settings

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

6
samples/interop/WindowsInteropTest/App.config

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6" />
</startup>
</configuration>

119
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.Designer.cs

@ -0,0 +1,119 @@
using Avalonia.Win32.Embedding;
namespace WindowsInteropTest
{
partial class EmbedToWinFormsDemo
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.monthCalendar1 = new System.Windows.Forms.MonthCalendar();
this.groupBox1 = new System.Windows.Forms.GroupBox();
this.groupBox2 = new System.Windows.Forms.GroupBox();
this.avaloniaHost = new WinFormsAvaloniaControlHost();
this.groupBox1.SuspendLayout();
this.groupBox2.SuspendLayout();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(28, 29);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(164, 73);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
//
// monthCalendar1
//
this.monthCalendar1.Location = new System.Drawing.Point(28, 114);
this.monthCalendar1.Name = "monthCalendar1";
this.monthCalendar1.TabIndex = 1;
//
// groupBox1
//
this.groupBox1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)));
this.groupBox1.Controls.Add(this.button1);
this.groupBox1.Controls.Add(this.monthCalendar1);
this.groupBox1.Location = new System.Drawing.Point(12, 12);
this.groupBox1.Name = "groupBox1";
this.groupBox1.Size = new System.Drawing.Size(227, 418);
this.groupBox1.TabIndex = 2;
this.groupBox1.TabStop = false;
this.groupBox1.Text = "WinForms";
//
// groupBox2
//
this.groupBox2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.groupBox2.Controls.Add(this.avaloniaHost);
this.groupBox2.Location = new System.Drawing.Point(245, 12);
this.groupBox2.Name = "groupBox2";
this.groupBox2.Size = new System.Drawing.Size(501, 418);
this.groupBox2.TabIndex = 3;
this.groupBox2.TabStop = false;
this.groupBox2.Text = "Avalonia";
//
// avaloniaHost
//
this.avaloniaHost.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
| System.Windows.Forms.AnchorStyles.Left)
| System.Windows.Forms.AnchorStyles.Right)));
this.avaloniaHost.Content = null;
this.avaloniaHost.Location = new System.Drawing.Point(6, 19);
this.avaloniaHost.Name = "avaloniaHost";
this.avaloniaHost.Size = new System.Drawing.Size(489, 393);
this.avaloniaHost.TabIndex = 0;
this.avaloniaHost.Text = "avaloniaHost";
//
// EmbedToWinFormsDemo
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(758, 442);
this.Controls.Add(this.groupBox2);
this.Controls.Add(this.groupBox1);
this.MinimumSize = new System.Drawing.Size(600, 400);
this.Name = "EmbedToWinFormsDemo";
this.Text = "EmbedToWinFormsDemo";
this.groupBox1.ResumeLayout(false);
this.groupBox2.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.MonthCalendar monthCalendar1;
private System.Windows.Forms.GroupBox groupBox1;
private System.Windows.Forms.GroupBox groupBox2;
private WinFormsAvaloniaControlHost avaloniaHost;
}
}

23
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Avalonia.Controls;
using ControlCatalog;
namespace WindowsInteropTest
{
public partial class EmbedToWinFormsDemo : Form
{
public EmbedToWinFormsDemo()
{
InitializeComponent();
avaloniaHost.Content = new MainView();
}
}
}

120
samples/interop/WindowsInteropTest/EmbedToWinFormsDemo.resx

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

21
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml

@ -0,0 +1,21 @@
<Window x:Class="WindowsInteropTest.EmbedToWpfDemo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WindowsInteropTest"
xmlns:embedding="clr-namespace:Avalonia.Win32.Embedding;assembly=Avalonia.Win32"
mc:Ignorable="d"
d:DesignHeight="400" d:DesignWidth="400" MinWidth="500" MinHeight="400">
<DockPanel>
<GroupBox DockPanel.Dock="Left" Header="WPF">
<StackPanel>
<Slider/>
<Calendar/>
</StackPanel>
</GroupBox>
<GroupBox Header="Avalonia">
<embedding:WpfAvaloniaControlHost x:Name="Host"/>
</GroupBox>
</DockPanel>
</Window>

31
samples/interop/WindowsInteropTest/EmbedToWpfDemo.xaml.cs

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using Avalonia.Controls;
using ControlCatalog;
using Window = System.Windows.Window;
namespace WindowsInteropTest
{
/// <summary>
/// Interaction logic for EmbedToWpfDemo.xaml
/// </summary>
public partial class EmbedToWpfDemo : Window
{
public EmbedToWpfDemo()
{
InitializeComponent();
Host.Content = new MainView();
}
}
}

22
samples/interop/WindowsInteropTest/Program.cs

@ -0,0 +1,22 @@
using System;
using Avalonia.Controls;
using ControlCatalog;
using Avalonia;
namespace WindowsInteropTest
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
System.Windows.Forms.Application.EnableVisualStyles();
System.Windows.Forms.Application.SetCompatibleTextRenderingDefault(false);
AppBuilder.Configure<App>().UseWin32().UseSkia().SetupWithoutStarting();
System.Windows.Forms.Application.Run(new SelectorForm());
}
}
}

36
samples/interop/WindowsInteropTest/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("WindowsInteropTest")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("WindowsInteropTest")]
[assembly: AssemblyCopyright("Copyright © 2016")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c7a69145-60b6-4882-97d6-a3921dd43978")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

71
samples/interop/WindowsInteropTest/Properties/Resources.Designer.cs

@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WindowsInteropTest.Properties
{
/// <summary>
/// A strongly-typed resource class, for looking up localized strings, etc.
/// </summary>
// This class was auto-generated by the StronglyTypedResourceBuilder
// class via a tool like ResGen or Visual Studio.
// To add or remove a member, edit your .ResX file then rerun ResGen
// with the /str option, or rebuild your VS project.
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// Returns the cached ResourceManager instance used by this class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("WindowsInteropTest.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// Overrides the current thread's CurrentUICulture property for all
/// resource lookups using this strongly typed resource class.
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

117
samples/interop/WindowsInteropTest/Properties/Resources.resx

@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
samples/interop/WindowsInteropTest/Properties/Settings.Designer.cs

@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace WindowsInteropTest.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

7
samples/interop/WindowsInteropTest/Properties/Settings.settings

@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

76
samples/interop/WindowsInteropTest/SelectorForm.Designer.cs

@ -0,0 +1,76 @@
namespace WindowsInteropTest
{
partial class SelectorForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.btnEmbedToWinForms = new System.Windows.Forms.Button();
this.btnEmbedToWpf = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// btnEmbedToWinForms
//
this.btnEmbedToWinForms.Location = new System.Drawing.Point(12, 12);
this.btnEmbedToWinForms.Name = "btnEmbedToWinForms";
this.btnEmbedToWinForms.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWinForms.TabIndex = 0;
this.btnEmbedToWinForms.Text = "Embed to WinForms";
this.btnEmbedToWinForms.UseVisualStyleBackColor = true;
this.btnEmbedToWinForms.Click += new System.EventHandler(this.btnEmbedToWinForms_Click);
//
// btnEmbedToWpf
//
this.btnEmbedToWpf.Location = new System.Drawing.Point(219, 12);
this.btnEmbedToWpf.Name = "btnEmbedToWpf";
this.btnEmbedToWpf.Size = new System.Drawing.Size(201, 86);
this.btnEmbedToWpf.TabIndex = 1;
this.btnEmbedToWpf.Text = "Embed to WPF";
this.btnEmbedToWpf.UseVisualStyleBackColor = true;
this.btnEmbedToWpf.Click += new System.EventHandler(this.btnEmbedToWpf_Click);
//
// SelectorForm
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(432, 284);
this.Controls.Add(this.btnEmbedToWpf);
this.Controls.Add(this.btnEmbedToWinForms);
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
this.MaximizeBox = false;
this.Name = "SelectorForm";
this.Text = "Interop";
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Button btnEmbedToWinForms;
private System.Windows.Forms.Button btnEmbedToWpf;
}
}

30
samples/interop/WindowsInteropTest/SelectorForm.cs

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsInteropTest
{
public partial class SelectorForm : Form
{
public SelectorForm()
{
InitializeComponent();
}
private void btnEmbedToWinForms_Click(object sender, EventArgs e)
{
new EmbedToWinFormsDemo().ShowDialog(this);
}
private void btnEmbedToWpf_Click(object sender, EventArgs e)
{
new EmbedToWpfDemo().ShowDialog();
}
}
}

120
samples/interop/WindowsInteropTest/SelectorForm.resx

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

190
samples/interop/WindowsInteropTest/WindowsInteropTest.csproj

@ -0,0 +1,190 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{C7A69145-60B6-4882-97D6-A3921DD43978}</ProjectGuid>
<OutputType>WinExe</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>WindowsInteropTest</RootNamespace>
<AssemblyName>WindowsInteropTest</AssemblyName>
<TargetFrameworkVersion>v4.6</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Xaml" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<Reference Include="WindowsBase" />
</ItemGroup>
<ItemGroup>
<Compile Include="EmbedToWinFormsDemo.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="EmbedToWinFormsDemo.Designer.cs">
<DependentUpon>EmbedToWinFormsDemo.cs</DependentUpon>
</Compile>
<Compile Include="EmbedToWpfDemo.xaml.cs">
<DependentUpon>EmbedToWpfDemo.xaml</DependentUpon>
</Compile>
<Compile Include="SelectorForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="SelectorForm.Designer.cs">
<DependentUpon>SelectorForm.cs</DependentUpon>
</Compile>
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="EmbedToWinFormsDemo.resx">
<DependentUpon>EmbedToWinFormsDemo.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<EmbeddedResource Include="SelectorForm.resx">
<DependentUpon>SelectorForm.cs</DependentUpon>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\src\Avalonia.Animation\Avalonia.Animation.csproj">
<Project>{d211e587-d8bc-45b9-95a4-f297c8fa5200}</Project>
<Name>Avalonia.Animation</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Base\Avalonia.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Controls\Avalonia.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Avalonia.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.DesignerSupport\Avalonia.DesignerSupport.csproj">
<Project>{799a7bb5-3c2c-48b6-85a7-406a12c420da}</Project>
<Name>Avalonia.DesignerSupport</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Avalonia.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.DotNetFrameworkRuntime\Avalonia.DotNetFrameworkRuntime.csproj">
<Project>{4a1abb09-9047-4bd5-a4ad-a055e52c5ee0}</Project>
<Name>Avalonia.DotNetFrameworkRuntime</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Avalonia.Input</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Interactivity\Avalonia.Interactivity.csproj">
<Project>{6b0ed19d-a08b-461c-a9d9-a9ee40b0c06b}</Project>
<Name>Avalonia.Interactivity</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Layout\Avalonia.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Avalonia.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.ReactiveUI\Avalonia.ReactiveUI.csproj">
<Project>{6417b24e-49c2-4985-8db2-3ab9d898ec91}</Project>
<Name>Avalonia.ReactiveUI</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.SceneGraph\Avalonia.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Avalonia.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Styling\Avalonia.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Avalonia.Styling</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Avalonia.Themes.Default\Avalonia.Themes.Default.csproj">
<Project>{3e10a5fa-e8da-48b1-ad44-6a5b6cb7750f}</Project>
<Name>Avalonia.Themes.Default</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup.Xaml\Avalonia.Markup.Xaml.csproj">
<Project>{3e53a01a-b331-47f3-b828-4a5717e77a24}</Project>
<Name>Avalonia.Markup.Xaml</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Markup\Avalonia.Markup\Avalonia.Markup.csproj">
<Project>{6417e941-21bc-467b-a771-0de389353ce6}</Project>
<Name>Avalonia.Markup</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Skia\Avalonia.Skia.Desktop\Avalonia.Skia.Desktop.csproj">
<Project>{925dd807-b651-475f-9f7c-cbeb974ce43d}</Project>
<Name>Avalonia.Skia.Desktop</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Direct2D1\Avalonia.Direct2D1.csproj">
<Project>{3e908f67-5543-4879-a1dc-08eace79b3cd}</Project>
<Name>Avalonia.Direct2D1</Name>
</ProjectReference>
<ProjectReference Include="..\..\..\src\Windows\Avalonia.Win32\Avalonia.Win32.csproj">
<Project>{811a76cf-1cf6-440f-963b-bbe31bd72a82}</Project>
<Name>Avalonia.Win32</Name>
</ProjectReference>
<ProjectReference Include="..\..\ControlCatalog\ControlCatalog.csproj">
<Project>{d0a739b9-3c68-4ba6-a328-41606954b6bd}</Project>
<Name>ControlCatalog</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Page Include="EmbedToWpfDemo.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

26
samples/interop/WindowsInteropTest/WindowsInteropTest.v2.ncrunchproject

@ -0,0 +1,26 @@
<ProjectConfiguration>
<AutoDetectNugetBuildDependencies>true</AutoDetectNugetBuildDependencies>
<BuildPriority>1000</BuildPriority>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<AllowCodeAnalysis>false</AllowCodeAnalysis>
<IgnoreThisComponentCompletely>true</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>false</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<DetectStackOverflow>true</DetectStackOverflow>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<UseBuildPlatform />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
</ProjectConfiguration>

2
src/Android/Avalonia.Android/AndroidPlatform.cs

@ -57,7 +57,7 @@ namespace Avalonia.Android
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
public IEmbeddableWindowImpl CreateEmbeddableWindow()
{
throw new NotImplementedException();
}

7
src/Avalonia.Base/Avalonia.Base.csproj

@ -43,10 +43,9 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="Data\BindingError.cs" />
<Compile Include="Data\BindingChainNullException.cs" />
<Compile Include="Data\BindingNotification.cs" />
<Compile Include="Data\IndexerBinding.cs" />
<Compile Include="Data\IValidationStatus.cs" />
<Compile Include="Data\ObjectValidationStatus.cs" />
<Compile Include="Diagnostics\INotifyCollectionChangedDebug.cs" />
<Compile Include="Data\AssignBindingAttribute.cs" />
<Compile Include="Data\BindingOperations.cs" />
@ -116,9 +115,11 @@
<Compile Include="Threading\AvaloniaScheduler.cs" />
<Compile Include="Threading\AvaloniaSynchronizationContext.cs" />
<Compile Include="Threading\SingleThreadDispatcher.cs" />
<Compile Include="Utilities\ExceptionUtilities.cs" />
<Compile Include="Utilities\IWeakSubscriber.cs" />
<Compile Include="Utilities\MathUtilities.cs" />
<Compile Include="Utilities\TypeUtilities.cs" />
<Compile Include="Utilities\WeakObservable.cs" />
<Compile Include="Utilities\WeakSubscriptionManager.cs" />
<Compile Include="Utilities\WeakTimer.cs" />
</ItemGroup>

267
src/Avalonia.Base/AvaloniaObject.cs

@ -50,29 +50,6 @@ namespace Avalonia
/// </summary>
private EventHandler<AvaloniaPropertyChangedEventArgs> _propertyChanged;
/// <summary>
/// Defines the <see cref="ValidationStatus"/> property.
/// </summary>
public static readonly DirectProperty<AvaloniaObject, ObjectValidationStatus> ValidationStatusProperty =
AvaloniaProperty.RegisterDirect<AvaloniaObject, ObjectValidationStatus>(nameof(ValidationStatus), c => c.ValidationStatus);
private ObjectValidationStatus validationStatus;
/// <summary>
/// The current validation status of the control.
/// </summary>
public ObjectValidationStatus ValidationStatus
{
get
{
return validationStatus;
}
private set
{
SetAndRaise(ValidationStatusProperty, ref validationStatus, value);
}
}
/// <summary>
/// Initializes a new instance of the <see cref="AvaloniaObject"/> class.
/// </summary>
@ -251,6 +228,10 @@ namespace Avalonia
/// </summary>
/// <param name="property">The property.</param>
/// <returns>True if the property is set, otherwise false.</returns>
/// <remarks>
/// Checks whether a value is assigned to the property, or that there is a binding to the
/// property that is producing a value other than <see cref="AvaloniaProperty.UnsetValue"/>.
/// </remarks>
public bool IsSet(AvaloniaProperty property)
{
Contract.Requires<ArgumentNullException>(property != null);
@ -281,42 +262,11 @@ namespace Avalonia
if (property.IsDirect)
{
var accessor = (IDirectPropertyAccessor)GetRegistered(property);
LogPropertySet(property, value, priority);
accessor.SetValue(this, DirectUnsetToDefault(value, property));
SetDirectValue(property, value);
}
else
{
PriorityValue v;
var originalValue = value;
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property))
{
ThrowNotRegistered(property);
}
if (!TypeUtilities.TryCast(property.PropertyType, value, out value))
{
throw new ArgumentException(string.Format(
"Invalid value for Property '{0}': '{1}' ({2})",
property.Name,
originalValue,
originalValue?.GetType().FullName ?? "(null)"));
}
if (!_values.TryGetValue(property, out v))
{
if (value == AvaloniaProperty.UnsetValue)
{
return;
}
v = CreatePriorityValue(property);
_values.Add(property, v);
}
LogPropertySet(property, value, priority);
v.SetValue(value, (int)priority);
SetStyledValue(property, value, priority);
}
}
@ -371,7 +321,6 @@ namespace Avalonia
GetDescription(source));
IDisposable subscription = null;
IDisposable validationSubcription = null;
if (_directBindings == null)
{
@ -379,19 +328,14 @@ namespace Avalonia
}
subscription = source
.Where(x => !(x is IValidationStatus))
.Select(x => CastOrDefault(x, property.PropertyType))
.Do(_ => { }, () => _directBindings.Remove(subscription))
.Subscribe(x => DirectBindingSet(property, x));
validationSubcription = source
.OfType<IValidationStatus>()
.Subscribe(x => DataValidationChanged(property, x));
.Subscribe(x => SetDirectValue(property, x));
_directBindings.Add(subscription);
return Disposable.Create(() =>
{
validationSubcription.Dispose();
subscription.Dispose();
_directBindings.Remove(subscription);
});
@ -487,28 +431,9 @@ namespace Avalonia
}
/// <inheritdoc/>
void IPriorityValueOwner.DataValidationChanged(PriorityValue sender, IValidationStatus status)
void IPriorityValueOwner.BindingNotificationReceived(PriorityValue sender, BindingNotification notification)
{
var property = sender.Property;
DataValidationChanged(property, status);
}
/// <summary>
/// Called when the validation state on a tracked property is changed.
/// </summary>
/// <param name="property">The property whose validation state changed.</param>
/// <param name="status">The new validation state.</param>
protected virtual void DataValidationChanged(AvaloniaProperty property, IValidationStatus status)
{
}
/// <summary>
/// Updates the validation status of the current object.
/// </summary>
/// <param name="status">The new validation status.</param>
protected void UpdateValidationState(IValidationStatus status)
{
ValidationStatus = ValidationStatus.UpdateValidationStatus(status);
UpdateDataValidation(sender.Property, notification);
}
/// <inheritdoc/>
@ -542,6 +467,18 @@ namespace Avalonia
});
}
/// <summary>
/// Called to update the validation state for properties for which data validation is
/// enabled.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="status">The new validation status.</param>
protected virtual void UpdateDataValidation(
AvaloniaProperty property,
BindingNotification status)
{
}
/// <summary>
/// Called when a avalonia property changes on the object.
/// </summary>
@ -623,22 +560,27 @@ namespace Avalonia
/// <summary>
/// Tries to cast a value to a type, taking into account that the value may be a
/// <see cref="BindingError"/>.
/// <see cref="BindingNotification"/>.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="type">The type.</param>
/// <returns>The cast value, or a <see cref="BindingError"/>.</returns>
/// <returns>The cast value, or a <see cref="BindingNotification"/>.</returns>
private static object CastOrDefault(object value, Type type)
{
var error = value as BindingError;
var notification = value as BindingNotification;
if (error == null)
if (notification == null)
{
return TypeUtilities.CastOrDefault(value, type);
}
else
{
return error;
if (notification.HasValue)
{
notification.SetValue(TypeUtilities.CastOrDefault(notification.Value, type));
}
return notification;
}
}
@ -666,50 +608,6 @@ namespace Avalonia
return result;
}
/// <summary>
/// Sets a property value for a direct property binding.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <returns></returns>
private void DirectBindingSet(AvaloniaProperty property, object value)
{
var error = value as BindingError;
if (error == null)
{
SetValue(property, value);
}
else
{
if (error.UseFallbackValue)
{
SetValue(property, error.FallbackValue);
}
Logger.Error(
LogArea.Binding,
this,
"Error binding to {Target}.{Property}: {Message}",
this,
property,
error.Exception.Message);
}
}
/// <summary>
/// Converts an unset value to the default value for a direct property.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="property">The property.</param>
/// <returns>The value.</returns>
private object DirectUnsetToDefault(object value, AvaloniaProperty property)
{
return value == AvaloniaProperty.UnsetValue ?
((IDirectPropertyMetadata)property.GetMetadata(GetType())).UnsetValue :
value;
}
/// <summary>
/// Gets the default value for a property.
/// </summary>
@ -753,6 +651,109 @@ namespace Avalonia
return result;
}
/// <summary>
/// Sets the value of a direct property.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
private void SetDirectValue(AvaloniaProperty property, object value)
{
var notification = value as BindingNotification;
if (notification != null)
{
if (notification.ErrorType == BindingErrorType.Error)
{
Logger.Error(
LogArea.Binding,
this,
"Error in binding to {Target}.{Property}: {Message}",
this,
property,
ExceptionUtilities.GetMessage(notification.Error));
}
if (notification.HasValue)
{
value = notification.Value;
}
}
if (notification == null || notification.HasValue)
{
var metadata = (IDirectPropertyMetadata)property.GetMetadata(GetType());
var accessor = (IDirectPropertyAccessor)GetRegistered(property);
var finalValue = value == AvaloniaProperty.UnsetValue ?
metadata.UnsetValue : value;
LogPropertySet(property, value, BindingPriority.LocalValue);
accessor.SetValue(this, finalValue);
}
if (notification != null)
{
UpdateDataValidation(property, notification);
}
}
/// <summary>
/// Sets the value of a styled property.
/// </summary>
/// <param name="property">The property.</param>
/// <param name="value">The value.</param>
/// <param name="priority">The priority of the value.</param>
private void SetStyledValue(AvaloniaProperty property, object value, BindingPriority priority)
{
var notification = value as BindingNotification;
// We currently accept BindingNotifications for non-direct properties but we just
// strip them to their underlying value.
if (notification != null)
{
if (!notification.HasValue)
{
return;
}
else
{
value = notification.Value;
}
}
var originalValue = value;
if (!AvaloniaPropertyRegistry.Instance.IsRegistered(this, property))
{
ThrowNotRegistered(property);
}
if (!TypeUtilities.TryCast(property.PropertyType, value, out value))
{
throw new ArgumentException(string.Format(
"Invalid value for Property '{0}': '{1}' ({2})",
property.Name,
originalValue,
originalValue?.GetType().FullName ?? "(null)"));
}
PriorityValue v;
if (!_values.TryGetValue(property, out v))
{
if (value == AvaloniaProperty.UnsetValue)
{
return;
}
v = CreatePriorityValue(property);
_values.Add(property, v);
}
LogPropertySet(property, value, priority);
v.SetValue(value, (int)priority);
}
/// <summary>
/// Given a <see cref="AvaloniaProperty"/> returns a registered avalonia property that is
/// equal or throws if not found.

11
src/Avalonia.Base/AvaloniaObjectExtensions.cs

@ -216,7 +216,13 @@ namespace Avalonia
Contract.Requires<ArgumentNullException>(property != null);
Contract.Requires<ArgumentNullException>(binding != null);
var result = binding.Initiate(target, property, anchor);
var metadata = property.GetMetadata(target.GetType()) as IDirectPropertyMetadata;
var result = binding.Initiate(
target,
property,
anchor,
metadata?.EnableDataValidation ?? false);
if (result != null)
{
@ -311,7 +317,8 @@ namespace Avalonia
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null)
object anchor = null,
bool enableDataValidation = false)
{
return new InstancedBinding(_source);
}

9
src/Avalonia.Base/AvaloniaProperty.cs

@ -360,20 +360,25 @@ namespace Avalonia
/// The value to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
/// <returns>A <see cref="AvaloniaProperty{TValue}"/></returns>
public static DirectProperty<TOwner, TValue> RegisterDirect<TOwner, TValue>(
string name,
Func<TOwner, TValue> getter,
Action<TOwner, TValue> setter = null,
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.OneWay)
BindingMode defaultBindingMode = BindingMode.OneWay,
bool enableDataValidation = false)
where TOwner : IAvaloniaObject
{
Contract.Requires<ArgumentNullException>(name != null);
var metadata = new DirectPropertyMetadata<TValue>(
unsetValue: unsetValue,
defaultBindingMode: defaultBindingMode);
defaultBindingMode: defaultBindingMode,
enableDataValidation: enableDataValidation);
var result = new DirectProperty<TOwner, TValue>(name, getter, setter, metadata);
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);

85
src/Avalonia.Base/Data/BindingChainNullException.cs

@ -0,0 +1,85 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Data
{
/// <summary>
/// An exception returned through <see cref="BindingNotification"/> signalling that a
/// requested binding expression could not be evaluated because of a null in one of the links
/// of the binding chain.
/// </summary>
public class BindingChainNullException : Exception
{
private string _message;
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// </summary>
public BindingChainNullException()
{
}
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// </summary>
public BindingChainNullException(string message)
{
_message = message;
}
/// <summary>
/// Initalizes a new instance of the <see cref="BindingChainNullException"/> class.
/// </summary>
/// <param name="expression">The expression.</param>
/// <param name="expressionNullPoint">
/// The point in the expression at which the null was encountered.
/// </param>
public BindingChainNullException(string expression, string expressionNullPoint)
{
Expression = expression;
ExpressionNullPoint = expressionNullPoint;
}
/// <summary>
/// Gets the expression that could not be evaluated.
/// </summary>
public string Expression { get; protected set; }
/// <summary>
/// Gets the point in the expression at which the null was encountered.
/// </summary>
public string ExpressionNullPoint { get; protected set; }
/// <inheritdoc/>
public override string Message
{
get
{
if (_message == null)
{
_message = BuildMessage();
}
return _message;
}
}
private string BuildMessage()
{
if (Expression != null && ExpressionNullPoint != null)
{
return $"'{ExpressionNullPoint}' is null in expression '{Expression}'.";
}
else if (ExpressionNullPoint != null)
{
return $"'{ExpressionNullPoint}' is null in expression.";
}
else
{
return "Null encountered in binding expression.";
}
}
}
}

59
src/Avalonia.Base/Data/BindingError.cs

@ -1,59 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Data
{
/// <summary>
/// Represents a recoverable binding error.
/// </summary>
/// <remarks>
/// When produced by a binding source observable, informs the binding system that an error
/// occurred. It can also provide an optional fallback value to be pushed to the binding
/// target.
///
/// Instead of using <see cref="BindingError"/>, one could simply not push a value (in the
/// case of a no fallback value) or push a fallback value, but BindingError also causes an
/// error to be logged with the correct binding target.
/// </remarks>
public class BindingError
{
/// <summary>
/// Initializes a new instance of the <see cref="BindingError"/> class.
/// </summary>
/// <param name="exception">An exception describing the binding error.</param>
public BindingError(Exception exception)
{
Exception = exception;
}
/// <summary>
/// Initializes a new instance of the <see cref="BindingError"/> class.
/// </summary>
/// <param name="exception">An exception describing the binding error.</param>
/// <param name="fallbackValue">The fallback value.</param>
public BindingError(Exception exception, object fallbackValue)
{
Exception = exception;
FallbackValue = fallbackValue;
UseFallbackValue = true;
}
/// <summary>
/// Gets the exception describing the binding error.
/// </summary>
public Exception Exception { get; }
/// <summary>
/// Get the fallback value.
/// </summary>
public object FallbackValue { get; }
/// <summary>
/// Get a value indicating whether the fallback value should be pushed to the binding
/// target.
/// </summary>
public bool UseFallbackValue { get; }
}
}

282
src/Avalonia.Base/Data/BindingNotification.cs

@ -0,0 +1,282 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Data
{
/// <summary>
/// Defines the types of binding errors for a <see cref="BindingNotification"/>.
/// </summary>
public enum BindingErrorType
{
/// <summary>
/// There was no error.
/// </summary>
None,
/// <summary>
/// There was a binding error.
/// </summary>
Error,
/// <summary>
/// There was a data validation error.
/// </summary>
DataValidationError,
}
/// <summary>
/// Represents a binding notification that can be a valid binding value, or a binding or
/// data validation error.
/// </summary>
public class BindingNotification
{
/// <summary>
/// A binding notification representing the null value.
/// </summary>
public static readonly BindingNotification Null =
new BindingNotification(null);
/// <summary>
/// A binding notification representing <see cref="AvaloniaProperty.UnsetValue"/>.
/// </summary>
public static readonly BindingNotification UnsetValue =
new BindingNotification(AvaloniaProperty.UnsetValue);
// Null cannot be held in WeakReference as it's indistinguishable from an expired value so
// use this value in its place.
private static readonly object NullValue = new object();
private WeakReference<object> _value;
/// <summary>
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
/// </summary>
/// <param name="value">The binding value.</param>
public BindingNotification(object value)
{
_value = new WeakReference<object>(value ?? NullValue);
}
/// <summary>
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
/// </summary>
/// <param name="error">The binding error.</param>
/// <param name="errorType">The type of the binding error.</param>
public BindingNotification(Exception error, BindingErrorType errorType)
{
if (errorType == BindingErrorType.None)
{
throw new ArgumentException($"'errorType' may not be None");
}
Error = error;
ErrorType = errorType;
}
/// <summary>
/// Initializes a new instance of the <see cref="BindingNotification"/> class.
/// </summary>
/// <param name="error">The binding error.</param>
/// <param name="errorType">The type of the binding error.</param>
/// <param name="fallbackValue">The fallback value.</param>
public BindingNotification(Exception error, BindingErrorType errorType, object fallbackValue)
: this(error, errorType)
{
_value = new WeakReference<object>(fallbackValue ?? NullValue);
}
/// <summary>
/// Gets the value that should be passed to the target when <see cref="HasValue"/>
/// is true.
/// </summary>
/// <remarks>
/// If this property is read when <see cref="HasValue"/> is false then it will return
/// <see cref="AvaloniaProperty.UnsetValue"/>.
/// </remarks>
public object Value
{
get
{
if (_value != null)
{
object result;
if (_value.TryGetTarget(out result))
{
return result == NullValue ? null : result;
}
}
// There's the possibility of a race condition in that HasValue can return true,
// and then the value is GC'd before Value is read. We should be ok though as
// we return UnsetValue which should be a safe alternative.
return AvaloniaProperty.UnsetValue;
}
}
/// <summary>
/// Gets a value indicating whether <see cref="Value"/> should be pushed to the target.
/// </summary>
public bool HasValue => _value != null;
/// <summary>
/// Gets the error that occurred on the source, if any.
/// </summary>
public Exception Error { get; set; }
/// <summary>
/// Gets the type of error that <see cref="Error"/> represents, if any.
/// </summary>
public BindingErrorType ErrorType { get; set; }
/// <summary>
/// Compares two instances of <see cref="BindingNotification"/> for equality.
/// </summary>
/// <param name="a">The first instance.</param>
/// <param name="b">The second instance.</param>
/// <returns>true if the two instances are equal; otherwise false.</returns>
public static bool operator ==(BindingNotification a, BindingNotification b)
{
if (object.ReferenceEquals(a, b))
{
return true;
}
if ((object)a == null || (object)b == null)
{
return false;
}
return a.HasValue == b.HasValue &&
a.ErrorType == b.ErrorType &&
(!a.HasValue || object.Equals(a.Value, b.Value)) &&
(a.ErrorType == BindingErrorType.None || ExceptionEquals(a.Error, b.Error));
}
/// <summary>
/// Compares two instances of <see cref="BindingNotification"/> for inequality.
/// </summary>
/// <param name="a">The first instance.</param>
/// <param name="b">The second instance.</param>
/// <returns>true if the two instances are unequal; otherwise false.</returns>
public static bool operator !=(BindingNotification a, BindingNotification b)
{
return !(a == b);
}
/// <summary>
/// Gets a value from an object that may be a <see cref="BindingNotification"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <returns>The value.</returns>
/// <remarks>
/// If <paramref name="o"/> is a <see cref="BindingNotification"/> then returns the binding
/// notification's <see cref="Value"/>. If not, returns the object unchanged.
/// </remarks>
public static object ExtractValue(object o)
{
var notification = o as BindingNotification;
return notification != null ? notification.Value : o;
}
/// <summary>
/// Gets an exception from an object that may be a <see cref="BindingNotification"/>.
/// </summary>
/// <param name="o">The object.</param>
/// <returns>The value.</returns>
/// <remarks>
/// If <paramref name="o"/> is a <see cref="BindingNotification"/> then returns the binding
/// notification's <see cref="Error"/>. If not, returns the object unchanged.
/// </remarks>
public static object ExtractError(object o)
{
var notification = o as BindingNotification;
return notification != null ? notification.Error : o;
}
/// <summary>
/// Compares an object to an instance of <see cref="BindingNotification"/> for equality.
/// </summary>
/// <param name="obj">The object to compare.</param>
/// <returns>true if the two instances are equal; otherwise false.</returns>
public override bool Equals(object obj)
{
return Equals(obj as BindingNotification);
}
/// <summary>
/// Compares a value to an instance of <see cref="BindingNotification"/> for equality.
/// </summary>
/// <param name="other">The value to compare.</param>
/// <returns>true if the two instances are equal; otherwise false.</returns>
public bool Equals(BindingNotification other)
{
return this == other;
}
/// <summary>
/// Gets the hash code for this instance of <see cref="BindingNotification"/>.
/// </summary>
/// <returns>A hash code.</returns>
public override int GetHashCode()
{
return base.GetHashCode();
}
/// <summary>
/// Adds an error to the <see cref="BindingNotification"/>.
/// </summary>
/// <param name="e">The error to add.</param>
/// <param name="type">The error type.</param>
public void AddError(Exception e, BindingErrorType type)
{
Contract.Requires<ArgumentNullException>(e != null);
Contract.Requires<ArgumentException>(type != BindingErrorType.None);
Error = Error != null ? new AggregateException(Error, e) : e;
if (type == BindingErrorType.Error || ErrorType == BindingErrorType.Error)
{
ErrorType = BindingErrorType.Error;
}
}
/// <summary>
/// Removes the <see cref="Value"/> and makes <see cref="HasValue"/> return null.
/// </summary>
public void ClearValue()
{
_value = null;
}
/// <summary>
/// Sets the <see cref="Value"/>.
/// </summary>
public void SetValue(object value)
{
_value = new WeakReference<object>(value ?? NullValue);
}
/// <inheritdoc/>
public override string ToString()
{
switch (ErrorType)
{
case BindingErrorType.None:
return $"{{Value: {Value}}}";
default:
return HasValue ?
$"{{{ErrorType}: {Error}, Fallback: {Value}}}" :
$"{{{ErrorType}: {Error}}}";
}
}
private static bool ExceptionEquals(Exception a, Exception b)
{
return a?.GetType() == b?.GetType() &&
a?.Message == b?.Message;
}
}
}

5
src/Avalonia.Base/Data/BindingOperations.cs

@ -54,7 +54,10 @@ namespace Avalonia.Data
if (source != null)
{
return source.Take(1).Subscribe(x => target.SetValue(property, x, binding.Priority));
return source
.Where(x => BindingNotification.ExtractValue(x) != AvaloniaProperty.UnsetValue)
.Take(1)
.Subscribe(x => target.SetValue(property, x, binding.Priority));
}
else
{

4
src/Avalonia.Base/Data/IBinding.cs

@ -19,12 +19,14 @@ namespace Avalonia.Data
/// order to locate named controls or resources. The <paramref name="anchor"/> parameter
/// can be used to provice this context.
/// </param>
/// <param name="enableDataValidation">Whether data validation should be enabled.</param>
/// <returns>
/// A <see cref="InstancedBinding"/> or null if the binding could not be resolved.
/// </returns>
InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null);
object anchor = null,
bool enableDataValidation = false);
}
}

17
src/Avalonia.Base/Data/IValidationStatus.cs

@ -1,17 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
namespace Avalonia.Data
{
/// <summary>
/// Contains information on if the current object passed validation.
/// Subclasses of this class contain additional information depending on the method of validation checking.
/// </summary>
public interface IValidationStatus
{
/// <summary>
/// True when the data passes validation; otherwise, false.
/// </summary>
bool IsValid { get; }
}
}

6
src/Avalonia.Base/Data/IndexerBinding.cs

@ -21,7 +21,11 @@ namespace Avalonia.Data
public AvaloniaProperty Property { get; }
private BindingMode Mode { get; }
public InstancedBinding Initiate(IAvaloniaObject target, AvaloniaProperty targetProperty, object anchor = null)
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null,
bool enableDataValidation = false)
{
var mode = Mode == BindingMode.Default ?
targetProperty.GetMetadata(target.GetType()).DefaultBindingMode :

44
src/Avalonia.Base/Data/ObjectValidationStatus.cs

@ -1,44 +0,0 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
namespace Avalonia.Data
{
/// <summary>
/// An immutable struct that contains validation information for a <see cref="AvaloniaObject"/> that validates a single property.
/// </summary>
public struct ObjectValidationStatus : IValidationStatus
{
private Dictionary<Type, IValidationStatus> currentValidationStatus;
public bool IsValid => currentValidationStatus?.Values.All(status => status.IsValid) ?? true;
/// <summary>
/// Constructs the structure with the given validation information.
/// </summary>
/// <param name="validations">The validation information</param>
public ObjectValidationStatus(Dictionary<Type, IValidationStatus> validations)
:this()
{
currentValidationStatus = validations;
}
/// <summary>
/// Creates a new status with the updated information.
/// </summary>
/// <param name="status">The updated status information.</param>
/// <returns>The new validation status.</returns>
public ObjectValidationStatus UpdateValidationStatus(IValidationStatus status)
{
var newStatus = new Dictionary<Type, IValidationStatus>(currentValidationStatus ??
new Dictionary<Type, IValidationStatus>());
newStatus[status.GetType()] = status;
return new ObjectValidationStatus(newStatus);
}
public IEnumerable<IValidationStatus> StatusInformation => currentValidationStatus.Values;
}
}

11
src/Avalonia.Base/DirectProperty.cs

@ -85,19 +85,26 @@ namespace Avalonia
/// The value to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode for the property.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
/// <returns>The property.</returns>
public DirectProperty<TNewOwner, TValue> AddOwner<TNewOwner>(
Func<TNewOwner, TValue> getter,
Action<TNewOwner, TValue> setter = null,
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.OneWay)
BindingMode defaultBindingMode = BindingMode.OneWay,
bool enableDataValidation = false)
where TNewOwner : AvaloniaObject
{
var result = new DirectProperty<TNewOwner, TValue>(
this,
getter,
setter,
new DirectPropertyMetadata<TValue>(unsetValue, defaultBindingMode));
new DirectPropertyMetadata<TValue>(
unsetValue: unsetValue,
defaultBindingMode: defaultBindingMode,
enableDataValidation: enableDataValidation));
AvaloniaPropertyRegistry.Instance.Register(typeof(TNewOwner), result);
return result;

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

@ -17,19 +17,35 @@ namespace Avalonia
/// The value to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>
/// </param>
/// <param name="defaultBindingMode">The default binding mode.</param>
/// <param name="enableDataValidation">
/// Whether the property is interested in data validation.
/// </param>
public DirectPropertyMetadata(
TValue unsetValue = default(TValue),
BindingMode defaultBindingMode = BindingMode.Default)
BindingMode defaultBindingMode = BindingMode.Default,
bool enableDataValidation = false)
: base(defaultBindingMode)
{
UnsetValue = unsetValue;
EnableDataValidation = enableDataValidation;
}
/// <summary>
/// Gets the to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>.
/// Gets the value to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>.
/// </summary>
public TValue UnsetValue { get; private set; }
/// <summary>
/// Gets a value indicating whether the property is interested in data validation.
/// </summary>
/// <remarks>
/// Data validation is validation performed at the target of a binding, for example in a
/// view model using the INotifyDataErrorInfo interface. Only certain properties on a
/// control (such as a TextBox's Text property) will be interested in recieving data
/// validation messages so this feature must be explicitly enabled by setting this flag.
/// </remarks>
public bool EnableDataValidation { get; }
/// <inheritdoc/>
object IDirectPropertyMetadata.UnsetValue => UnsetValue;

5
src/Avalonia.Base/IDirectPropertyMetadata.cs

@ -12,5 +12,10 @@ namespace Avalonia
/// Gets the to use when the property is set to <see cref="AvaloniaProperty.UnsetValue"/>.
/// </summary>
object UnsetValue { get; }
/// <summary>
/// Gets a value indicating whether the property is interested in data validation.
/// </summary>
bool EnableDataValidation { get; }
}
}

7
src/Avalonia.Base/IPriorityValueOwner.cs

@ -19,10 +19,11 @@ namespace Avalonia
void Changed(PriorityValue sender, object oldValue, object newValue);
/// <summary>
/// Called when the validation state of a <see cref="PriorityValue"/> changes.
/// Called when a <see cref="BindingNotification"/> is received by a
/// <see cref="PriorityValue"/>.
/// </summary>
/// <param name="sender">The source of the change.</param>
/// <param name="status">The validation status.</param>
void DataValidationChanged(PriorityValue sender, IValidationStatus status);
/// <param name="notification">The notification.</param>
void BindingNotificationReceived(PriorityValue sender, BindingNotification notification);
}
}

26
src/Avalonia.Base/PriorityBindingEntry.cs

@ -93,22 +93,24 @@ namespace Avalonia
private void ValueChanged(object value)
{
var bindingError = value as BindingError;
var notification = value as BindingNotification;
if (bindingError != null)
if (notification != null)
{
_owner.Error(this, bindingError);
if (notification.HasValue)
{
Value = notification.Value;
_owner.Changed(this);
}
if (notification.ErrorType != BindingErrorType.None)
{
_owner.Error(this, notification);
}
}
var validationStatus = value as IValidationStatus;
if (validationStatus != null)
{
_owner.Validation(this, validationStatus);
}
else if (bindingError == null || bindingError.UseFallbackValue)
else
{
Value = bindingError == null ? value : bindingError.FallbackValue;
Value = value;
_owner.Changed(this);
}
}

13
src/Avalonia.Base/PriorityLevel.cs

@ -159,22 +159,11 @@ namespace Avalonia
/// </summary>
/// <param name="entry">The entry that completed.</param>
/// <param name="error">The error.</param>
public void Error(PriorityBindingEntry entry, BindingError error)
public void Error(PriorityBindingEntry entry, BindingNotification error)
{
_owner.LevelError(this, error);
}
/// <summary>
/// Invoked when an entry in <see cref="Bindings"/> reports validation status.
/// </summary>
/// <param name="entry">The entry that completed.</param>
/// <param name="validationStatus">The validation status.</param>
public void Validation(PriorityBindingEntry entry, IValidationStatus validationStatus)
{
_owner.LevelValidation(this, validationStatus);
}
/// <summary>
/// Activates the first binding that has a value.
/// </summary>

39
src/Avalonia.Base/PriorityValue.cs

@ -77,7 +77,6 @@ namespace Avalonia
/// </summary>
/// <param name="binding">The binding.</param>
/// <param name="priority">The binding priority.</param>
/// <param name="validation">Validation settings for the binding.</param>
/// <returns>
/// A disposable that will remove the binding.
/// </returns>
@ -179,31 +178,21 @@ namespace Avalonia
}
}
/// <summary>
/// Called whenever a priority level validation state changes.
/// </summary>
/// <param name="priorityLevel">The priority level of the changed entry.</param>
/// <param name="validationStatus">The validation status.</param>
public void LevelValidation(PriorityLevel priorityLevel, IValidationStatus validationStatus)
{
_owner.DataValidationChanged(this, validationStatus);
}
/// <summary>
/// Called when a priority level encounters an error.
/// </summary>
/// <param name="level">The priority level of the changed entry.</param>
/// <param name="error">The binding error.</param>
public void LevelError(PriorityLevel level, BindingError error)
public void LevelError(PriorityLevel level, BindingNotification error)
{
Logger.Log(
LogEventLevel.Error,
LogArea.Binding,
_owner,
"Error binding to {Target}.{Property}: {Message}",
"Error in binding to {Target}.{Property}: {Message}",
_owner,
Property,
error.Exception.Message);
error.Error.Message);
}
/// <summary>
@ -248,8 +237,14 @@ namespace Avalonia
/// <param name="priority">The priority level that the value came from.</param>
private void UpdateValue(object value, int priority)
{
var notification = value as BindingNotification;
object castValue;
if (notification != null)
{
value = (notification.HasValue) ? notification.Value : null;
}
if (TypeUtilities.TryCast(_valueType, value, out castValue))
{
var old = _value;
@ -261,7 +256,21 @@ namespace Avalonia
ValuePriority = priority;
_value = castValue;
_owner?.Changed(this, old, _value);
if (notification?.HasValue == true)
{
notification.SetValue(castValue);
}
if (notification == null || notification.HasValue)
{
_owner?.Changed(this, old, _value);
}
if (notification != null)
{
_owner?.BindingNotificationReceived(this, notification);
}
}
else
{

3
src/Avalonia.Base/PropertyMetadata.cs

@ -17,7 +17,8 @@ namespace Avalonia
/// Initializes a new instance of the <see cref="PropertyMetadata"/> class.
/// </summary>
/// <param name="defaultBindingMode">The default binding mode.</param>
public PropertyMetadata(BindingMode defaultBindingMode = BindingMode.Default)
public PropertyMetadata(
BindingMode defaultBindingMode = BindingMode.Default)
{
_defaultBindingMode = defaultBindingMode;
}

23
src/Avalonia.Base/Utilities/ExceptionUtilities.cs

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Avalonia.Utilities
{
internal static class ExceptionUtilities
{
public static string GetMessage(Exception e)
{
var aggregate = e as AggregateException;
if (aggregate != null)
{
return string.Join(" | ", aggregate.InnerExceptions.Select(x => x.Message));
}
return e.Message;
}
}
}

41
src/Avalonia.Base/Utilities/TypeUtilities.cs

@ -27,6 +27,21 @@ namespace Avalonia.Utilities
{ typeof(short), new List<Type> { typeof(byte) } }
};
private static readonly Type[] NumericTypes = new[]
{
typeof(Byte),
typeof(Decimal),
typeof(Double),
typeof(Int16),
typeof(Int32),
typeof(Int64),
typeof(SByte),
typeof(Single),
typeof(UInt16),
typeof(UInt32),
typeof(UInt64),
};
/// <summary>
/// Returns a value indicating whether null can be assigned to the specified type.
/// </summary>
@ -208,5 +223,31 @@ namespace Avalonia.Utilities
return null;
}
}
/// <summary>
/// Determines if a type is numeric. Nullable numeric types are considered numeric.
/// </summary>
/// <returns>
/// True if the type is numberic; otherwise false.
/// </returns>
/// <remarks>
/// Boolean is not considered numeric.
/// </remarks>
public static bool IsNumeric(Type type)
{
if (type == null)
{
return false;
}
if (type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
{
return IsNumeric(Nullable.GetUnderlyingType(type));
}
else
{
return NumericTypes.Contains(type);
}
}
}
}

54
src/Avalonia.Base/Utilities/WeakObservable.cs

@ -0,0 +1,54 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive;
using System.Reactive.Linq;
namespace Avalonia.Utilities
{
/// <summary>
/// Provides extension methods for working with weak event handlers.
/// </summary>
public static class WeakObservable
{
/// <summary>
/// Converts a .NET event conforming to the standard .NET event pattern into an observable
/// sequence, subscribing weakly.
/// </summary>
/// <typeparam name="TEventArgs">The type of the event args.</typeparam>
/// <param name="target">Object instance that exposes the event to convert.</param>
/// <param name="eventName">Name of the event to convert.</param>
/// <returns></returns>
public static IObservable<EventPattern<object, TEventArgs>> FromEventPattern<TEventArgs>(
object target,
string eventName)
where TEventArgs : EventArgs
{
Contract.Requires<ArgumentNullException>(target != null);
Contract.Requires<ArgumentNullException>(eventName != null);
return Observable.Create<EventPattern<object, TEventArgs>>(observer =>
{
var handler = new Handler<TEventArgs>(observer);
WeakSubscriptionManager.Subscribe(target, eventName, handler);
return () => WeakSubscriptionManager.Unsubscribe(target, eventName, handler);
}).Publish().RefCount();
}
private class Handler<TEventArgs> : IWeakSubscriber<TEventArgs> where TEventArgs : EventArgs
{
private IObserver<EventPattern<object, TEventArgs>> _observer;
public Handler(IObserver<EventPattern<object, TEventArgs>> observer)
{
_observer = observer;
}
public void OnEvent(object sender, TEventArgs e)
{
_observer.OnNext(new EventPattern<object, TEventArgs>(sender, e));
}
}
}
}

39
src/Avalonia.Controls/AppBuilder.cs → src/Avalonia.Controls/AppBuilderBase.cs

@ -10,7 +10,8 @@ namespace Avalonia.Controls
/// <summary>
/// Initializes up platform-specific services for an <see cref="Application"/>.
/// </summary>
public abstract class AppBuilderBase<AppBuilder> where AppBuilder : AppBuilderBase<AppBuilder>, new()
/// <typeparam name="TAppBuilder"></typeparam>
public abstract class AppBuilderBase<TAppBuilder> where TAppBuilder : AppBuilderBase<TAppBuilder>, new()
{
/// <summary>
/// Gets or sets the <see cref="IRuntimePlatform"/> instance.
@ -41,7 +42,7 @@ namespace Avalonia.Controls
/// Gets or sets a method to call before <see cref="Start{TMainWindow}"/> is called on the
/// <see cref="Application"/>.
/// </summary>
public Action<AppBuilder> BeforeStartCallback { get; set; }
public Action<TAppBuilder> BeforeStartCallback { get; set; }
protected AppBuilderBase(IRuntimePlatform platform, Action platformSevices)
{
@ -53,8 +54,8 @@ namespace Avalonia.Controls
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <typeparam name="TApp">The subclass of <see cref="Application"/> to configure.</typeparam>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public static AppBuilder Configure<TApp>()
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public static TAppBuilder Configure<TApp>()
where TApp : Application, new()
{
return Configure(new TApp());
@ -63,26 +64,26 @@ namespace Avalonia.Controls
/// <summary>
/// Begin configuring an <see cref="Application"/>.
/// </summary>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public static AppBuilder Configure(Application app)
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public static TAppBuilder Configure(Application app)
{
AvaloniaLocator.CurrentMutable.BindToSelf(app);
return new AppBuilder()
return new TAppBuilder()
{
Instance = app,
};
}
protected AppBuilder Self => (AppBuilder) this;
protected TAppBuilder Self => (TAppBuilder) this;
/// <summary>
/// Registers a callback to call before <see cref="Start{TMainWindow}"/> is called on the
/// <see cref="Application"/>.
/// </summary>
/// <param name="callback">The callback.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder BeforeStarting(Action<AppBuilder> callback)
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder BeforeStarting(Action<TAppBuilder> callback)
{
BeforeStartCallback = callback;
return Self;
@ -107,7 +108,7 @@ namespace Avalonia.Controls
/// Sets up the platform-specific services for the application, but does not run it.
/// </summary>
/// <returns></returns>
public AppBuilder SetupWithoutStarting()
public TAppBuilder SetupWithoutStarting()
{
Setup();
return Self;
@ -117,8 +118,8 @@ namespace Avalonia.Controls
/// Specifies a windowing subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the windowing subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseWindowingSubsystem(Action initializer)
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(Action initializer)
{
WindowingSubsystem = initializer;
return Self;
@ -128,15 +129,15 @@ namespace Avalonia.Controls
/// Specifies a windowing subsystem to use.
/// </summary>
/// <param name="dll">The dll in which to look for subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseWindowingSubsystem(string dll) => UseWindowingSubsystem(GetInitializer(dll));
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseWindowingSubsystem(string dll) => UseWindowingSubsystem(GetInitializer(dll));
/// <summary>
/// Specifies a rendering subsystem to use.
/// </summary>
/// <param name="initializer">The method to call to initialize the rendering subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseRenderingSubsystem(Action initializer)
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseRenderingSubsystem(Action initializer)
{
RenderingSubsystem = initializer;
return Self;
@ -146,8 +147,8 @@ namespace Avalonia.Controls
/// Specifies a rendering subsystem to use.
/// </summary>
/// <param name="dll">The dll in which to look for subsystem.</param>
/// <returns>An <see cref="AppBuilder"/> instance.</returns>
public AppBuilder UseRenderingSubsystem(string dll) => UseRenderingSubsystem(GetInitializer(dll));
/// <returns>An <typeparamref name="TAppBuilder"/> instance.</returns>
public TAppBuilder UseRenderingSubsystem(string dll) => UseRenderingSubsystem(GetInitializer(dll));
static Action GetInitializer(string assemblyName) => () =>
{

4
src/Avalonia.Controls/Avalonia.Controls.csproj

@ -43,7 +43,7 @@
<Compile Include="..\Shared\SharedAssemblyInfo.cs">
<Link>Properties\SharedAssemblyInfo.cs</Link>
</Compile>
<Compile Include="AppBuilder.cs" />
<Compile Include="AppBuilderBase.cs" />
<Compile Include="Application.cs" />
<Compile Include="Classes.cs" />
<Compile Include="ContextMenu.cs" />
@ -56,6 +56,8 @@
<Compile Include="HotkeyManager.cs" />
<Compile Include="IApplicationLifecycle.cs" />
<Compile Include="IScrollable.cs" />
<Compile Include="Embedding\EmbeddableControlRoot.cs" />
<Compile Include="Platform\IEmbeddableWindowImpl.cs" />
<Compile Include="WindowIcon.cs" />
<Compile Include="IPseudoClasses.cs" />
<Compile Include="DropDownItem.cs" />

1
src/Avalonia.Controls/Canvas.cs

@ -47,6 +47,7 @@ namespace Avalonia.Controls
/// </summary>
static Canvas()
{
ClipToBoundsProperty.OverrideDefaultValue<Canvas>(false);
AffectsCanvasArrange(LeftProperty, TopProperty, RightProperty, BottomProperty);
}

9
src/Avalonia.Controls/Control.cs

@ -108,7 +108,6 @@ namespace Avalonia.Controls
PseudoClass(IsEnabledCoreProperty, x => !x, ":disabled");
PseudoClass(IsFocusedProperty, ":focus");
PseudoClass(IsPointerOverProperty, ":pointerover");
PseudoClass(ValidationStatusProperty, status => !status.IsValid, ":invalid");
}
/// <summary>
@ -400,13 +399,6 @@ namespace Avalonia.Controls
/// </summary>
protected IPseudoClasses PseudoClasses => Classes;
/// <inheritdoc/>
protected override void DataValidationChanged(AvaloniaProperty property, IValidationStatus status)
{
base.DataValidationChanged(property, status);
ValidationStatus.UpdateValidationStatus(status);
}
/// <summary>
/// Sets the control's logical parent.
/// </summary>
@ -729,7 +721,6 @@ namespace Avalonia.Controls
_isAttachedToLogicalTree = false;
_styleDetach.OnNext(this);
this.TemplatedParent = null;
OnDetachedFromLogicalTree(e);
foreach (var child in LogicalChildren.OfType<Control>())

73
src/Avalonia.Controls/Embedding/EmbeddableControlRoot.cs

@ -0,0 +1,73 @@
using System;
using Avalonia.Controls.Platform;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.Styling;
namespace Avalonia.Controls.Embedding
{
public class EmbeddableControlRoot : TopLevel, IStyleable, IFocusScope, INameScope, IDisposable
{
public EmbeddableControlRoot(IEmbeddableWindowImpl impl) : base(impl)
{
PlatformImpl.Show();
}
public EmbeddableControlRoot() : base(PlatformManager.CreateEmbeddableWindow())
{
PlatformImpl.Show();
}
public new IEmbeddableWindowImpl PlatformImpl => (IEmbeddableWindowImpl) base.PlatformImpl;
public void Prepare()
{
EnsureInitialized();
ApplyTemplate();
PlatformImpl.Show();
LayoutManager.Instance.ExecuteInitialLayoutPass(this);
}
private void EnsureInitialized()
{
if (!this.IsInitialized)
{
var init = (ISupportInitialize)this;
init.BeginInit();
init.EndInit();
}
}
protected override Size MeasureOverride(Size availableSize)
{
base.MeasureOverride(PlatformImpl.ClientSize);
return PlatformImpl.ClientSize;
}
private readonly NameScope _nameScope = new NameScope();
public event EventHandler<NameScopeEventArgs> Registered
{
add { _nameScope.Registered += value; }
remove { _nameScope.Registered -= value; }
}
public event EventHandler<NameScopeEventArgs> Unregistered
{
add { _nameScope.Unregistered += value; }
remove { _nameScope.Unregistered -= value; }
}
public void Register(string name, object element) => _nameScope.Register(name, element);
public object Find(string name) => _nameScope.Find(name);
public void Unregister(string name) => _nameScope.Unregister(name);
Type IStyleable.StyleKey => typeof(EmbeddableControlRoot);
public void Dispose()
{
PlatformImpl.Dispose();
}
}
}

11
src/Avalonia.Controls/ItemsControl.cs

@ -285,17 +285,6 @@ namespace Avalonia.Controls
LogicalChildren.RemoveAll(toRemove);
}
/// <inheritdoc/>
protected override void OnTemplateChanged(AvaloniaPropertyChangedEventArgs e)
{
base.OnTemplateChanged(e);
if (e.NewValue == null)
{
ItemContainerGenerator?.Clear();
}
}
/// <summary>
/// Caled when the <see cref="Items"/> property changes.
/// </summary>

15
src/Avalonia.Controls/Platform/IEmbeddableWindowImpl.cs

@ -0,0 +1,15 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
namespace Avalonia.Platform
{
/// <summary>
/// Defines a platform-specific embeddable window implementation.
/// </summary>
public interface IEmbeddableWindowImpl : IWindowImpl
{
event Action LostFocus;
}
}

2
src/Avalonia.Controls/Platform/IWindowingPlatform.cs

@ -9,7 +9,7 @@ namespace Avalonia.Platform
public interface IWindowingPlatform
{
IWindowImpl CreateWindow();
IWindowImpl CreateEmbeddableWindow();
IEmbeddableWindowImpl CreateEmbeddableWindow();
IPopupImpl CreatePopup();
}
}

8
src/Avalonia.Controls/Platform/PlatformManager.cs

@ -43,6 +43,14 @@ namespace Avalonia.Controls.Platform
return s_designerMode ? platform.CreateEmbeddableWindow() : platform.CreateWindow();
}
public static IEmbeddableWindowImpl CreateEmbeddableWindow()
{
var platform = AvaloniaLocator.Current.GetService<IWindowingPlatform>();
if (platform == null)
throw new Exception("Could not CreateEmbeddableWindow(): IWindowingPlatform is not registered.");
return platform.CreateEmbeddableWindow();
}
public static IPopupImpl CreatePopup()
{
return AvaloniaLocator.Current.GetService<IWindowingPlatform>().CreatePopup();

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

@ -68,6 +68,7 @@ namespace Avalonia.Controls.Primitives
private PopupRoot _popupRoot;
private TopLevel _topLevel;
private IDisposable _nonClientListener;
bool _ignoreIsOpenChanged = false;
/// <summary>
/// Initializes static members of the <see cref="Popup"/> class.
@ -220,7 +221,11 @@ namespace Avalonia.Controls.Primitives
PopupRootCreated?.Invoke(this, EventArgs.Empty);
_popupRoot.Show();
_ignoreIsOpenChanged = true;
IsOpen = true;
_ignoreIsOpenChanged = false;
Opened?.Invoke(this, EventArgs.Empty);
}
@ -268,8 +273,13 @@ namespace Avalonia.Controls.Primitives
{
base.OnDetachedFromLogicalTree(e);
_topLevel = null;
_popupRoot?.Dispose();
_popupRoot = null;
if (_popupRoot != null)
{
((ISetLogicalParent)_popupRoot).SetParent(null);
_popupRoot.Dispose();
_popupRoot = null;
}
}
/// <summary>
@ -278,13 +288,16 @@ namespace Avalonia.Controls.Primitives
/// <param name="e">The event args.</param>
private void IsOpenChanged(AvaloniaPropertyChangedEventArgs e)
{
if ((bool)e.NewValue)
{
Open();
}
else
if (!_ignoreIsOpenChanged)
{
Close();
if ((bool)e.NewValue)
{
Open();
}
else
{
Close();
}
}
}

2
src/Avalonia.Controls/Primitives/PopupRoot.cs

@ -130,7 +130,7 @@ namespace Avalonia.Controls.Primitives
control.ApplyTemplate();
if (!(control is IPresenter && control.TemplatedParent == templatedParent))
if (!(control is IPresenter) && control.TemplatedParent == templatedParent)
{
foreach (IControl child in control.GetVisualChildren())
{

1
src/Avalonia.Controls/Properties/AssemblyInfo.cs

@ -11,6 +11,7 @@ using Avalonia.Metadata;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Embedding")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Presenters")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Shapes")]

101
src/Avalonia.Controls/TextBox.cs

@ -35,6 +35,14 @@ namespace Avalonia.Controls
o => o.CaretIndex,
(o, v) => o.CaretIndex = v);
public static readonly DirectProperty<TextBox, IEnumerable<Exception>> DataValidationErrorsProperty =
AvaloniaProperty.RegisterDirect<TextBox, IEnumerable<Exception>>(
nameof(DataValidationErrors),
o => o.DataValidationErrors);
public static readonly StyledProperty<bool> IsReadOnlyProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsReadOnly));
public static readonly DirectProperty<TextBox, int> SelectionStartProperty =
AvaloniaProperty.RegisterDirect<TextBox, int>(
nameof(SelectionStart),
@ -51,7 +59,8 @@ namespace Avalonia.Controls
TextBlock.TextProperty.AddOwner<TextBox>(
o => o.Text,
(o, v) => o.Text = v,
defaultBindingMode: BindingMode.TwoWay);
defaultBindingMode: BindingMode.TwoWay,
enableDataValidation: true);
public static readonly StyledProperty<TextAlignment> TextAlignmentProperty =
TextBlock.TextAlignmentProperty.AddOwner<TextBox>();
@ -65,9 +74,6 @@ namespace Avalonia.Controls
public static readonly StyledProperty<bool> UseFloatingWatermarkProperty =
AvaloniaProperty.Register<TextBox, bool>("UseFloatingWatermark");
public static readonly StyledProperty<bool> IsReadOnlyProperty =
AvaloniaProperty.Register<TextBox, bool>(nameof(IsReadOnly));
struct UndoRedoState : IEquatable<UndoRedoState>
{
public string Text { get; }
@ -89,6 +95,8 @@ namespace Avalonia.Controls
private bool _canScrollHorizontally;
private TextPresenter _presenter;
private UndoRedoHelper<UndoRedoState> _undoRedoHelper;
private bool _ignoreTextChanges;
private IEnumerable<Exception> _dataValidationErrors;
static TextBox()
{
@ -145,6 +153,18 @@ namespace Avalonia.Controls
}
}
public IEnumerable<Exception> DataValidationErrors
{
get { return _dataValidationErrors; }
private set { SetAndRaise(DataValidationErrorsProperty, ref _dataValidationErrors, value); }
}
public bool IsReadOnly
{
get { return GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public int SelectionStart
{
get
@ -177,7 +197,13 @@ namespace Avalonia.Controls
public string Text
{
get { return _text; }
set { SetAndRaise(TextProperty, ref _text, value); }
set
{
if (!_ignoreTextChanges)
{
SetAndRaise(TextProperty, ref _text, value);
}
}
}
public TextAlignment TextAlignment
@ -198,12 +224,6 @@ namespace Avalonia.Controls
set { SetValue(UseFloatingWatermarkProperty, value); }
}
public bool IsReadOnly
{
get { return GetValue(IsReadOnlyProperty); }
set { SetValue(IsReadOnlyProperty, value); }
}
public TextWrapping TextWrapping
{
get { return GetValue(TextWrappingProperty); }
@ -235,14 +255,6 @@ namespace Avalonia.Controls
HandleTextInput(e.Text);
}
protected override void DataValidationChanged(AvaloniaProperty property, IValidationStatus status)
{
if (property == TextProperty)
{
UpdateValidationState(status);
}
}
private void HandleTextInput(string input)
{
if (!IsReadOnly)
@ -254,7 +266,7 @@ namespace Avalonia.Controls
DeleteSelection();
caretIndex = CaretIndex;
text = Text ?? string.Empty;
Text = text.Substring(0, caretIndex) + input + text.Substring(caretIndex);
SetTextInternal(text.Substring(0, caretIndex) + input + text.Substring(caretIndex));
CaretIndex += input.Length;
SelectionStart = SelectionEnd = CaretIndex;
_undoRedoHelper.DiscardRedo();
@ -367,7 +379,8 @@ namespace Avalonia.Controls
if (!DeleteSelection() && CaretIndex > 0)
{
CaretIndex -= DeleteCharacter(CaretIndex - 1);
SetTextInternal(text.Substring(0, caretIndex - 1) + text.Substring(caretIndex));
--CaretIndex;
}
break;
@ -380,7 +393,7 @@ namespace Avalonia.Controls
if (!DeleteSelection() && caretIndex < text.Length)
{
DeleteCharacter(CaretIndex);
SetTextInternal(text.Substring(0, caretIndex) + text.Substring(caretIndex + 1));
}
break;
@ -478,6 +491,35 @@ namespace Avalonia.Controls
}
}
protected override void UpdateDataValidation(AvaloniaProperty property, BindingNotification status)
{
if (property == TextProperty)
{
var classes = (IPseudoClasses)Classes;
DataValidationErrors = UnpackException(status.Error);
classes.Set(":error", DataValidationErrors != null);
}
}
private static IEnumerable<Exception> UnpackException(Exception exception)
{
if (exception != null)
{
var aggregate = exception as AggregateException;
var exceptions = aggregate == null ?
(IEnumerable<Exception>)new[] { exception } :
aggregate.InnerExceptions;
var filtered = exceptions.Where(x => !(x is BindingChainNullException)).ToList();
if (filtered.Count > 0)
{
return filtered;
}
}
return null;
}
private int CoerceCaretIndex(int value)
{
var text = Text;
@ -663,7 +705,7 @@ namespace Avalonia.Controls
var start = Math.Min(selectionStart, selectionEnd);
var end = Math.Max(selectionStart, selectionEnd);
var text = Text;
Text = text.Substring(0, start) + text.Substring(end);
SetTextInternal(text.Substring(0, start) + text.Substring(end));
SelectionStart = SelectionEnd = CaretIndex = start;
return true;
}
@ -710,6 +752,19 @@ namespace Avalonia.Controls
return i;
}
private void SetTextInternal(string value)
{
try
{
_ignoreTextChanges = true;
SetAndRaise(TextProperty, ref _text, value);
}
finally
{
_ignoreTextChanges = false;
}
}
private void SetSelectionForControlBackspace(InputModifiers modifiers)
{
SelectionStart = CaretIndex;

23
src/Avalonia.Controls/ToolTip.cs

@ -105,20 +105,17 @@ namespace Avalonia.Controls
{
if (control != null && control.IsVisible && control.GetVisualRoot() != null)
{
if (s_popup == null)
if (s_popup != null)
{
s_popup = new PopupRoot
{
Content = new ToolTip(),
};
((ISetLogicalParent)s_popup).SetParent(control);
throw new AvaloniaInternalException("Previous ToolTip not disposed.");
}
var cp = MouseDevice.Instance?.GetPosition(control);
var position = control.PointToScreen(cp ?? new Point(0, 0)) + new Vector(0, 22);
((ToolTip)s_popup.Content).Content = GetTip(control);
s_popup = new PopupRoot();
((ISetLogicalParent)s_popup).SetParent(control);
s_popup.Content = new ToolTip { Content = GetTip(control) };
s_popup.Position = position;
s_popup.Show();
@ -148,9 +145,15 @@ namespace Avalonia.Controls
if (control == s_current)
{
if (s_popup != null && s_popup.IsVisible)
if (s_popup != null)
{
s_popup.Hide();
// Clear the ToolTip's Content in case it has control content: this will
// reset its visual parent allowing it to be used again.
((ToolTip)s_popup.Content).Content = null;
// Dispose of the popup.
s_popup.Dispose();
s_popup = null;
}
s_show.OnNext(null);

26
src/Avalonia.DotNetFrameworkRuntime/Avalonia.DotNetFrameworkRuntime.v2.ncrunchproject

@ -0,0 +1,26 @@
<ProjectConfiguration>
<AutoDetectNugetBuildDependencies>true</AutoDetectNugetBuildDependencies>
<BuildPriority>1000</BuildPriority>
<CopyReferencedAssembliesToWorkspace>false</CopyReferencedAssembliesToWorkspace>
<ConsiderInconclusiveTestsAsPassing>false</ConsiderInconclusiveTestsAsPassing>
<PreloadReferencedAssemblies>false</PreloadReferencedAssemblies>
<AllowDynamicCodeContractChecking>true</AllowDynamicCodeContractChecking>
<AllowStaticCodeContractChecking>false</AllowStaticCodeContractChecking>
<AllowCodeAnalysis>false</AllowCodeAnalysis>
<IgnoreThisComponentCompletely>false</IgnoreThisComponentCompletely>
<RunPreBuildEvents>false</RunPreBuildEvents>
<RunPostBuildEvents>false</RunPostBuildEvents>
<PreviouslyBuiltSuccessfully>true</PreviouslyBuiltSuccessfully>
<InstrumentAssembly>true</InstrumentAssembly>
<PreventSigningOfAssembly>false</PreventSigningOfAssembly>
<AnalyseExecutionTimes>true</AnalyseExecutionTimes>
<DetectStackOverflow>true</DetectStackOverflow>
<IncludeStaticReferencesInWorkspace>true</IncludeStaticReferencesInWorkspace>
<DefaultTestTimeout>60000</DefaultTestTimeout>
<UseBuildConfiguration />
<UseBuildPlatform />
<ProxyProcessPath />
<UseCPUArchitecture>AutoDetect</UseCPUArchitecture>
<MSTestThreadApartmentState>STA</MSTestThreadApartmentState>
<BuildProcessArchitecture>x86</BuildProcessArchitecture>
</ProjectConfiguration>

110
src/Avalonia.SceneGraph/Media/PathMarkupParser.cs

@ -17,21 +17,13 @@ namespace Avalonia.Media
private static readonly Dictionary<char, Command> Commands = new Dictionary<char, Command>
{
{ 'F', Command.FillRule },
{ 'f', Command.FillRule },
{ 'M', Command.Move },
{ 'm', Command.MoveRelative },
{ 'L', Command.Line },
{ 'l', Command.LineRelative },
{ 'H', Command.HorizontalLine },
{ 'h', Command.HorizontalLineRelative },
{ 'V', Command.VerticalLine },
{ 'v', Command.VerticalLineRelative },
{ 'C', Command.CubicBezierCurve },
{ 'c', Command.CubicBezierCurveRelative },
{ 'A', Command.Arc },
{ 'a', Command.Arc },
{ 'Z', Command.Close },
{ 'z', Command.Close },
};
private static readonly Dictionary<char, FillRule> FillRules = new Dictionary<char, FillRule>
@ -63,18 +55,12 @@ namespace Avalonia.Media
None,
FillRule,
Move,
MoveRelative,
Line,
LineRelative,
HorizontalLine,
HorizontalLineRelative,
VerticalLine,
VerticalLineRelative,
CubicBezierCurve,
CubicBezierCurveRelative,
Arc,
Close,
Eof,
}
/// <summary>
@ -87,11 +73,11 @@ namespace Avalonia.Media
using (StringReader reader = new StringReader(s))
{
Command lastCommand = Command.None;
Command command;
Command command = Command.None;
Point point = new Point();
bool relative = false;
while ((command = ReadCommand(reader, lastCommand)) != Command.Eof)
while (ReadCommand(reader, ref command, ref relative))
{
switch (command)
{
@ -100,72 +86,58 @@ namespace Avalonia.Media
break;
case Command.Move:
case Command.MoveRelative:
if (openFigure)
{
_context.EndFigure(false);
}
point = command == Command.Move ?
ReadPoint(reader) :
ReadRelativePoint(reader, point);
point = ReadPoint(reader, point, relative);
_context.BeginFigure(point, true);
openFigure = true;
break;
case Command.Line:
point = ReadPoint(reader);
_context.LineTo(point);
break;
case Command.LineRelative:
point = ReadRelativePoint(reader, point);
point = ReadPoint(reader, point, relative);
_context.LineTo(point);
break;
case Command.HorizontalLine:
point = point.WithX(ReadDouble(reader));
_context.LineTo(point);
break;
if (!relative)
{
point = point.WithX(ReadDouble(reader));
}
else
{
point = new Point(point.X + ReadDouble(reader), point.Y);
}
case Command.HorizontalLineRelative:
point = new Point(point.X + ReadDouble(reader), point.Y);
_context.LineTo(point);
break;
case Command.VerticalLine:
point = point.WithY(ReadDouble(reader));
_context.LineTo(point);
break;
if (!relative)
{
point = point.WithY(ReadDouble(reader));
}
else
{
point = new Point(point.X, point.Y + ReadDouble(reader));
}
case Command.VerticalLineRelative:
point = new Point(point.X, point.Y + ReadDouble(reader));
_context.LineTo(point);
break;
case Command.CubicBezierCurve:
{
Point point1 = ReadPoint(reader);
Point point2 = ReadPoint(reader);
point = ReadPoint(reader);
Point point1 = ReadPoint(reader, point, relative);
Point point2 = ReadPoint(reader, point, relative);
point = ReadPoint(reader, point, relative);
_context.CubicBezierTo(point1, point2, point);
break;
}
case Command.CubicBezierCurveRelative:
{
Point point1 = ReadRelativePoint(reader, point);
Point point2 = ReadRelativePoint(reader, point);
_context.CubicBezierTo(point, point1, point2);
point = point2;
break;
}
case Command.Arc:
{
//example: A10,10 0 0,0 10,20
//format - size rotationAngle isLargeArcFlag sweepDirectionFlag endPoint
Size size = ReadSize(reader);
ReadSeparator(reader);
double rotationAngle = ReadDouble(reader);
@ -173,7 +145,7 @@ namespace Avalonia.Media
bool isLargeArc = ReadBool(reader);
ReadSeparator(reader);
SweepDirection sweepDirection = ReadBool(reader) ? SweepDirection.Clockwise : SweepDirection.CounterClockwise;
point = ReadPoint(reader);
point = ReadPoint(reader, point, relative);
_context.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);
break;
@ -187,8 +159,6 @@ namespace Avalonia.Media
default:
throw new NotSupportedException("Unsupported command");
}
lastCommand = command;
}
if (openFigure)
@ -198,7 +168,10 @@ namespace Avalonia.Media
}
}
private static Command ReadCommand(StringReader reader, Command lastCommand)
private static bool ReadCommand(
StringReader reader,
ref Command command,
ref bool relative)
{
ReadWhitespace(reader);
@ -206,19 +179,19 @@ namespace Avalonia.Media
if (i == -1)
{
return Command.Eof;
return false;
}
else
{
char c = (char)i;
Command command = Command.None;
Command next = Command.None;
if (!Commands.TryGetValue(c, out command))
if (!Commands.TryGetValue(char.ToUpperInvariant(c), out next))
{
if ((char.IsDigit(c) || c == '.' || c == '+' || c == '-') &&
(lastCommand != Command.None))
(command != Command.None))
{
return lastCommand;
return true;
}
else
{
@ -226,8 +199,10 @@ namespace Avalonia.Media
}
}
command = next;
relative = char.IsLower(c);
reader.Read();
return command;
return true;
}
}
@ -297,12 +272,17 @@ namespace Avalonia.Media
return double.Parse(b.ToString(), CultureInfo.InvariantCulture);
}
private static Point ReadPoint(StringReader reader)
private static Point ReadPoint(StringReader reader, Point current, bool relative)
{
if (!relative)
{
current = new Point();
}
ReadWhitespace(reader);
double x = ReadDouble(reader);
double x = current.X + ReadDouble(reader);
ReadSeparator(reader);
double y = ReadDouble(reader);
double y = current.Y + ReadDouble(reader);
return new Point(x, y);
}

2
src/Avalonia.Themes.Default/Accents/BaseLight.xaml

@ -18,6 +18,8 @@
<SolidColorBrush x:Key="ThemeAccentBrush2">#99119EDA</SolidColorBrush>
<SolidColorBrush x:Key="ThemeAccentBrush3">#66119EDA</SolidColorBrush>
<SolidColorBrush x:Key="ThemeAccentBrush4">#33119EDA</SolidColorBrush>
<SolidColorBrush x:Key="ErrorBrush">Red</SolidColorBrush>
<SolidColorBrush x:Key="ErrorBrushLight">#10ff0000</SolidColorBrush>
<sys:Double x:Key="ThemeBorderThickness">2</sys:Double>
<sys:Double x:Key="ThemeDisabledOpacity">0.5</sys:Double>

5
src/Avalonia.Themes.Default/Avalonia.Themes.Default.csproj

@ -208,6 +208,11 @@
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="EmbeddableControlRoot.xaml">
<SubType>Designer</SubType>
</EmbeddedResource>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.

5
src/Avalonia.Themes.Default/DefaultTheme.xaml

@ -1,4 +1,7 @@
<Styles xmlns="https://github.com/avaloniaui">
<!-- Define ToolTip first so its styles can be overriden by other controls (e.g. TextBox) -->
<StyleInclude Source="resm:Avalonia.Themes.Default.ToolTip.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.FocusAdorner.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Button.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Carousel.xaml?assembly=Avalonia.Themes.Default"/>
@ -28,8 +31,8 @@
<StyleInclude Source="resm:Avalonia.Themes.Default.TextBox.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ToggleButton.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Expander.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.ToolTip.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TreeView.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.TreeViewItem.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.Window.xaml?assembly=Avalonia.Themes.Default"/>
<StyleInclude Source="resm:Avalonia.Themes.Default.EmbeddableControlRoot.xaml?assembly=Avalonia.Themes.Default"/>
</Styles>

8
src/Avalonia.Themes.Default/DropDown.xaml

@ -10,10 +10,10 @@
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid ColumnDefinitions="*,Auto">
<ContentPresenter Content="{TemplateBinding SelectionBoxItem}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<ContentControl Content="{TemplateBinding SelectionBoxItem}"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"/>
<ToggleButton Name="toggle"
BorderThickness="0"
Background="Transparent"

17
src/Avalonia.Themes.Default/EmbeddableControlRoot.xaml

@ -0,0 +1,17 @@
<Style xmlns="https://github.com/avaloniaui" Selector="EmbeddableControlRoot">
<Setter Property="Background" Value="{StyleResource ThemeBackgroundBrush}"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="{StyleResource FontSizeNormal}"/>
<Setter Property="Template">
<ControlTemplate>
<Border Background="{TemplateBinding Background}">
<AdornerDecorator>
<ContentPresenter Name="PART_ContentPresenter"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Margin="{TemplateBinding Padding}"/>
</AdornerDecorator>
</Border>
</ControlTemplate>
</Setter>
</Style>

34
src/Avalonia.Themes.Default/TextBox.xaml

@ -27,10 +27,19 @@
</MultiBinding>
</TextBlock.IsVisible>
</TextBlock>
<ScrollViewer CanScrollHorizontally="{TemplateBinding CanScrollHorizontally}"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<DockPanel LastChildFill="True">
<Canvas Name="error" DockPanel.Dock="Right" Width="14" Height="14" Margin="4 0 1 0">
<ToolTip.Tip>
<ItemsControl Items="{TemplateBinding DataValidationErrors}" MemberSelector="Message"/>
</ToolTip.Tip>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2" Stroke="{StyleResource ErrorBrush}" StrokeThickness="2"/>
</Canvas>
<ScrollViewer CanScrollHorizontally="{TemplateBinding CanScrollHorizontally}"
HorizontalScrollBarVisibility="{TemplateBinding (ScrollViewer.HorizontalScrollBarVisibility)}"
VerticalScrollBarVisibility="{TemplateBinding (ScrollViewer.VerticalScrollBarVisibility)}">
<Panel>
<TextBlock Name="watermark"
Opacity="0.5"
@ -45,8 +54,9 @@
TextWrapping="{TemplateBinding TextWrapping}"/>
</Panel>
</ScrollViewer>
</DockPanel>
</DockPanel>
</Border>
</ControlTemplate>
</Setter>
@ -57,7 +67,17 @@
<Style Selector="TextBox:focus /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ThemeBorderDarkBrush}"/>
</Style>
<Style Selector="TextBox:invalid /template/ Border#border">
<Setter Property="BorderBrush" Value="Red"/>
<Style Selector="TextBox:error /template/ Border#border">
<Setter Property="BorderBrush" Value="{StyleResource ErrorBrush}"/>
</Style>
<Style Selector="TextBox /template/ Canvas#error">
<Setter Property="IsVisible" Value="False"/>
</Style>
<Style Selector="TextBox:error /template/ Canvas#error">
<Setter Property="IsVisible" Value="True"/>
</Style>
<Style Selector="TextBox /template/ ToolTip">
<Setter Property="Background" Value="{StyleResource ErrorBrushLight}"/>
<Setter Property="BorderBrush" Value="{StyleResource ErrorBrush}"/>
</Style>
</Styles>

22
src/Gtk/Avalonia.Cairo/CairoPlatform.cs

@ -53,13 +53,21 @@ namespace Avalonia.Cairo
public IRenderTarget CreateRenderer(IPlatformHandle handle)
{
var window = handle as Gtk.Window;
if (window == null)
throw new NotSupportedException(string.Format(
"Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window",
handle.HandleDescriptor));
window.DoubleBuffered = true;
return new RenderTarget(window);
if (window != null)
{
window.DoubleBuffered = true;
return new RenderTarget(window);
}
var area = handle as Gtk.DrawingArea;
if (area != null)
{
area.DoubleBuffered = true;
return new RenderTarget(area);
}
throw new NotSupportedException(string.Format(
"Don't know how to create a Cairo renderer from a '{0}' handle which isn't Gtk.Window or Gtk.DrawingArea",
handle.HandleDescriptor));
}
public IRenderTargetBitmapImpl CreateRenderTargetBitmap(int width, int height)

23
src/Gtk/Avalonia.Cairo/RenderTarget.cs

@ -7,6 +7,7 @@ using Avalonia.Cairo.Media;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Gtk;
using DrawingContext = Avalonia.Media.DrawingContext;
namespace Avalonia.Cairo
@ -20,6 +21,7 @@ namespace Avalonia.Cairo
{
private readonly Surface _surface;
private readonly Gtk.Window _window;
private readonly Gtk.DrawingArea _area;
/// <summary>
/// Initializes a new instance of the <see cref="RenderTarget"/> class.
@ -37,19 +39,28 @@ namespace Avalonia.Cairo
_surface = surface;
}
public RenderTarget(DrawingArea area)
{
_area = area;
}
/// <summary>
/// Creates a cairo surface that targets a platform-specific resource.
/// </summary>
/// <returns>A surface wrapped in an <see cref="Avalonia.Media.DrawingContext"/>.</returns>
public DrawingContext CreateDrawingContext()
public DrawingContext CreateDrawingContext() => new DrawingContext(CreateMediaDrawingContext());
public IDrawingContextImpl CreateMediaDrawingContext()
{
var ctx = _surface != null
? new Media.DrawingContext(_surface)
: new Media.DrawingContext(_window.GdkWindow);
return new DrawingContext(ctx);
if (_window != null)
return new Media.DrawingContext(_window.GdkWindow);
if (_surface != null)
return new Media.DrawingContext(_surface);
if (_area != null)
return new Media.DrawingContext(_area.GdkWindow);
throw new InvalidOperationException("Unspecified render target");
}
public void Dispose() => _surface?.Dispose();
}
}

8
src/Gtk/Avalonia.Gtk/Avalonia.Gtk.csproj

@ -46,6 +46,8 @@
</ItemGroup>
<ItemGroup>
<Compile Include="ClipboardImpl.cs" />
<Compile Include="EmbeddableImpl.cs" />
<Compile Include="Embedding\GtkAvaloniaControlHost.cs" />
<Compile Include="IconImpl.cs" />
<Compile Include="SystemDialogImpl.cs" />
<Compile Include="CursorFactory.cs" />
@ -54,8 +56,10 @@
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="GtkPlatform.cs" />
<Compile Include="WindowImpl.cs" />
<Compile Include="WindowImplBase.cs" />
<Compile Include="Input\GtkKeyboardDevice.cs" />
<Compile Include="Input\GtkMouseDevice.cs" />
<Compile Include="Windows.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -67,6 +71,10 @@
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Avalonia.Base</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Diagnostics\Avalonia.Diagnostics.csproj">
<Project>{7062ae20-5dcc-4442-9645-8195bdece63e}</Project>
<Name>Avalonia.Diagnostics</Name>
</ProjectReference>
<ProjectReference Include="..\..\Avalonia.Input\Avalonia.Input.csproj">
<Project>{62024B2D-53EB-4638-B26B-85EEAA54866E}</Project>
<Name>Avalonia.Input</Name>

70
src/Gtk/Avalonia.Gtk/EmbeddableImpl.cs

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Disposables;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
using Gdk;
using Gtk;
using Action = System.Action;
using WindowEdge = Avalonia.Controls.WindowEdge;
namespace Avalonia.Gtk
{
class EmbeddableImpl : WindowImplBase, IEmbeddableWindowImpl
{
public event Action LostFocus;
public EmbeddableImpl(DrawingArea area) : base(area)
{
area.Events = EventMask.AllEventsMask;
area.SizeAllocated += Plug_SizeAllocated;
}
public EmbeddableImpl() : this(new PlatformHandleAwareDrawingArea())
{
}
private void Plug_SizeAllocated(object o, SizeAllocatedArgs args)
{
Resized?.Invoke(new Size(args.Allocation.Width, args.Allocation.Height));
}
public override Size ClientSize
{
get { return new Size(Widget.Allocation.Width, Widget.Allocation.Height); }
set {}
}
//Stubs are needed for future GTK designer embedding support
public override void SetTitle(string title)
{
}
public override IDisposable ShowDialog() => Disposable.Create(() => { });
public override void SetSystemDecorations(bool enabled)
{
}
public override void SetIcon(IWindowIconImpl icon)
{
}
public override void BeginMoveDrag()
{
}
public override void BeginResizeDrag(WindowEdge edge)
{
}
public override Point Position
{
get { return new Point(); }
set {}
}
}
}

77
src/Gtk/Avalonia.Gtk/Embedding/GtkAvaloniaControlHost.cs

@ -0,0 +1,77 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Controls;
using Avalonia.Controls.Embedding;
using Avalonia.Diagnostics;
using Avalonia.Input;
using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Platform;
using Avalonia.VisualTree;
using Gdk;
using Gtk;
namespace Avalonia.Gtk.Embedding
{
public class GtkAvaloniaControlHost : DrawingArea, IPlatformHandle
{
private EmbeddableControlRoot _root;
public GtkAvaloniaControlHost()
{
_root = new EmbeddableControlRoot(new EmbeddableImpl(this));
_root.Prepare();
if (_root.IsFocused)
Unfocus();
_root.GotFocus += RootGotFocus;
CanFocus = true;
}
void Unfocus()
{
var focused = (IVisual)FocusManager.Instance.Current;
if (focused == null)
return;
while (focused.VisualParent != null)
focused = focused.VisualParent;
if (focused == _root)
KeyboardDevice.Instance.SetFocusedElement(null, NavigationMethod.Unspecified, InputModifiers.None);
}
protected override bool OnFocusOutEvent(EventFocus evnt)
{
Unfocus();
return false;
}
private void RootGotFocus(object sender, RoutedEventArgs e)
{
this.HasFocus = true;
GdkWindow.Focus(0);
}
private Control _content;
public Control Content
{
get { return _content; }
set
{
_content = value;
if (_root != null)
{
_root.Content = value;
_root.Prepare();
}
}
}
IntPtr IPlatformHandle.Handle => PlatformHandleAwareWindow.GetNativeWindow(GdkWindow);
string IPlatformHandle.HandleDescriptor => "HWND";
}
}

5
src/Gtk/Avalonia.Gtk/GtkPlatform.cs

@ -103,10 +103,7 @@ namespace Avalonia.Gtk
return new WindowImpl();
}
public IWindowImpl CreateEmbeddableWindow()
{
throw new NotSupportedException();
}
public IEmbeddableWindowImpl CreateEmbeddableWindow() => new EmbeddableImpl();
public IPopupImpl CreatePopup()
{

4
src/Gtk/Avalonia.Gtk/SystemDialogImpl.cs

@ -15,7 +15,7 @@ namespace Avalonia.Gtk
public Task<string[]> ShowFileDialogAsync(FileDialog dialog, IWindowImpl parent)
{
var tcs = new TaskCompletionSource<string[]>();
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent),
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window,
dialog is OpenFileDialog
? FileChooserAction.Open
: FileChooserAction.Save,
@ -57,7 +57,7 @@ namespace Avalonia.Gtk
public Task<string> ShowFolderDialogAsync(OpenFolderDialog dialog, IWindowImpl parent)
{
var tcs = new TaskCompletionSource<string>();
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImpl)parent),
var dlg = new global::Gtk.FileChooserDialog(dialog.Title, ((WindowImplBase)parent).Widget.Toplevel as Window,
FileChooserAction.SelectFolder,
"Cancel", ResponseType.Cancel,
"Select Folder", ResponseType.Accept)

374
src/Gtk/Avalonia.Gtk/WindowImpl.cs

@ -1,404 +1,118 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using Gdk;
using Avalonia.Controls;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Input;
using Avalonia.Threading;
using Action = System.Action;
using WindowEdge = Avalonia.Controls.WindowEdge;
using Gdk;
namespace Avalonia.Gtk
{
using Gtk = global::Gtk;
public class WindowImpl : Gtk.Window, IWindowImpl, IPlatformHandle
public class WindowImpl : WindowImplBase
{
private IInputRoot _inputRoot;
private Gtk.Window _window;
private Gtk.Window Window => _window ?? (_window = (Gtk.Window) Widget);
private Size _lastClientSize;
private Gtk.IMContext _imContext;
private uint _lastKeyEventTimestamp;
private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
public WindowImpl()
: base(Gtk.WindowType.Toplevel)
public WindowImpl(Gtk.WindowType type) : base(new PlatformHandleAwareWindow(type))
{
DefaultSize = new Gdk.Size(900, 480);
Init();
}
public WindowImpl(Gtk.WindowType type)
: base(type)
public WindowImpl()
: base(new PlatformHandleAwareWindow(Gtk.WindowType.Toplevel) {DefaultSize = new Gdk.Size(900, 480)})
{
Init();
}
private void Init()
void Init()
{
Events = EventMask.PointerMotionMask |
EventMask.ButtonPressMask |
EventMask.ButtonReleaseMask;
_imContext = new Gtk.IMMulticontext();
_imContext.Commit += ImContext_Commit;
DoubleBuffered = false;
Realize();
Window.FocusActivated += OnFocusActivated;
Window.ConfigureEvent += OnConfigureEvent;
_lastClientSize = ClientSize;
}
protected override void OnRealized ()
{
base.OnRealized ();
_imContext.ClientWindow = this.GdkWindow;
}
public Size ClientSize
private Size _lastClientSize;
void OnConfigureEvent(object o, Gtk.ConfigureEventArgs args)
{
get
{
int width;
int height;
GetSize(out width, out height);
return new Size(width, height);
}
set
{
Resize((int)value.Width, (int)value.Height);
}
}
var evnt = args.Event;
args.RetVal = true;
var newSize = new Size(evnt.Width, evnt.Height);
public Size MaxClientSize
{
get
if (newSize != _lastClientSize)
{
// TODO: This should take into account things such as taskbar and window border
// thickness etc.
return new Size(Screen.Width, Screen.Height);
Resized(newSize);
_lastClientSize = newSize;
}
}
public Avalonia.Controls.WindowState WindowState
public override Size ClientSize
{
get
{
switch (GdkWindow.State)
{
case Gdk.WindowState.Iconified:
return Controls.WindowState.Minimized;
case Gdk.WindowState.Maximized:
return Controls.WindowState.Maximized;
default:
return Controls.WindowState.Normal;
}
int width;
int height;
Window.GetSize(out width, out height);
return new Size(width, height);
}
set
{
switch (value)
{
case Controls.WindowState.Minimized:
GdkWindow.Iconify();
break;
case Controls.WindowState.Maximized:
GdkWindow.Maximize();
break;
case Controls.WindowState.Normal:
GdkWindow.Deiconify();
GdkWindow.Unmaximize();
break;
}
Window.Resize((int)value.Width, (int)value.Height);
}
}
public double Scaling => 1;
IPlatformHandle ITopLevelImpl.Handle => this;
[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow);
[DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
[DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)]
extern static IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow);
IntPtr _nativeWindow;
IntPtr GetNativeWindow()
public override void SetTitle(string title)
{
IntPtr h = GdkWindow.Handle;
if (_nativeWindow != IntPtr.Zero)
return _nativeWindow;
//Try whatever backend that works
try
{
return _nativeWindow = gdk_quartz_window_get_nswindow(h);
}
catch
{
}
try
{
return _nativeWindow = gdk_x11_drawable_get_xid(h);
}
catch
{
}
return _nativeWindow = gdk_win32_drawable_get_handle(h);
Window.Title = title;
}
IntPtr IPlatformHandle.Handle => GetNativeWindow();
public string HandleDescriptor => "HWND";
public Action Activated { get; set; }
public Action Closed { get; set; }
public Action Deactivated { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
public void Invalidate(Rect rect)
{
if (base.GdkWindow != null)
base.GdkWindow.InvalidateRect(
new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
}
public Point PointToClient(Point point)
void OnFocusActivated(object sender, EventArgs eventArgs)
{
int x, y;
GdkWindow.GetDeskrelativeOrigin(out x, out y);
return new Point(point.X - x, point.Y - y);
}
public Point PointToScreen(Point point)
{
int x, y;
GdkWindow.GetDeskrelativeOrigin(out x, out y);
return new Point(point.X + x, point.Y + y);
}
public void SetInputRoot(IInputRoot inputRoot)
{
_inputRoot = inputRoot;
}
public void SetTitle(string title)
{
Title = title;
}
public void SetCursor(IPlatformHandle cursor)
{
GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
Activated();
}
public void BeginMoveDrag()
public override void BeginMoveDrag()
{
int x, y;
ModifierType mod;
Screen.RootWindow.GetPointer(out x, out y, out mod);
BeginMoveDrag(1, x, y, 0);
Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
Window.BeginMoveDrag(1, x, y, 0);
}
public void BeginResizeDrag(WindowEdge edge)
public override void BeginResizeDrag(Controls.WindowEdge edge)
{
int x, y;
ModifierType mod;
Screen.RootWindow.GetPointer(out x, out y, out mod);
BeginResizeDrag((Gdk.WindowEdge) (int) edge, 1, x, y, 0);
Window.Screen.RootWindow.GetPointer(out x, out y, out mod);
Window.BeginResizeDrag((Gdk.WindowEdge)(int)edge, 1, x, y, 0);
}
public Point Position
public override Point Position
{
get
{
int x, y;
GetPosition(out x, out y);
Window.GetPosition(out x, out y);
return new Point(x, y);
}
set
{
Move((int)value.X, (int)value.Y);
Window.Move((int)value.X, (int)value.Y);
}
}
public IDisposable ShowDialog()
public override IDisposable ShowDialog()
{
Modal = true;
Show();
Window.Modal = true;
Window.Show();
return Disposable.Empty;
}
public void SetSystemDecorations(bool enabled) => Decorated = enabled;
void ITopLevelImpl.Activate()
{
Activate();
}
private static InputModifiers GetModifierKeys(ModifierType state)
{
var rv = InputModifiers.None;
if (state.HasFlag(ModifierType.ControlMask))
rv |= InputModifiers.Control;
if (state.HasFlag(ModifierType.ShiftMask))
rv |= InputModifiers.Shift;
if (state.HasFlag(ModifierType.Mod1Mask))
rv |= InputModifiers.Control;
if(state.HasFlag(ModifierType.Button1Mask))
rv |= InputModifiers.LeftMouseButton;
if (state.HasFlag(ModifierType.Button2Mask))
rv |= InputModifiers.RightMouseButton;
if (state.HasFlag(ModifierType.Button3Mask))
rv |= InputModifiers.MiddleMouseButton;
return rv;
}
protected override bool OnButtonPressEvent(EventButton evnt)
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
evnt.Button == 1
? RawMouseEventType.LeftButtonDown
: evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnScrollEvent(EventScroll evnt)
{
double step = 1;
var delta = new Vector();
if (evnt.Direction == ScrollDirection.Down)
delta = new Vector(0, -step);
else if (evnt.Direction == ScrollDirection.Up)
delta = new Vector(0, step);
else if (evnt.Direction == ScrollDirection.Right)
delta = new Vector(-step, 0);
if (evnt.Direction == ScrollDirection.Left)
delta = new Vector(step, 0);
var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State));
Input(e);
return base.OnScrollEvent(evnt);
}
protected override bool OnButtonReleaseEvent(EventButton evnt)
{
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
evnt.Button == 1
? RawMouseEventType.LeftButtonUp
: evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp,
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnConfigureEvent(EventConfigure evnt)
{
var newSize = new Size(evnt.Width, evnt.Height);
if (newSize != _lastClientSize)
{
Resized(newSize);
_lastClientSize = newSize;
}
return true;
}
protected override void OnDestroyed()
{
Closed();
}
private bool ProcessKeyEvent(EventKey evnt)
{
_lastKeyEventTimestamp = evnt.Time;
if (_imContext.FilterKeypress(evnt))
return true;
var e = new RawKeyEventArgs(
GtkKeyboardDevice.Instance,
evnt.Time,
evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
Input(e);
return true;
}
protected override bool OnKeyPressEvent(EventKey evnt) => ProcessKeyEvent(evnt);
protected override bool OnKeyReleaseEvent(EventKey evnt) => ProcessKeyEvent(evnt);
private void ImContext_Commit(object o, Gtk.CommitArgs args)
{
Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
}
protected override bool OnExposeEvent(EventExpose evnt)
{
Paint(evnt.Area.ToAvalonia());
return true;
}
protected override void OnFocusActivated()
{
Activated();
}
protected override bool OnMotionNotifyEvent(EventMotion evnt)
{
var position = new Point(evnt.X, evnt.Y);
GtkMouseDevice.Instance.SetClientPosition(position);
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
RawMouseEventType.Move,
position, GetModifierKeys(evnt.State));
Input(e);
return true;
}
public override void SetSystemDecorations(bool enabled) => Window.Decorated = enabled;
public void SetIcon(IWindowIconImpl icon)
public override void SetIcon(IWindowIconImpl icon)
{
Icon = ((IconImpl)icon).Pixbuf;
Window.Icon = ((IconImpl)icon).Pixbuf;
}
}
}
}

310
src/Gtk/Avalonia.Gtk/WindowImplBase.cs

@ -0,0 +1,310 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
using System.Reactive.Disposables;
using System.Runtime.InteropServices;
using Gdk;
using Avalonia.Controls;
using Avalonia.Input.Raw;
using Avalonia.Platform;
using Avalonia.Input;
using Avalonia.Threading;
using Action = System.Action;
using WindowEdge = Avalonia.Controls.WindowEdge;
namespace Avalonia.Gtk
{
using Gtk = global::Gtk;
public abstract class WindowImplBase : IWindowImpl
{
private IInputRoot _inputRoot;
protected Gtk.Widget _window;
public Gtk.Widget Widget => _window;
private Gtk.IMContext _imContext;
private uint _lastKeyEventTimestamp;
private static readonly Gdk.Cursor DefaultCursor = new Gdk.Cursor(CursorType.LeftPtr);
protected WindowImplBase(Gtk.Widget window)
{
_window = window;
Init();
}
void Init()
{
Handle = _window as IPlatformHandle;
_window.Events = EventMask.AllEventsMask;
_imContext = new Gtk.IMMulticontext();
_imContext.Commit += ImContext_Commit;
_window.Realized += OnRealized;
_window.DoubleBuffered = false;
_window.Realize();
_window.ButtonPressEvent += OnButtonPressEvent;
_window.ButtonReleaseEvent += OnButtonReleaseEvent;
_window.ScrollEvent += OnScrollEvent;
_window.Destroyed += OnDestroyed;
_window.KeyPressEvent += OnKeyPressEvent;
_window.KeyReleaseEvent += OnKeyReleaseEvent;
_window.ExposeEvent += OnExposeEvent;
_window.MotionNotifyEvent += OnMotionNotifyEvent;
}
public IPlatformHandle Handle { get; private set; }
void OnRealized (object sender, EventArgs eventArgs)
{
_imContext.ClientWindow = _window.GdkWindow;
}
public abstract Size ClientSize { get; set; }
public Size MaxClientSize
{
get
{
// TODO: This should take into account things such as taskbar and window border
// thickness etc.
return new Size(_window.Screen.Width, _window.Screen.Height);
}
}
public Avalonia.Controls.WindowState WindowState
{
get
{
switch (_window.GdkWindow.State)
{
case Gdk.WindowState.Iconified:
return Controls.WindowState.Minimized;
case Gdk.WindowState.Maximized:
return Controls.WindowState.Maximized;
default:
return Controls.WindowState.Normal;
}
}
set
{
switch (value)
{
case Controls.WindowState.Minimized:
_window.GdkWindow.Iconify();
break;
case Controls.WindowState.Maximized:
_window.GdkWindow.Maximize();
break;
case Controls.WindowState.Normal:
_window.GdkWindow.Deiconify();
_window.GdkWindow.Unmaximize();
break;
}
}
}
public double Scaling => 1;
public Action Activated { get; set; }
public Action Closed { get; set; }
public Action Deactivated { get; set; }
public Action<RawInputEventArgs> Input { get; set; }
public Action<Rect> Paint { get; set; }
public Action<Size> Resized { get; set; }
public Action<double> ScalingChanged { get; set; }
public IPopupImpl CreatePopup()
{
return new PopupImpl();
}
public void Invalidate(Rect rect)
{
if (_window.GdkWindow != null)
_window.GdkWindow.InvalidateRect(
new Rectangle((int) rect.X, (int) rect.Y, (int) rect.Width, (int) rect.Height), true);
}
public Point PointToClient(Point point)
{
int x, y;
_window.GdkWindow.GetDeskrelativeOrigin(out x, out y);
return new Point(point.X - x, point.Y - y);
}
public Point PointToScreen(Point point)
{
int x, y;
_window.GdkWindow.GetDeskrelativeOrigin(out x, out y);
return new Point(point.X + x, point.Y + y);
}
public void SetInputRoot(IInputRoot inputRoot)
{
_inputRoot = inputRoot;
}
public abstract void SetTitle(string title);
public abstract IDisposable ShowDialog();
public abstract void SetSystemDecorations(bool enabled);
public abstract void SetIcon(IWindowIconImpl icon);
public void SetCursor(IPlatformHandle cursor)
{
_window.GdkWindow.Cursor = cursor != null ? new Gdk.Cursor(cursor.Handle) : DefaultCursor;
}
public void Show() => _window.Show();
public void Hide() => _window.Hide();
public abstract void BeginMoveDrag();
public abstract void BeginResizeDrag(WindowEdge edge);
public abstract Point Position { get; set; }
void ITopLevelImpl.Activate()
{
_window.Activate();
}
private static InputModifiers GetModifierKeys(ModifierType state)
{
var rv = InputModifiers.None;
if (state.HasFlag(ModifierType.ControlMask))
rv |= InputModifiers.Control;
if (state.HasFlag(ModifierType.ShiftMask))
rv |= InputModifiers.Shift;
if (state.HasFlag(ModifierType.Mod1Mask))
rv |= InputModifiers.Control;
if(state.HasFlag(ModifierType.Button1Mask))
rv |= InputModifiers.LeftMouseButton;
if (state.HasFlag(ModifierType.Button2Mask))
rv |= InputModifiers.RightMouseButton;
if (state.HasFlag(ModifierType.Button3Mask))
rv |= InputModifiers.MiddleMouseButton;
return rv;
}
void OnButtonPressEvent(object o, Gtk.ButtonPressEventArgs args)
{
var evnt = args.Event;
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
evnt.Button == 1
? RawMouseEventType.LeftButtonDown
: evnt.Button == 3 ? RawMouseEventType.RightButtonDown : RawMouseEventType.MiddleButtonDown,
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
}
void OnScrollEvent(object o, Gtk.ScrollEventArgs args)
{
var evnt = args.Event;
double step = 1;
var delta = new Vector();
if (evnt.Direction == ScrollDirection.Down)
delta = new Vector(0, -step);
else if (evnt.Direction == ScrollDirection.Up)
delta = new Vector(0, step);
else if (evnt.Direction == ScrollDirection.Right)
delta = new Vector(-step, 0);
if (evnt.Direction == ScrollDirection.Left)
delta = new Vector(step, 0);
var e = new RawMouseWheelEventArgs(GtkMouseDevice.Instance, evnt.Time, _inputRoot, new Point(evnt.X, evnt.Y), delta, GetModifierKeys(evnt.State));
Input(e);
}
protected void OnButtonReleaseEvent(object o, Gtk.ButtonReleaseEventArgs args)
{
var evnt = args.Event;
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
evnt.Button == 1
? RawMouseEventType.LeftButtonUp
: evnt.Button == 3 ? RawMouseEventType.RightButtonUp : RawMouseEventType.MiddleButtonUp,
new Point(evnt.X, evnt.Y), GetModifierKeys(evnt.State));
Input(e);
}
void OnDestroyed(object sender, EventArgs eventArgs)
{
Closed();
}
private void ProcessKeyEvent(EventKey evnt)
{
_lastKeyEventTimestamp = evnt.Time;
if (_imContext.FilterKeypress(evnt))
return;
var e = new RawKeyEventArgs(
GtkKeyboardDevice.Instance,
evnt.Time,
evnt.Type == EventType.KeyPress ? RawKeyEventType.KeyDown : RawKeyEventType.KeyUp,
GtkKeyboardDevice.ConvertKey(evnt.Key), GetModifierKeys(evnt.State));
Input(e);
}
void OnKeyPressEvent(object o, Gtk.KeyPressEventArgs args)
{
args.RetVal = true;
ProcessKeyEvent(args.Event);
}
void OnKeyReleaseEvent(object o, Gtk.KeyReleaseEventArgs args)
{
args.RetVal = true;
ProcessKeyEvent(args.Event);
}
private void ImContext_Commit(object o, Gtk.CommitArgs args)
{
Input(new RawTextInputEventArgs(GtkKeyboardDevice.Instance, _lastKeyEventTimestamp, args.Str));
}
void OnExposeEvent(object o, Gtk.ExposeEventArgs args)
{
Paint(args.Event.Area.ToAvalonia());
args.RetVal = true;
}
void OnMotionNotifyEvent(object o, Gtk.MotionNotifyEventArgs args)
{
var evnt = args.Event;
var position = new Point(evnt.X, evnt.Y);
GtkMouseDevice.Instance.SetClientPosition(position);
var e = new RawMouseEventArgs(
GtkMouseDevice.Instance,
evnt.Time,
_inputRoot,
RawMouseEventType.Move,
position, GetModifierKeys(evnt.State));
Input(e);
args.RetVal = true;
}
public void Dispose()
{
_window.Dispose();
}
}
}

91
src/Gtk/Avalonia.Gtk/Windows.cs

@ -0,0 +1,91 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Avalonia.Platform;
using Gdk;
using Gtk;
using Window = Gtk.Window;
using WindowType = Gtk.WindowType;
namespace Avalonia.Gtk
{
class PlatformHandleAwareWindow : Window, IPlatformHandle
{
public PlatformHandleAwareWindow(WindowType type) : base(type)
{
Events = EventMask.AllEventsMask;
}
IntPtr IPlatformHandle.Handle => GetNativeWindow();
public string HandleDescriptor => "HWND";
[DllImport("libgdk-win32-2.0-0.dll", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr gdk_win32_drawable_get_handle(IntPtr gdkWindow);
[DllImport("libgtk-x11-2.0.so.0", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr gdk_x11_drawable_get_xid(IntPtr gdkWindow);
[DllImport("libgdk-quartz-2.0-0.dylib", CallingConvention = CallingConvention.Cdecl)]
static extern IntPtr gdk_quartz_window_get_nswindow(IntPtr gdkWindow);
IntPtr _nativeWindow;
IntPtr GetNativeWindow()
{
if (_nativeWindow != IntPtr.Zero)
return _nativeWindow;
return _nativeWindow = GetNativeWindow(GdkWindow);
}
public static IntPtr GetNativeWindow(Gdk.Window window)
{
IntPtr h = window.Handle;
//Try whatever backend that works
try
{
return gdk_quartz_window_get_nswindow(h);
}
catch
{
}
try
{
return gdk_x11_drawable_get_xid(h);
}
catch
{
}
return gdk_win32_drawable_get_handle(h);
}
protected override bool OnConfigureEvent(EventConfigure evnt)
{
base.OnConfigureEvent(evnt);
return false;
}
}
class PlatformHandleAwareDrawingArea : DrawingArea, IPlatformHandle
{
IntPtr IPlatformHandle.Handle => GetNativeWindow();
public string HandleDescriptor => "HWND";
IntPtr _nativeWindow;
IntPtr GetNativeWindow()
{
if (_nativeWindow != IntPtr.Zero)
return _nativeWindow;
Realize();
return _nativeWindow = PlatformHandleAwareWindow.GetNativeWindow(GdkWindow);
}
}
}

59
src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs

@ -27,10 +27,12 @@ namespace Avalonia.Markup.Xaml.Data
/// Initializes a new instance of the <see cref="Binding"/> class.
/// </summary>
/// <param name="path">The binding path.</param>
public Binding(string path)
/// <param name="mode">The binding mode.</param>
public Binding(string path, BindingMode mode = BindingMode.Default)
: this()
{
Path = path;
Mode = mode;
}
/// <summary>
@ -78,21 +80,18 @@ namespace Avalonia.Markup.Xaml.Data
/// </summary>
public object Source { get; set; }
/// <summary>
/// Gets or sets a value indicating whether the property should be validated.
/// </summary>
public bool EnableValidation { get; set; }
/// <inheritdoc/>
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null)
object anchor = null,
bool enableDataValidation = false)
{
Contract.Requires<ArgumentNullException>(target != null);
var pathInfo = ParsePath(Path);
ValidateState(pathInfo);
enableDataValidation = enableDataValidation && Priority == BindingPriority.LocalValue;
ExpressionObserver observer;
@ -105,7 +104,7 @@ namespace Avalonia.Markup.Xaml.Data
}
else if (Source != null)
{
observer = CreateSourceObserver(Source, pathInfo.Path);
observer = CreateSourceObserver(Source, pathInfo.Path, enableDataValidation);
}
else if (RelativeSource == null || RelativeSource.Mode == RelativeSourceMode.DataContext)
{
@ -113,7 +112,8 @@ namespace Avalonia.Markup.Xaml.Data
target,
pathInfo.Path,
targetProperty == Control.DataContextProperty,
anchor);
anchor,
enableDataValidation);
}
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{
@ -135,7 +135,7 @@ namespace Avalonia.Markup.Xaml.Data
fallback = null;
}
var subject = new ExpressionSubject(
var subject = new BindingExpression(
observer,
targetProperty?.PropertyType ?? typeof(object),
fallback,
@ -197,7 +197,8 @@ namespace Avalonia.Markup.Xaml.Data
IAvaloniaObject target,
string path,
bool targetIsDataContext,
object anchor)
object anchor,
bool enableDataValidation)
{
Contract.Requires<ArgumentNullException>(target != null);
@ -220,19 +221,16 @@ namespace Avalonia.Markup.Xaml.Data
() => target.GetValue(Control.DataContextProperty),
path,
update,
EnableValidation);
enableDataValidation);
return result;
}
else
{
return new ExpressionObserver(
target.GetObservable(Visual.VisualParentProperty)
.OfType<IAvaloniaObject>()
.Select(x => x.GetObservable(Control.DataContextProperty))
.Switch(),
GetParentDataContext(target),
path,
EnableValidation);
enableDataValidation);
}
}
@ -240,18 +238,23 @@ namespace Avalonia.Markup.Xaml.Data
{
Contract.Requires<ArgumentNullException>(target != null);
var description = $"#{elementName}.{path}";
var result = new ExpressionObserver(
ControlLocator.Track(target, elementName),
path,
EnableValidation);
false,
description);
return result;
}
private ExpressionObserver CreateSourceObserver(object source, string path)
private ExpressionObserver CreateSourceObserver(
object source,
string path,
bool enabledDataValidation)
{
Contract.Requires<ArgumentNullException>(source != null);
return new ExpressionObserver(source, path, EnableValidation);
return new ExpressionObserver(source, path, enabledDataValidation);
}
private ExpressionObserver CreateTemplatedParentObserver(
@ -272,6 +275,22 @@ namespace Avalonia.Markup.Xaml.Data
return result;
}
private IObservable<object> GetParentDataContext(IAvaloniaObject target)
{
// The DataContext is based on the visual parent and not the logical parent: this may
// seem unintuitive considering the fact that property inheritance works on the logical
// tree, but consider a ContentControl with a ContentPresenter. The ContentControl's
// Content property is bound to a value which becomes the ContentPresenter's
// DataContext - it is from this that the child hosted by the ContentPresenter needs to
// inherit its DataContext.
return target.GetObservable(Visual.VisualParentProperty)
.Select(x =>
{
return (x as IAvaloniaObject)?.GetObservable(Control.DataContextProperty) ??
Observable.Return((object)null);
}).Switch();
}
private class PathInfo
{
public string Path { get; set; }

3
src/Markup/Avalonia.Markup.Xaml/Data/MultiBinding.cs

@ -53,7 +53,8 @@ namespace Avalonia.Markup.Xaml.Data
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null)
object anchor = null,
bool enableDataValidation = false)
{
if (Converter == null)
{

3
src/Markup/Avalonia.Markup.Xaml/Data/StyleResourceBinding.cs

@ -37,7 +37,8 @@ namespace Avalonia.Markup.Xaml.Data
public InstancedBinding Initiate(
IAvaloniaObject target,
AvaloniaProperty targetProperty,
object anchor = null)
object anchor = null,
bool enableDataValidation = false)
{
if (Name == "Red")
{

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

@ -29,7 +29,6 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
Mode = Mode,
Path = Path,
Priority = Priority,
EnableValidation = EnableValidation,
};
}
@ -41,6 +40,5 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
public string Path { get; set; }
public BindingPriority Priority { get; set; } = BindingPriority.LocalValue;
public object Source { get; set; }
public bool EnableValidation { get; set; }
}
}

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

Loading…
Cancel
Save