diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 14fe60ab0b..7a6e7dc72f 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -641,6 +641,7 @@ private:
[Window setCanBecomeKeyAndMain];
[Window disableCursorRects];
[Window setTabbingMode:NSWindowTabbingModeDisallowed];
+ [Window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
}
void HideOrShowTrafficLights ()
@@ -1091,14 +1092,7 @@ private:
{
_fullScreenActive = true;
- [Window setHasShadow:YES];
- [Window setTitleVisibility:NSWindowTitleVisible];
- [Window setTitlebarAppearsTransparent:NO];
[Window setTitle:_lastTitle];
-
- Window.styleMask = Window.styleMask | NSWindowStyleMaskTitled | NSWindowStyleMaskResizable;
- Window.styleMask = Window.styleMask & ~NSWindowStyleMaskFullSizeContentView;
-
[Window toggleFullScreen:nullptr];
}
@@ -1672,6 +1666,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
switch(event.buttonNumber)
{
+ case 2:
case 3:
_isMiddlePressed = true;
[self mouseEvent:event withType:MiddleButtonDown];
@@ -1704,6 +1699,7 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
{
switch(event.buttonNumber)
{
+ case 2:
case 3:
_isMiddlePressed = false;
[self mouseEvent:event withType:MiddleButtonUp];
diff --git a/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs b/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
index 9ec600d2bc..2385d4981c 100644
--- a/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/FuncValueConverter.cs
@@ -26,7 +26,7 @@ namespace Avalonia.Data.Converters
///
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
- if (value is TIn || (value == null && TypeUtilities.AcceptsNull(typeof(TIn))))
+ if (TypeUtilities.CanCast(value))
{
return _convert((TIn)value);
}
diff --git a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
index 1a78792173..326d1a3f53 100644
--- a/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
+++ b/src/Avalonia.Base/Threading/AvaloniaSynchronizationContext.cs
@@ -39,7 +39,7 @@ namespace Avalonia.Threading
if (Dispatcher.UIThread.CheckAccess())
d(state);
else
- Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).Wait();
+ Dispatcher.UIThread.InvokeAsync(() => d(state), DispatcherPriority.Send).GetAwaiter().GetResult();
}
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index 179ded3549..0978308ef6 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -3,6 +3,7 @@ using System.ComponentModel;
using System.Globalization;
using System.Linq;
using System.Reflection;
+using System.Runtime.CompilerServices;
namespace Avalonia.Utilities
{
@@ -93,6 +94,17 @@ namespace Avalonia.Utilities
return !type.IsValueType || IsNullableType(type);
}
+ ///
+ /// Returns a value indicating whether null can be assigned to the specified type.
+ ///
+ /// The type
+ /// True if the type accepts null values; otherwise false.
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static bool AcceptsNull()
+ {
+ return default(T) is null;
+ }
+
///
/// Returns a value indicating whether value can be casted to the specified type.
/// If value is null, checks if instances of that type can be null.
@@ -102,7 +114,7 @@ namespace Avalonia.Utilities
/// True if the cast is possible, otherwise false.
public static bool CanCast(object value)
{
- return value is T || (value is null && AcceptsNull(typeof(T)));
+ return value is T || (value is null && AcceptsNull());
}
///
diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs
index 5a6e78f441..0e946126ea 100644
--- a/src/Avalonia.Controls/AutoCompleteBox.cs
+++ b/src/Avalonia.Controls/AutoCompleteBox.cs
@@ -2094,7 +2094,21 @@ namespace Avalonia.Controls
bool inResults = !(stringFiltering || objectFiltering);
if (!inResults)
{
- inResults = stringFiltering ? TextFilter(text, FormatValue(item)) : ItemFilter(text, item);
+ if (stringFiltering)
+ {
+ inResults = TextFilter(text, FormatValue(item));
+ }
+ else
+ {
+ if (ItemFilter is null)
+ {
+ throw new Exception("ItemFilter property can not be null when FilterMode has value AutoCompleteFilterMode.Custom");
+ }
+ else
+ {
+ inResults = ItemFilter(text, item);
+ }
+ }
}
if (view_count > view_index && inResults && _view[view_index] == item)
diff --git a/src/Avalonia.Controls/TextBox.cs b/src/Avalonia.Controls/TextBox.cs
index 0eade8d6df..9eae928eeb 100644
--- a/src/Avalonia.Controls/TextBox.cs
+++ b/src/Avalonia.Controls/TextBox.cs
@@ -145,6 +145,18 @@ namespace Avalonia.Controls
(o, v) => o.UndoLimit = v,
unsetValue: -1);
+ public static readonly RoutedEvent CopyingToClipboardEvent =
+ RoutedEvent.Register(
+ "CopyingToClipboard", RoutingStrategies.Bubble);
+
+ public static readonly RoutedEvent CuttingToClipboardEvent =
+ RoutedEvent.Register(
+ "CuttingToClipboard", RoutingStrategies.Bubble);
+
+ public static readonly RoutedEvent PastingFromClipboardEvent =
+ RoutedEvent.Register(
+ "PastingFromClipboard", RoutingStrategies.Bubble);
+
readonly struct UndoRedoState : IEquatable
{
public string Text { get; }
@@ -500,6 +512,24 @@ namespace Avalonia.Controls
}
}
+ public event EventHandler CopyingToClipboard
+ {
+ add => AddHandler(CopyingToClipboardEvent, value);
+ remove => RemoveHandler(CopyingToClipboardEvent, value);
+ }
+
+ public event EventHandler CuttingToClipboard
+ {
+ add => AddHandler(CuttingToClipboardEvent, value);
+ remove => RemoveHandler(CuttingToClipboardEvent, value);
+ }
+
+ public event EventHandler PastingFromClipboard
+ {
+ add => AddHandler(PastingFromClipboardEvent, value);
+ remove => RemoveHandler(PastingFromClipboardEvent, value);
+ }
+
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
_presenter = e.NameScope.Get("PART_TextPresenter");
@@ -638,27 +668,54 @@ namespace Avalonia.Controls
public async void Cut()
{
var text = GetSelection();
- if (text is null) return;
+ if (string.IsNullOrEmpty(text))
+ {
+ return;
+ }
- SnapshotUndoRedo();
- Copy();
- DeleteSelection();
+ var eventArgs = new RoutedEventArgs(CuttingToClipboardEvent);
+ RaiseEvent(eventArgs);
+ if (!eventArgs.Handled)
+ {
+ SnapshotUndoRedo();
+ await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)))
+ .SetTextAsync(text);
+ DeleteSelection();
+ }
}
public async void Copy()
{
var text = GetSelection();
- if (text is null) return;
+ if (string.IsNullOrEmpty(text))
+ {
+ return;
+ }
- await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)))
- .SetTextAsync(text);
+ var eventArgs = new RoutedEventArgs(CopyingToClipboardEvent);
+ RaiseEvent(eventArgs);
+ if (!eventArgs.Handled)
+ {
+ await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard)))
+ .SetTextAsync(text);
+ }
}
public async void Paste()
{
+ var eventArgs = new RoutedEventArgs(PastingFromClipboardEvent);
+ RaiseEvent(eventArgs);
+ if (eventArgs.Handled)
+ {
+ return;
+ }
+
var text = await ((IClipboard)AvaloniaLocator.Current.GetService(typeof(IClipboard))).GetTextAsync();
- if (text is null) return;
+ if (string.IsNullOrEmpty(text))
+ {
+ return;
+ }
SnapshotUndoRedo();
HandleTextInput(text);
diff --git a/src/Avalonia.Input/AccessKeyHandler.cs b/src/Avalonia.Input/AccessKeyHandler.cs
index 5c4af68d79..5082265ea6 100644
--- a/src/Avalonia.Input/AccessKeyHandler.cs
+++ b/src/Avalonia.Input/AccessKeyHandler.cs
@@ -157,10 +157,9 @@ namespace Avalonia.Input
_restoreFocusElement?.Focus();
_restoreFocusElement = null;
+
+ e.Handled = true;
}
-
- // We always handle the Alt key.
- e.Handled = true;
}
else if (_altIsDown)
{
diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
index 9e90d34e97..f4ac681b91 160000
--- a/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
+++ b/src/Markup/Avalonia.Markup.Xaml.Loader/xamlil.github
@@ -1 +1 @@
-Subproject commit 9e90d34e97c766ba8dcb70128147fcded65d195a
+Subproject commit f4ac681b91a9dc7a7a095d1050a683de23d86b72
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 3b7d3efa2f..8fc25f8cfa 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -263,10 +263,8 @@ namespace Avalonia.Win32
{
ShowWindow(value, true);
}
- else
- {
- _showWindowState = value;
- }
+
+ _showWindowState = value;
}
}
diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
index b346fca330..c8bd289e54 100644
--- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
@@ -105,6 +105,16 @@ namespace Avalonia.Controls.UnitTests
});
}
+ [Fact]
+ public void Custom_FilterMode_Without_ItemFilter_Setting_Throws_Exception()
+ {
+ RunTest((control, textbox) =>
+ {
+ control.FilterMode = AutoCompleteFilterMode.Custom;
+ Assert.Throws(() => { control.Text = "a"; });
+ });
+ }
+
[Fact]
public void Text_Completion_Via_Text_Property()
{