diff --git a/Directory.Build.props b/Directory.Build.props
index 97781b7517..42daa2df7f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -1,4 +1,5 @@
+
$(MSBuildThisFileDirectory)build-intermediate/nuget
$(MSBuildThisFileDirectory)\src\tools\Avalonia.Designer.HostApp\bin\$(Configuration)\netcoreapp2.0\Avalonia.Designer.HostApp.dll
diff --git a/build/AvaloniaPublicKey.props b/build/AvaloniaPublicKey.props
new file mode 100644
index 0000000000..89215635c0
--- /dev/null
+++ b/build/AvaloniaPublicKey.props
@@ -0,0 +1,5 @@
+
+
+ 0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87
+
+
diff --git a/build/HarfBuzzSharp.props b/build/HarfBuzzSharp.props
index e10de93530..85e7a1f34d 100644
--- a/build/HarfBuzzSharp.props
+++ b/build/HarfBuzzSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/JetBrains.dotMemoryUnit.props b/build/JetBrains.dotMemoryUnit.props
index eb4e2b6f15..5d74d474cf 100644
--- a/build/JetBrains.dotMemoryUnit.props
+++ b/build/JetBrains.dotMemoryUnit.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/NetFX.props b/build/NetFX.props
index 8ffc9ec561..14adb54035 100644
--- a/build/NetFX.props
+++ b/build/NetFX.props
@@ -1,7 +1,6 @@
-
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index a217a8272d..1ee4aa56a2 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,7 +1,7 @@
-
-
-
+
+
+
diff --git a/build/SourceLink.props b/build/SourceLink.props
index 9f05848881..dd7ecc8d2a 100644
--- a/build/SourceLink.props
+++ b/build/SourceLink.props
@@ -19,7 +19,7 @@
-
+
diff --git a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
index 022769bad0..6dc59ae4d8 100644
--- a/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
+++ b/native/Avalonia.Native/src/OSX/WindowBaseImpl.mm
@@ -296,6 +296,7 @@ HRESULT WindowBaseImpl::Resize(double x, double y, AvnPlatformResizeReason reaso
if(Window != nullptr) {
[Window setContentSize:lastSize];
+ [Window invalidateShadow];
}
}
@finally {
@@ -583,6 +584,8 @@ void WindowBaseImpl::InitialiseNSWindow() {
[Window setContentMaxSize:lastMaxSize];
[Window setOpaque:false];
+
+ [Window invalidateShadow];
if (lastMenu != nullptr) {
[GetWindowProtocol() applyMenu:lastMenu];
diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj
index 52b60b7d0f..b2c58e2292 100644
--- a/nukebuild/_build.csproj
+++ b/nukebuild/_build.csproj
@@ -8,11 +8,10 @@
False
CS0649;CS0169
-
+
-
diff --git a/samples/ControlCatalog/ControlCatalog.csproj b/samples/ControlCatalog/ControlCatalog.csproj
index e5f07c90c3..bce924a3f2 100644
--- a/samples/ControlCatalog/ControlCatalog.csproj
+++ b/samples/ControlCatalog/ControlCatalog.csproj
@@ -1,7 +1,8 @@
netstandard2.0
- true
+ true
+ enable
diff --git a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
index 3cadc7243a..bed9f4c62a 100644
--- a/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DialogsPage.xaml.cs
@@ -8,7 +8,6 @@ using Avalonia.Dialogs;
using Avalonia.Layout;
using Avalonia.Markup.Xaml;
#pragma warning disable 4014
-
namespace ControlCatalog.Pages
{
public class DialogsPage : UserControl
@@ -22,7 +21,7 @@ namespace ControlCatalog.Pages
string lastSelectedDirectory = null;
- List GetFilters()
+ List? GetFilters()
{
if (this.FindControl("UseFilters").IsChecked != true)
return null;
@@ -42,13 +41,17 @@ namespace ControlCatalog.Pages
this.FindControl
diff --git a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
index 445f35aad2..45c67b9f48 100644
--- a/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
+++ b/src/Avalonia.Base/AvaloniaPropertyChangedEventArgs.cs
@@ -55,7 +55,7 @@ namespace Avalonia
///
///
/// This will usually be true, except in
- ///
+ ///
/// which receives notifications for all changes to property values, whether a value with a higher
/// priority is present or not. When this property is false, the change that is being signaled
/// has not resulted in a change to the property value on the object.
diff --git a/src/Avalonia.Base/Collections/Pooled/PooledList.cs b/src/Avalonia.Base/Collections/Pooled/PooledList.cs
index 200a52fb0d..803b8d60dc 100644
--- a/src/Avalonia.Base/Collections/Pooled/PooledList.cs
+++ b/src/Avalonia.Base/Collections/Pooled/PooledList.cs
@@ -587,7 +587,7 @@ namespace Avalonia.Collections.Pooled
if (size > 0 && _clearOnFree)
{
// Clear the elements so that the gc can reclaim the references.
- Array.Clear(_items, 0, _size);
+ Array.Clear(_items, 0, size);
}
}
diff --git a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
index 3c4120ad0b..cc6d92ceb7 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/AvaloniaPropertyAccessorPlugin.cs
@@ -1,5 +1,6 @@
using System;
using System.Runtime.ExceptionServices;
+using Avalonia.Utilities;
namespace Avalonia.Data.Core.Plugins
{
@@ -60,11 +61,10 @@ namespace Avalonia.Data.Core.Plugins
return AvaloniaPropertyRegistry.Instance.FindRegistered(o, propertyName);
}
- private class Accessor : PropertyAccessorBase, IObserver
diff --git a/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs
index 0135541349..64769303d6 100644
--- a/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Controls.ColorPicker/Properties/AssemblyInfo.cs
@@ -1,8 +1,5 @@
-using System.Runtime.CompilerServices;
using Avalonia.Metadata;
-[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")]
diff --git a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
index 410cac72fc..6369961f0f 100644
--- a/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
+++ b/src/Avalonia.Controls.DataGrid/Avalonia.Controls.DataGrid.csproj
@@ -18,4 +18,9 @@
+
+
+
+
+
diff --git a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
index a3095ad214..ae52e5f970 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
@@ -193,8 +193,11 @@ namespace Avalonia.Controls
}
}
+ /// Try get number of DataSource itmes.
/// When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.
/// If "getAny" is true, method can use Linq.Any() method to speedup.
+ /// number of DataSource itmes.
+ /// true if able to retrieve number of DataSource itmes; otherwise, false.
internal bool TryGetCount(bool allowSlow, bool getAny, out int count)
{
bool result;
diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
index d61c05ab6e..64769303d6 100644
--- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs
@@ -1,9 +1,5 @@
-using System.Runtime.CompilerServices;
using Avalonia.Metadata;
-[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")]
diff --git a/src/Avalonia.Controls/Avalonia.Controls.csproj b/src/Avalonia.Controls/Avalonia.Controls.csproj
index 4d239e69f4..00f094f508 100644
--- a/src/Avalonia.Controls/Avalonia.Controls.csproj
+++ b/src/Avalonia.Controls/Avalonia.Controls.csproj
@@ -14,4 +14,10 @@
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls/Properties/AssemblyInfo.cs b/src/Avalonia.Controls/Properties/AssemblyInfo.cs
index 25330614cf..0f3da91107 100644
--- a/src/Avalonia.Controls/Properties/AssemblyInfo.cs
+++ b/src/Avalonia.Controls/Properties/AssemblyInfo.cs
@@ -1,10 +1,5 @@
-using System.Runtime.CompilerServices;
using Avalonia.Metadata;
-[assembly: InternalsVisibleTo("Avalonia.Controls.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Automation")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")]
diff --git a/src/Avalonia.Controls/SystemDialog.cs b/src/Avalonia.Controls/SystemDialog.cs
index 4a9e745e30..093f10be51 100644
--- a/src/Avalonia.Controls/SystemDialog.cs
+++ b/src/Avalonia.Controls/SystemDialog.cs
@@ -15,7 +15,7 @@ namespace Avalonia.Controls
/// Gets or sets a collection of filters which determine the types of files displayed in an
/// or an .
///
- public List Filters { get; set; } = new List();
+ public List? Filters { get; set; } = new List();
///
/// Gets or sets initial file name that is displayed when the dialog is opened.
diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
index bcb63783a4..e9d6394aa5 100644
--- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
+++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj
@@ -8,5 +8,7 @@
-
+
+
+
diff --git a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs
index a7cc4f4cc2..4a55212de3 100644
--- a/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs
+++ b/src/Avalonia.FreeDesktop/DBusTrayIconImpl.cs
@@ -12,10 +12,6 @@ using Tmds.DBus;
[assembly: InternalsVisibleTo(Connection.DynamicAssemblyName)]
-[assembly:
- InternalsVisibleTo(
- "Avalonia.X11, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
namespace Avalonia.FreeDesktop
{
internal class DBusTrayIconImpl : ITrayIconImpl
diff --git a/src/Avalonia.Native/SystemDialogs.cs b/src/Avalonia.Native/SystemDialogs.cs
index 4372829df1..d1d9c17ae3 100644
--- a/src/Avalonia.Native/SystemDialogs.cs
+++ b/src/Avalonia.Native/SystemDialogs.cs
@@ -30,7 +30,7 @@ namespace Avalonia.Native
ofd.Title ?? "",
ofd.Directory ?? "",
ofd.InitialFileName ?? "",
- string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
+ string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty()));
}
else
{
@@ -39,7 +39,7 @@ namespace Avalonia.Native
dialog.Title ?? "",
dialog.Directory ?? "",
dialog.InitialFileName ?? "",
- string.Join(";", dialog.Filters.SelectMany(f => f.Extensions)));
+ string.Join(";", dialog.Filters?.SelectMany(f => f.Extensions) ?? Array.Empty()));
}
return events.Task.ContinueWith(t => { events.Dispose(); return t.Result; });
diff --git a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj
index 5336f1e630..98839b7af3 100644
--- a/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj
+++ b/src/Avalonia.PlatformSupport/Avalonia.PlatformSupport.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/src/Avalonia.X11/NativeDialogs/Gtk.cs b/src/Avalonia.X11/NativeDialogs/Gtk.cs
index a0f146afa8..73e6a2d6a4 100644
--- a/src/Avalonia.X11/NativeDialogs/Gtk.cs
+++ b/src/Avalonia.X11/NativeDialogs/Gtk.cs
@@ -195,7 +195,10 @@ namespace Avalonia.X11.NativeDialogs
[DllImport(GtkName)]
public static extern void gtk_file_chooser_set_current_name(IntPtr chooser, Utf8Buffer file);
-
+
+ [DllImport(GtkName)]
+ public static extern void gtk_file_chooser_set_current_folder(IntPtr chooser, Utf8Buffer file);
+
[DllImport(GtkName)]
public static extern IntPtr gtk_file_filter_new();
diff --git a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs
index 1a6514eb03..9539f024b7 100644
--- a/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs
+++ b/src/Avalonia.X11/NativeDialogs/GtkNativeFileDialogs.cs
@@ -15,8 +15,9 @@ namespace Avalonia.X11.NativeDialogs
class GtkSystemDialog : ISystemDialogImpl
{
private Task _initialized;
- private unsafe Task ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action,
- bool multiSelect, string initialFileName, IEnumerable filters, string defaultExtension, bool overwritePrompt)
+
+ private unsafe Task ShowDialog(string title, IWindowImpl parent, GtkFileChooserAction action,
+ bool multiSelect, string initialDirectory, string initialFileName, IEnumerable filters, string defaultExtension, bool overwritePrompt)
{
IntPtr dlg;
using (var name = new Utf8Buffer(title))
@@ -44,7 +45,7 @@ namespace Avalonia.X11.NativeDialogs
filtersDic[filter] = f;
using (var b = new Utf8Buffer(f.Name))
gtk_file_filter_set_name(filter, b);
-
+
foreach (var e in f.Extensions)
using (var b = new Utf8Buffer("*." + e))
gtk_file_filter_add_pattern(filter, b);
@@ -100,17 +101,32 @@ namespace Avalonia.X11.NativeDialogs
gtk_dialog_add_button(dlg, open, GtkResponseType.Accept);
using (var open = new Utf8Buffer("Cancel"))
gtk_dialog_add_button(dlg, open, GtkResponseType.Cancel);
+
+ if (initialDirectory != null)
+ {
+ using var dir = new Utf8Buffer(initialDirectory);
+ gtk_file_chooser_set_current_folder(dlg, dir);
+ }
+
if (initialFileName != null)
- using (var fn = new Utf8Buffer(initialFileName))
+ {
+ // gtk_file_chooser_set_filename() expects full path
+ using var fn = action == GtkFileChooserAction.Open
+ ? new Utf8Buffer(Path.Combine(initialDirectory ?? "", initialFileName))
+ : new Utf8Buffer(initialFileName);
+
+ if (action == GtkFileChooserAction.Save)
{
- if (action == GtkFileChooserAction.Save)
- gtk_file_chooser_set_current_name(dlg, fn);
- else
- gtk_file_chooser_set_filename(dlg, fn);
+ gtk_file_chooser_set_current_name(dlg, fn);
}
+ else
+ {
+ gtk_file_chooser_set_filename(dlg, fn);
+ }
+ }
gtk_file_chooser_set_do_overwrite_confirmation(dlg, overwritePrompt);
-
+
gtk_window_present(dlg);
return tcs.Task;
}
@@ -144,13 +160,15 @@ namespace Avalonia.X11.NativeDialogs
var platformImpl = parent?.PlatformImpl;
- return await await RunOnGlibThread(
- () => ShowDialog(dialog.Title, platformImpl,
- dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
- (dialog as OpenFileDialog)?.AllowMultiple ?? false,
- Path.Combine(string.IsNullOrEmpty(dialog.Directory) ? "" : dialog.Directory,
- string.IsNullOrEmpty(dialog.InitialFileName) ? "" : dialog.InitialFileName), dialog.Filters,
- (dialog as SaveFileDialog)?.DefaultExtension, (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false));
+ return await await RunOnGlibThread(() => ShowDialog(
+ dialog.Title, platformImpl,
+ dialog is OpenFileDialog ? GtkFileChooserAction.Open : GtkFileChooserAction.Save,
+ (dialog as OpenFileDialog)?.AllowMultiple ?? false,
+ dialog.Directory,
+ dialog.InitialFileName,
+ dialog.Filters,
+ (dialog as SaveFileDialog)?.DefaultExtension,
+ (dialog as SaveFileDialog)?.ShowOverwritePrompt ?? false));
}
public async Task ShowFolderDialogAsync(OpenFolderDialog dialog, Window parent)
@@ -161,12 +179,20 @@ namespace Avalonia.X11.NativeDialogs
return await await RunOnGlibThread(async () =>
{
- var res = await ShowDialog(dialog.Title, platformImpl,
- GtkFileChooserAction.SelectFolder, false, dialog.Directory, null, null, false);
+ var res = await ShowDialog(
+ dialog.Title,
+ platformImpl,GtkFileChooserAction.SelectFolder,
+ false,
+ dialog.Directory,
+ null,
+ null,
+ null,
+ false);
+
return res?.FirstOrDefault();
});
}
-
+
async Task EnsureInitialized()
{
if (_initialized == null) _initialized = StartGtk();
@@ -174,7 +200,7 @@ namespace Avalonia.X11.NativeDialogs
if (!(await _initialized))
throw new Exception("Unable to initialize GTK on separate thread");
}
-
+
void UpdateParent(IntPtr chooser, IWindowImpl parentWindow)
{
var xid = parentWindow.Handle.Handle;
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
index cf691db860..d4dfcf9c4b 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlDataContextTypeTransformer.cs
@@ -49,6 +49,8 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
}
else if (child is XamlPropertyAssignmentNode pa)
{
+ var templateDataTypeAttribute = context.GetAvaloniaTypes().DataTypeAttribute;
+
if (pa.Property.Name == "DataContext"
&& pa.Property.DeclaringType.Equals(context.GetAvaloniaTypes().StyledElement)
&& pa.Values[0] is XamlMarkupExtensionNode ext
@@ -56,8 +58,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
{
inferredDataContextTypeNode = ParseDataContext(context, on, obj);
}
- else if(context.GetAvaloniaTypes().DataTemplate.IsAssignableFrom(on.Type.GetClrType())
- && pa.Property.Name == "DataType"
+ else if(pa.Property.CustomAttributes.Any(a => a.Type == templateDataTypeAttribute)
&& pa.Values[0] is XamlTypeExtensionNode dataTypeNode)
{
inferredDataContextTypeNode = new AvaloniaXamlIlDataContextTypeMetadataNode(on, dataTypeNode.Value.GetClrType());
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
index 5da40035d2..28787d9b84 100644
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
@@ -26,6 +26,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType Transitions { get; }
public IXamlType AssignBindingAttribute { get; }
public IXamlType DependsOnAttribute { get; }
+ public IXamlType DataTypeAttribute { get; }
public IXamlType UnsetValueType { get; }
public IXamlType StyledElement { get; }
public IXamlType IStyledElement { get; }
@@ -112,6 +113,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
Transitions = cfg.TypeSystem.GetType("Avalonia.Animation.Transitions");
AssignBindingAttribute = cfg.TypeSystem.GetType("Avalonia.Data.AssignBindingAttribute");
DependsOnAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.DependsOnAttribute");
+ DataTypeAttribute = cfg.TypeSystem.GetType("Avalonia.Metadata.DataTypeAttribute");
AvaloniaObjectBindMethod = AvaloniaObjectExtensions.FindMethod("Bind", IDisposable, false, IAvaloniaObject,
AvaloniaProperty,
IBinding, cfg.WellKnownTypes.Object);
diff --git a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
index 622ec416e8..30d321426f 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
+++ b/src/Markup/Avalonia.Markup.Xaml/Avalonia.Markup.Xaml.csproj
@@ -63,4 +63,8 @@
+
+
+
+
diff --git a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
index cee4d90917..7e5b3159d4 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Properties/AssemblyInfo.cs
@@ -1,9 +1,6 @@
using Avalonia.Metadata;
-using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.MarkupExtensions")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Styling")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Xaml.Templates")]
-[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
index b7db1a3fbb..d2b24979cc 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
@@ -7,6 +7,7 @@ namespace Avalonia.Markup.Xaml.Templates
{
public class DataTemplate : IRecyclingDataTemplate
{
+ [DataType]
public Type DataType { get; set; }
[Content]
diff --git a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
index 7b065c7f47..10061c3d48 100644
--- a/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
+++ b/src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
@@ -11,6 +11,7 @@ namespace Avalonia.Markup.Xaml.Templates
{
public class TreeDataTemplate : ITreeDataTemplate
{
+ [DataType]
public Type DataType { get; set; }
[Content]
diff --git a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
index f7f1a111ba..6711c3dd3d 100644
--- a/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
+++ b/src/Markup/Avalonia.Markup/Avalonia.Markup.csproj
@@ -17,4 +17,8 @@
+
+
+
+
diff --git a/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs
index 46e2925f92..36ca2784da 100644
--- a/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs
+++ b/src/Markup/Avalonia.Markup/Properties/AssemblyInfo.cs
@@ -1,8 +1,5 @@
using Avalonia.Metadata;
-using System.Runtime.CompilerServices;
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data")]
[assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Markup.Data")]
-[assembly: InternalsVisibleTo("Avalonia.Markup.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
diff --git a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
index 26c0fb756e..413c2ba4d4 100644
--- a/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
+++ b/src/Skia/Avalonia.Skia/Avalonia.Skia.csproj
@@ -18,4 +18,13 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
index b45968ec27..8293769138 100644
--- a/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
+++ b/src/Skia/Avalonia.Skia/DrawingContextImpl.cs
@@ -181,7 +181,8 @@ namespace Avalonia.Skia
var size = geometry.Bounds.Size;
using (var fill = brush != null ? CreatePaint(_fillPaint, brush, size) : default(PaintWrapper))
- using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen, size) : default(PaintWrapper))
+ using (var stroke = pen?.Brush != null ? CreatePaint(_strokePaint, pen,
+ size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))) : default(PaintWrapper))
{
if (fill.Paint != null)
{
@@ -398,7 +399,7 @@ namespace Avalonia.Skia
if (pen?.Brush != null)
{
- using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size))
+ using (var paint = CreatePaint(_strokePaint, pen, rect.Rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))))
{
if (paint.Paint is object)
{
@@ -433,7 +434,7 @@ namespace Avalonia.Skia
if (pen?.Brush != null)
{
- using (var paint = CreatePaint(_strokePaint, pen, rect.Size))
+ using (var paint = CreatePaint(_strokePaint, pen, rect.Size.Inflate(new Thickness(pen?.Thickness / 2 ?? 0))))
{
if (paint.Paint is object)
{
@@ -625,8 +626,12 @@ namespace Avalonia.Skia
}
else
{
+ var transformOrigin = linearGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * linearGradient.Transform.Value * (offset);
+
using (var shader =
- SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, linearGradient.Transform.Value.ToSKMatrix()))
+ SKShader.CreateLinearGradient(start, end, stopColors, stopOffsets, tileMode, transform.ToSKMatrix()))
{
paintWrapper.Paint.Shader = shader;
}
@@ -654,8 +659,12 @@ namespace Avalonia.Skia
}
else
{
+ var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * radialGradient.Transform.Value * (offset);
+
using (var shader =
- SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, radialGradient.Transform.Value.ToSKMatrix()))
+ SKShader.CreateRadialGradient(center, radius, stopColors, stopOffsets, tileMode, transform.ToSKMatrix()))
{
paintWrapper.Paint.Shader = shader;
}
@@ -694,9 +703,14 @@ namespace Avalonia.Skia
}
else
{
+
+ var transformOrigin = radialGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * radialGradient.Transform.Value * (offset);
+
using (var shader = SKShader.CreateCompose(
SKShader.CreateColor(reversedColors[0]),
- SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, radialGradient.Transform.Value.ToSKMatrix())
+ SKShader.CreateTwoPointConicalGradient(center, radius, origin, 0, reversedColors, reversedStops, tileMode, transform.ToSKMatrix())
))
{
paintWrapper.Paint.Shader = shader;
@@ -717,7 +731,12 @@ namespace Avalonia.Skia
if (conicGradient.Transform is { })
{
- rotation = rotation.PreConcat(conicGradient.Transform.Value.ToSKMatrix());
+
+ var transformOrigin = conicGradient.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(transformOrigin);
+ var transform = (-offset) * conicGradient.Transform.Value * (offset);
+
+ rotation = rotation.PreConcat(transform.ToSKMatrix());
}
using (var shader =
@@ -794,7 +813,11 @@ namespace Avalonia.Skia
if (tileBrush.Transform is { })
{
- paintTransform = paintTransform.PreConcat(tileBrush.Transform.Value.ToSKMatrix());
+ var origin = tileBrush.TransformOrigin.ToPixels(targetSize);
+ var offset = Matrix.CreateTranslation(origin);
+ var transform = (-offset) * tileBrush.Transform.Value * (offset);
+
+ paintTransform = paintTransform.PreConcat(transform.ToSKMatrix());
}
using (var shader = image.ToShader(tileX, tileY, paintTransform))
diff --git a/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs b/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs
deleted file mode 100644
index a7e556ee84..0000000000
--- a/src/Skia/Avalonia.Skia/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,5 +0,0 @@
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Avalonia.Skia.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.Skia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-
diff --git a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
index bd1f05b30f..03b3ebec0d 100644
--- a/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
+++ b/src/Windows/Avalonia.Direct2D1/Avalonia.Direct2D1.csproj
@@ -19,4 +19,14 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs b/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
deleted file mode 100644
index 89fd6c2dd8..0000000000
--- a/src/Windows/Avalonia.Direct2D1/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("Avalonia.Direct2D1.RenderTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
-[assembly: InternalsVisibleTo("Avalonia.Direct2D1.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")]
diff --git a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
index 9ff6f76ac4..3adefd965f 100644
--- a/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
+++ b/src/Windows/Avalonia.Win32/Input/Imm32InputMethod.cs
@@ -37,6 +37,24 @@ namespace Avalonia.Win32.Input
IsComposing = false;
}
+ public void ClearLanguageAndWindow()
+ {
+ if (HWND != IntPtr.Zero && _defaultImc != IntPtr.Zero)
+ {
+ ImmReleaseContext(HWND, _defaultImc);
+ }
+
+ _defaultImc = IntPtr.Zero;
+ HWND = IntPtr.Zero;
+ _parent = null;
+ _active = false;
+ _langId = 0;
+ _showCompositionWindow = false;
+ _showCandidateList = false;
+
+ IsComposing = false;
+ }
+
//Dependant on CurrentThread. When Avalonia will support Multiple Dispatchers -
//every Dispatcher should have their own InputMethod.
public static Imm32InputMethod Current { get; } = new Imm32InputMethod();
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
index 64ab15bc30..cae8834550 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.AppWndProc.cs
@@ -82,6 +82,12 @@ namespace Avalonia.Win32
case WindowsMessage.WM_DESTROY:
{
UiaCoreProviderApi.UiaReturnRawElementProvider(_hwnd, IntPtr.Zero, IntPtr.Zero, null);
+
+ // We need to release IMM context and state to avoid leaks.
+ if (Imm32InputMethod.Current.HWND == _hwnd)
+ {
+ Imm32InputMethod.Current.ClearLanguageAndWindow();
+ }
//Window doesn't exist anymore
_hwnd = IntPtr.Zero;
diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs
index 3a5a8f1474..bb520c16aa 100644
--- a/tests/Avalonia.LeakTests/ControlTests.cs
+++ b/tests/Avalonia.LeakTests/ControlTests.cs
@@ -2,17 +2,18 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
-using System.Runtime.Remoting.Contexts;
+using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
+using Avalonia.Data;
using Avalonia.Diagnostics;
using Avalonia.Input;
-using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Styling;
+using Avalonia.Threading;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using JetBrains.dotMemoryUnit;
@@ -661,14 +662,96 @@ namespace Avalonia.LeakTests
}
}
+ [Fact]
+ public void ElementName_Binding_In_DataTemplate_Is_Freed()
+ {
+ using (Start())
+ {
+ var items = new ObservableCollection(Enumerable.Range(0, 10));
+ NameScope ns;
+ TextBox tb;
+ ListBox lb;
+ var window = new Window
+ {
+ [NameScope.NameScopeProperty] = ns = new NameScope(),
+ Width = 100,
+ Height = 100,
+ Content = new StackPanel
+ {
+ Children =
+ {
+ (tb = new TextBox
+ {
+ Name = "tb",
+ Text = "foo",
+ }),
+ (lb = new ListBox
+ {
+ Items = items,
+ ItemTemplate = new FuncDataTemplate((_, _) =>
+ new Canvas
+ {
+ Width = 10,
+ Height = 10,
+ [!Control.TagProperty] = new Binding
+ {
+ ElementName = "tb",
+ Path = "Text",
+ NameScope = new WeakReference(ns),
+ }
+ })
+ }),
+ }
+ }
+ };
+
+ tb.RegisterInNameScope(ns);
+
+ window.Show();
+ window.LayoutManager.ExecuteInitialLayoutPass();
+
+ void AssertInitialItemState()
+ {
+ var item0 = (ListBoxItem)lb.ItemContainerGenerator.Containers.First().ContainerControl;
+ var canvas0 = (Canvas)item0.Presenter.Child;
+ Assert.Equal("foo", canvas0.Tag);
+ }
+
+ Assert.Equal(10, lb.ItemContainerGenerator.Containers.Count());
+ AssertInitialItemState();
+
+ items.Clear();
+ window.LayoutManager.ExecuteLayoutPass();
+
+ Assert.Empty(lb.ItemContainerGenerator.Containers);
+
+ dotMemory.Check(memory =>
+ Assert.Equal(0, memory.GetObjects(where => where.Type.Is