diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets
index 4f9c4d7720..1b822c14cf 100644
--- a/packages/Avalonia/AvaloniaBuildTasks.targets
+++ b/packages/Avalonia/AvaloniaBuildTasks.targets
@@ -74,7 +74,7 @@
ReportImportance="$(AvaloniaXamlReportImportance)"/>
+ Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:GenerateAvaloniaResources /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
@@ -112,7 +112,7 @@
/>
+ Command="dotnet msbuild /nodereuse:false $(MSBuildProjectFile) /t:CompileAvaloniaXaml /p:_AvaloniaForceInternalMSBuild=true /p:Configuration=$(Configuration) /p:TargetFramework=$(TargetFramework) /p:RuntimeIdentifier=$(RuntimeIdentifier) /p:BuildProjectReferences=false"/>
diff --git a/samples/BindingDemo/App.xaml b/samples/BindingDemo/App.xaml
index 175e838616..5a8e65ed22 100644
--- a/samples/BindingDemo/App.xaml
+++ b/samples/BindingDemo/App.xaml
@@ -2,8 +2,14 @@
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="BindingDemo.App">
-
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/ExpanderPage.xaml b/samples/ControlCatalog/Pages/ExpanderPage.xaml
index f0a80fd7ab..b5a2e6cdd0 100644
--- a/samples/ControlCatalog/Pages/ExpanderPage.xaml
+++ b/samples/ControlCatalog/Pages/ExpanderPage.xaml
@@ -52,6 +52,24 @@
Rounded
+
+
+ Expanded content
+
+
+
+
+ Expanded content
+
+
diff --git a/samples/ControlCatalog/Pages/ExpanderPage.xaml.cs b/samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
index e8a080899a..98a494e533 100644
--- a/samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ExpanderPage.xaml.cs
@@ -10,6 +10,12 @@ namespace ControlCatalog.Pages
{
this.InitializeComponent();
DataContext = new ExpanderPageViewModel();
+
+ var CollapsingDisabledExpander = this.Get("CollapsingDisabledExpander");
+ var ExpandingDisabledExpander = this.Get("ExpandingDisabledExpander");
+
+ CollapsingDisabledExpander.Collapsing += (s, e) => { e.Handled = true; };
+ ExpandingDisabledExpander.Expanding += (s, e) => { e.Handled = true; };
}
private void InitializeComponent()
diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml
index 04129cb82d..dc0eaf0a51 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml
@@ -32,6 +32,7 @@
diff --git a/samples/ControlCatalog/Pages/TabControlPage.xaml b/samples/ControlCatalog/Pages/TabControlPage.xaml
index a830ce69ac..e289de90f9 100644
--- a/samples/ControlCatalog/Pages/TabControlPage.xaml
+++ b/samples/ControlCatalog/Pages/TabControlPage.xaml
@@ -53,14 +53,8 @@
-
-
-
-
-
-
diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
index 59489ebcc0..f89d9d1e20 100644
--- a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Reactive;
using Avalonia.Controls;
using Avalonia.Controls.Selection;
+using ControlCatalog.Pages;
using MiniMvvm;
namespace ControlCatalog.ViewModels
@@ -20,9 +21,9 @@ namespace ControlCatalog.ViewModels
public ListBoxPageViewModel()
{
- Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
+ Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
- Selection = new SelectionModel();
+ Selection = new SelectionModel();
Selection.Select(1);
_selectionMode = this.WhenAnyValue(
@@ -58,8 +59,8 @@ namespace ControlCatalog.ViewModels
});
}
- public ObservableCollection Items { get; }
- public SelectionModel Selection { get; }
+ public ObservableCollection Items { get; }
+ public SelectionModel Selection { get; }
public IObservable SelectionMode => _selectionMode;
public bool Multiple
@@ -96,6 +97,31 @@ namespace ControlCatalog.ViewModels
public MiniCommand RemoveItemCommand { get; }
public MiniCommand SelectRandomItemCommand { get; }
- private string GenerateItem() => $"Item {_counter++.ToString()}";
+ private ItemModel GenerateItem() => new ItemModel(_counter ++);
+ }
+
+ ///
+ /// An Item model for the
+ ///
+ public class ItemModel
+ {
+ ///
+ /// Creates a new ItemModel with the given ID
+ ///
+ /// The ID to display
+ public ItemModel(int id)
+ {
+ ID = id;
+ }
+
+ ///
+ /// The ID of this Item
+ ///
+ public int ID { get; }
+
+ public override string ToString()
+ {
+ return $"Item {ID}";
+ }
}
}
diff --git a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
index 83892247e6..93857fd899 100644
--- a/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/TransitioningContentControlPageViewModel.cs
@@ -293,10 +293,10 @@ namespace ControlCatalog.ViewModels
///
/// Any one of the parameters may be null, but not both.
///
- private static IVisual GetVisualParent(IVisual? from, IVisual? to)
+ private static Visual GetVisualParent(Visual? from, Visual? to)
{
- var p1 = (from ?? to)!.VisualParent;
- var p2 = (to ?? from)!.VisualParent;
+ var p1 = (from ?? to)!.GetVisualParent();
+ var p2 = (to ?? from)!.GetVisualParent();
if (p1 != null && p2 != null && p1 != p2)
{
diff --git a/src/Android/Avalonia.Android/AndroidInputMethod.cs b/src/Android/Avalonia.Android/AndroidInputMethod.cs
index b6adbde738..8d56086470 100644
--- a/src/Android/Avalonia.Android/AndroidInputMethod.cs
+++ b/src/Android/Avalonia.Android/AndroidInputMethod.cs
@@ -95,6 +95,10 @@ namespace Avalonia.Android
_imm.UpdateSelection(_host, surroundingText.AnchorOffset, surroundingText.CursorOffset, surroundingText.AnchorOffset, surroundingText.CursorOffset);
}
+ else
+ {
+ _imm.HideSoftInputFromWindow(_host.WindowToken, HideSoftInputFlags.ImplicitOnly);
+ }
}
private void SurroundingTextChanged(object sender, EventArgs e)
diff --git a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
index de8d02f188..b24581fb8b 100644
--- a/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
+++ b/src/Android/Avalonia.Android/AvaloniaMainActivity.cs
@@ -4,9 +4,12 @@ using Android.Content;
using Android.Content.Res;
using Android.OS;
using Android.Runtime;
+using Android.Views;
using AndroidX.AppCompat.App;
using AndroidX.Lifecycle;
+using AndroidRect = Android.Graphics.Rect;
+
namespace Avalonia.Android
{
public abstract class AvaloniaMainActivity : AppCompatActivity, IActivityResultHandler
@@ -15,6 +18,7 @@ namespace Avalonia.Android
public Action ActivityResult { get; set; }
internal AvaloniaView View;
+ private GlobalLayoutListener _listener;
protected override void OnCreate(Bundle savedInstanceState)
{
@@ -32,6 +36,10 @@ namespace Avalonia.Android
base.OnCreate(savedInstanceState);
SetContentView(View);
+
+ _listener = new GlobalLayoutListener(View);
+
+ View.ViewTreeObserver?.AddOnGlobalLayoutListener(_listener);
}
public object Content
@@ -57,6 +65,8 @@ namespace Avalonia.Android
{
View.Content = null;
+ View.ViewTreeObserver?.RemoveOnGlobalLayoutListener(_listener);
+
base.OnDestroy();
}
@@ -66,5 +76,20 @@ namespace Avalonia.Android
ActivityResult?.Invoke(requestCode, resultCode, data);
}
+
+ class GlobalLayoutListener : Java.Lang.Object, ViewTreeObserver.IOnGlobalLayoutListener
+ {
+ private AvaloniaView _view;
+
+ public GlobalLayoutListener(AvaloniaView view)
+ {
+ _view = view;
+ }
+
+ public void OnGlobalLayout()
+ {
+ _view.TopLevelImpl?.Resize(_view.TopLevelImpl.ClientSize);
+ }
+ }
}
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 5f53eb36c8..4150b52946 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -26,6 +26,7 @@ using Avalonia.Rendering;
using Avalonia.Rendering.Composition;
using Java.Lang;
using Math = System.Math;
+using AndroidRect = Android.Graphics.Rect;
namespace Avalonia.Android.Platform.SkiaPlatform
{
@@ -63,7 +64,21 @@ namespace Avalonia.Android.Platform.SkiaPlatform
public IInputRoot InputRoot { get; private set; }
- public virtual Size ClientSize => Size.ToSize(RenderScaling);
+ public virtual Size ClientSize
+ {
+ get
+ {
+ AndroidRect rect = new AndroidRect();
+ AndroidRect intersection = new AndroidRect();
+
+ _view.GetWindowVisibleDisplayFrame(intersection);
+ _view.GetGlobalVisibleRect(rect);
+
+ intersection.Intersect(rect);
+
+ return new PixelSize(intersection.Right - intersection.Left, intersection.Bottom - intersection.Top).ToSize(RenderScaling);
+ }
+ }
public Size? FrameSize => null;
@@ -94,7 +109,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
? new CompositingRenderer(root, AndroidPlatform.Compositor)
: AndroidPlatform.Options.UseDeferredRendering
? new DeferredRenderer(root, AvaloniaLocator.Current.GetRequiredService()) { RenderOnlyOnRenderThread = true }
- : new ImmediateRenderer(root);
+ : new ImmediateRenderer((Visual)root);
public virtual void Hide()
{
@@ -149,6 +164,11 @@ namespace Avalonia.Android.Platform.SkiaPlatform
Resized?.Invoke(size, PlatformResizeReason.Unspecified);
}
+ internal void Resize(Size size)
+ {
+ Resized?.Invoke(size, PlatformResizeReason.Layout);
+ }
+
class ViewImpl : InvalidationAwareSurfaceView, ISurfaceHolderCallback, IInitEditorInfo
{
private readonly TopLevelImpl _tl;
diff --git a/src/Avalonia.Base/Animation/PageSlide.cs b/src/Avalonia.Base/Animation/PageSlide.cs
index b22bc8b243..609441ae8c 100644
--- a/src/Avalonia.Base/Animation/PageSlide.cs
+++ b/src/Avalonia.Base/Animation/PageSlide.cs
@@ -157,7 +157,7 @@ namespace Avalonia.Animation
///
/// Any one of the parameters may be null, but not both.
///
- protected static IVisual GetVisualParent(IVisual? from, IVisual? to)
+ protected static Visual GetVisualParent(Visual? from, Visual? to)
{
var p1 = (from ?? to)!.VisualParent;
var p2 = (to ?? from)!.VisualParent;
diff --git a/src/Avalonia.Base/AttachedProperty.cs b/src/Avalonia.Base/AttachedProperty.cs
index 12c569c452..a43194153c 100644
--- a/src/Avalonia.Base/AttachedProperty.cs
+++ b/src/Avalonia.Base/AttachedProperty.cs
@@ -34,7 +34,7 @@ namespace Avalonia
///
/// The owner type.
/// The property.
- public new AttachedProperty AddOwner() where TOwner : IAvaloniaObject
+ public new AttachedProperty AddOwner() where TOwner : AvaloniaObject
{
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), this);
return this;
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 68c8f19f19..a3a732428e 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -16,7 +16,7 @@ namespace Avalonia
///
/// This class is analogous to DependencyObject in WPF.
///
- public class AvaloniaObject : IAvaloniaObject, IAvaloniaObjectDebug, INotifyPropertyChanged
+ public class AvaloniaObject : IAvaloniaObjectDebug, INotifyPropertyChanged
{
private readonly ValueStore _values;
private AvaloniaObject? _inheritanceParent;
diff --git a/src/Avalonia.Base/AvaloniaObjectExtensions.cs b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
index 9644063da7..867d6215a5 100644
--- a/src/Avalonia.Base/AvaloniaObjectExtensions.cs
+++ b/src/Avalonia.Base/AvaloniaObjectExtensions.cs
@@ -36,7 +36,7 @@ namespace Avalonia
///
/// The subscription to is created using a weak reference.
///
- public static IObservable