diff --git a/.editorconfig b/.editorconfig
index b7a03207a4..5f08d1e940 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -132,6 +132,9 @@ csharp_space_between_method_declaration_parameter_list_parentheses = false
csharp_space_between_parentheses = false
csharp_space_between_square_brackets = false
+# Wrapping preferences
+csharp_wrap_before_ternary_opsigns = false
+
# Xaml files
[*.xaml]
indent_size = 4
diff --git a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
index 2ab6c26e68..df80931367 100644
--- a/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
+++ b/samples/BindingDemo/ViewModels/ExceptionErrorViewModel.cs
@@ -21,7 +21,7 @@ namespace BindingDemo.ViewModels
}
else
{
- throw new ArgumentOutOfRangeException("Value must be less than 10.");
+ throw new ArgumentOutOfRangeException(nameof(value), "Value must be less than 10.");
}
}
}
diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
index 932f3292ff..8f147638b5 100644
--- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml
+++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
@@ -10,7 +10,8 @@
HorizontalAlignment="Center"
Spacing="16">
+ Margin="16"
+ Padding="48,48,48,48">
@@ -31,7 +32,24 @@
-
+
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs b/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
index dc73bef07a..96e8b49f89 100644
--- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml.cs
@@ -1,5 +1,6 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
+using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
@@ -8,6 +9,7 @@ namespace ControlCatalog.Pages
public ContextMenuPage()
{
this.InitializeComponent();
+ DataContext = new ContextMenuPageViewModel();
}
private void InitializeComponent()
diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml.cs b/samples/ControlCatalog/Pages/MenuPage.xaml.cs
index 5a07cae89f..0a77607719 100644
--- a/samples/ControlCatalog/Pages/MenuPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/MenuPage.xaml.cs
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
+using ControlCatalog.ViewModels;
using ReactiveUI;
namespace ControlCatalog.Pages
@@ -13,51 +14,7 @@ namespace ControlCatalog.Pages
public MenuPage()
{
this.InitializeComponent();
- var vm = new MenuPageViewModel();
-
- vm.MenuItems = new[]
- {
- new MenuItemViewModel
- {
- Header = "_File",
- Items = new[]
- {
- new MenuItemViewModel { Header = "_Open...", Command = vm.OpenCommand },
- new MenuItemViewModel { Header = "Save", Command = vm.SaveCommand },
- new MenuItemViewModel { Header = "-" },
- new MenuItemViewModel
- {
- Header = "Recent",
- Items = new[]
- {
- new MenuItemViewModel
- {
- Header = "File1.txt",
- Command = vm.OpenRecentCommand,
- CommandParameter = @"c:\foo\File1.txt"
- },
- new MenuItemViewModel
- {
- Header = "File2.txt",
- Command = vm.OpenRecentCommand,
- CommandParameter = @"c:\foo\File2.txt"
- },
- }
- },
- }
- },
- new MenuItemViewModel
- {
- Header = "_Edit",
- Items = new[]
- {
- new MenuItemViewModel { Header = "_Copy" },
- new MenuItemViewModel { Header = "_Paste" },
- }
- }
- };
-
- DataContext = vm;
+ DataContext = new MenuPageViewModel();
}
private void InitializeComponent()
@@ -65,51 +22,4 @@ namespace ControlCatalog.Pages
AvaloniaXamlLoader.Load(this);
}
}
-
- public class MenuPageViewModel
- {
- public MenuPageViewModel()
- {
- OpenCommand = ReactiveCommand.CreateFromTask(Open);
- SaveCommand = ReactiveCommand.Create(Save);
- OpenRecentCommand = ReactiveCommand.Create(OpenRecent);
- }
-
- public IReadOnlyList MenuItems { get; set; }
- public ReactiveCommand OpenCommand { get; }
- public ReactiveCommand SaveCommand { get; }
- public ReactiveCommand OpenRecentCommand { get; }
-
- public async Task Open()
- {
- var dialog = new OpenFileDialog();
- var result = await dialog.ShowAsync(App.Current.MainWindow);
-
- if (result != null)
- {
- foreach (var path in result)
- {
- System.Diagnostics.Debug.WriteLine($"Opened: {path}");
- }
- }
- }
-
- public void Save()
- {
- System.Diagnostics.Debug.WriteLine("Save");
- }
-
- public void OpenRecent(string path)
- {
- System.Diagnostics.Debug.WriteLine($"Open recent: {path}");
- }
- }
-
- public class MenuItemViewModel
- {
- public string Header { get; set; }
- public ICommand Command { get; set; }
- public object CommandParameter { get; set; }
- public IList Items { get; set; }
- }
}
diff --git a/samples/ControlCatalog/Pages/TreeViewPage.xaml b/samples/ControlCatalog/Pages/TreeViewPage.xaml
index f8f3cd5848..c03edb8b03 100644
--- a/samples/ControlCatalog/Pages/TreeViewPage.xaml
+++ b/samples/ControlCatalog/Pages/TreeViewPage.xaml
@@ -9,7 +9,7 @@
Margin="0,16,0,0"
HorizontalAlignment="Center"
Spacing="16">
-
+
diff --git a/samples/ControlCatalog/SideBar.xaml b/samples/ControlCatalog/SideBar.xaml
index 625b344b8c..fea55bcb07 100644
--- a/samples/ControlCatalog/SideBar.xaml
+++ b/samples/ControlCatalog/SideBar.xaml
@@ -1,6 +1,14 @@
+
+
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
index 135935498c..e48c671a13 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/MethodAccessorPlugin.cs
@@ -21,7 +21,7 @@ namespace Avalonia.Data.Core.Plugins
{
if (method.GetParameters().Length + (method.ReturnType == typeof(void) ? 0 : 1) > 8)
{
- var exception = new ArgumentException("Cannot create a binding accessor for a method with more than 8 parameters or more than 7 parameters if it has a non-void return type.", nameof(method));
+ var exception = new ArgumentException("Cannot create a binding accessor for a method with more than 8 parameters or more than 7 parameters if it has a non-void return type.", nameof(methodName));
return new PropertyError(new BindingNotification(exception, BindingErrorType.Error));
}
diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
new file mode 100644
index 0000000000..0ade1af249
--- /dev/null
+++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
@@ -0,0 +1,219 @@
+// 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;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+namespace Avalonia.Utilities
+{
+ ///
+ /// Manages subscriptions to events using weak listeners.
+ ///
+ public static class WeakEventHandlerManager
+ {
+ ///
+ /// Subscribes to an event on an object using a weak subscription.
+ ///
+ /// The type of the target.
+ /// The type of the event arguments.
+ /// The event source.
+ /// The name of the event.
+ /// The subscriber.
+ public static void Subscribe(TTarget target, string eventName, EventHandler subscriber)
+ where TEventArgs : EventArgs where TSubscriber : class
+ {
+ var dic = SubscriptionTypeStorage.Subscribers.GetOrCreateValue(target);
+ Subscription sub;
+
+ if (!dic.TryGetValue(eventName, out sub))
+ {
+ dic[eventName] = sub = new Subscription(dic, typeof(TTarget), target, eventName);
+ }
+
+ sub.Add(subscriber);
+ }
+
+ ///
+ /// Unsubscribes from an event.
+ ///
+ /// The type of the event arguments.
+ /// The event source.
+ /// The name of the event.
+ /// The subscriber.
+ public static void Unsubscribe(object target, string eventName, EventHandler subscriber)
+ where TEventArgs : EventArgs where TSubscriber : class
+ {
+ SubscriptionDic dic;
+
+ if (SubscriptionTypeStorage.Subscribers.TryGetValue(target, out dic))
+ {
+ Subscription sub;
+
+ if (dic.TryGetValue(eventName, out sub))
+ {
+ sub.Remove(subscriber);
+ }
+ }
+ }
+
+ private static class SubscriptionTypeStorage
+ where TArgs : EventArgs where TSubscriber : class
+ {
+ public static readonly ConditionalWeakTable