diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 92e4afdca8..603308ef9a 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -52,7 +52,7 @@ jobs:
sdk: 'macosx10.14'
configuration: 'Release'
xcWorkspacePath: '**/*.xcodeproj/project.xcworkspace'
- xcodeVersion: 'default' # Options: 8, 9, default, specifyPath
+ xcodeVersion: '10' # Options: 8, 9, default, specifyPath
args: '-derivedDataPath ./'
- task: CmdLine@2
diff --git a/src/Avalonia.Base/EnumExtensions.cs b/src/Avalonia.Base/EnumExtensions.cs
new file mode 100644
index 0000000000..a8306c2d69
--- /dev/null
+++ b/src/Avalonia.Base/EnumExtensions.cs
@@ -0,0 +1,23 @@
+// 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.Runtime.CompilerServices;
+
+namespace Avalonia
+{
+ ///
+ /// Provides extension methods for enums.
+ ///
+ public static class EnumExtensions
+ {
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static unsafe bool HasFlagCustom(this T value, T flag) where T : unmanaged, Enum
+ {
+ var intValue = *(int*)&value;
+ var intFlag = *(int*)&flag;
+
+ return (intValue & intFlag) == intFlag;
+ }
+ }
+}
diff --git a/src/Avalonia.Base/Utilities/MathUtilities.cs b/src/Avalonia.Base/Utilities/MathUtilities.cs
index 41b57b6e70..027028480c 100644
--- a/src/Avalonia.Base/Utilities/MathUtilities.cs
+++ b/src/Avalonia.Base/Utilities/MathUtilities.cs
@@ -159,6 +159,11 @@ namespace Avalonia.Utilities
/// The clamped value.
public static int Clamp(int val, int min, int max)
{
+ if (min > max)
+ {
+ throw new ArgumentException($"{min} cannot be greater than {max}.");
+ }
+
if (val < min)
{
return min;
diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
index a6a64e570b..d99648a158 100644
--- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
@@ -48,11 +48,6 @@ namespace Avalonia.Controls.Generators
tabItem[~ContentControl.ContentTemplateProperty] = Owner[~TabControl.ContentTemplateProperty];
}
- if (tabItem.Content == null)
- {
- tabItem[~ContentControl.ContentProperty] = tabItem[~StyledElement.DataContextProperty];
- }
-
return tabItem;
}
}
diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs
index b027da6d0c..bf22f0a08a 100644
--- a/src/Avalonia.Controls/ItemsControl.cs
+++ b/src/Avalonia.Controls/ItemsControl.cs
@@ -359,6 +359,12 @@ namespace Avalonia.Controls
UpdateItemCount();
RemoveControlItemsFromLogicalChildren(oldValue);
AddControlItemsToLogicalChildren(newValue);
+
+ if (Presenter != null)
+ {
+ Presenter.Items = newValue;
+ }
+
SubscribeToItems(newValue);
}
@@ -370,6 +376,8 @@ namespace Avalonia.Controls
/// The event args.
protected virtual void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
+ UpdateItemCount();
+
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
@@ -381,7 +389,7 @@ namespace Avalonia.Controls
break;
}
- UpdateItemCount();
+ Presenter?.ItemsChanged(e);
var collection = sender as ICollection;
PseudoClasses.Set(":empty", collection == null || collection.Count == 0);
diff --git a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
index 42311dc781..c4acf1ebef 100644
--- a/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/IItemsPresenter.cs
@@ -1,12 +1,19 @@
// 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.Collections;
+using System.Collections.Specialized;
+
namespace Avalonia.Controls.Presenters
{
public interface IItemsPresenter : IPresenter
{
+ IEnumerable Items { get; set; }
+
IPanel Panel { get; }
+ void ItemsChanged(NotifyCollectionChangedEventArgs e);
+
void ScrollIntoView(object item);
}
}
diff --git a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
index 0f0cdc37cf..ef1f277162 100644
--- a/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
+++ b/src/Avalonia.Controls/Presenters/ItemsPresenterBase.cs
@@ -63,7 +63,7 @@ namespace Avalonia.Controls.Presenters
_itemsSubscription?.Dispose();
_itemsSubscription = null;
- if (_createdPanel && value is INotifyCollectionChanged incc)
+ if (!IsHosted && _createdPanel && value is INotifyCollectionChanged incc)
{
_itemsSubscription = incc.WeakSubscribe(ItemsCollectionChanged);
}
@@ -130,6 +130,8 @@ namespace Avalonia.Controls.Presenters
private set;
}
+ protected bool IsHosted => TemplatedParent is IItemsPresenterHost;
+
///
public override sealed void ApplyTemplate()
{
@@ -144,6 +146,15 @@ namespace Avalonia.Controls.Presenters
{
}
+ ///
+ void IItemsPresenter.ItemsChanged(NotifyCollectionChangedEventArgs e)
+ {
+ if (Panel != null)
+ {
+ ItemsChanged(e);
+ }
+ }
+
///
/// Creates the for the control.
///
@@ -215,7 +226,7 @@ namespace Avalonia.Controls.Presenters
_createdPanel = true;
- if (_itemsSubscription == null && Items is INotifyCollectionChanged incc)
+ if (!IsHosted && _itemsSubscription == null && Items is INotifyCollectionChanged incc)
{
_itemsSubscription = incc.WeakSubscribe(ItemsCollectionChanged);
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 7fddee1012..b6ae567123 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -302,13 +302,24 @@ namespace Avalonia.Controls.Primitives
///
protected override void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
- base.ItemsCollectionChanged(sender, e);
-
if (_updateCount > 0)
{
+ base.ItemsCollectionChanged(sender, e);
return;
}
+ switch (e.Action)
+ {
+ case NotifyCollectionChangedAction.Add:
+ _selection.ItemsInserted(e.NewStartingIndex, e.NewItems.Count);
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ _selection.ItemsRemoved(e.OldStartingIndex, e.OldItems.Count);
+ break;
+ }
+
+ base.ItemsCollectionChanged(sender, e);
+
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
@@ -318,14 +329,12 @@ namespace Avalonia.Controls.Primitives
}
else
{
- _selection.ItemsInserted(e.NewStartingIndex, e.NewItems.Count);
UpdateSelectedItem(_selection.First(), false);
}
break;
case NotifyCollectionChangedAction.Remove:
- _selection.ItemsRemoved(e.OldStartingIndex, e.OldItems.Count);
UpdateSelectedItem(_selection.First(), false);
ResetSelectedItems();
break;
@@ -1088,9 +1097,15 @@ namespace Avalonia.Controls.Primitives
}
else
{
- SelectedIndex = _updateSelectedIndex != int.MinValue ?
- _updateSelectedIndex :
- AlwaysSelected ? 0 : -1;
+ if (_updateSelectedIndex != int.MinValue)
+ {
+ SelectedIndex = _updateSelectedIndex;
+ }
+
+ if (AlwaysSelected && SelectedIndex == -1)
+ {
+ SelectedIndex = 0;
+ }
}
}
}
diff --git a/src/Avalonia.Controls/ToolTipService.cs b/src/Avalonia.Controls/ToolTipService.cs
index 384a9db0cf..d90729e8a5 100644
--- a/src/Avalonia.Controls/ToolTipService.cs
+++ b/src/Avalonia.Controls/ToolTipService.cs
@@ -1,6 +1,7 @@
using System;
using Avalonia.Input;
using Avalonia.Threading;
+using Avalonia.VisualTree;
namespace Avalonia.Controls
{
@@ -79,7 +80,10 @@ namespace Avalonia.Controls
{
StopTimer();
- ToolTip.SetIsOpen(control, true);
+ if ((control as IVisual).IsAttachedToVisualTree)
+ {
+ ToolTip.SetIsOpen(control, true);
+ }
}
private void Close(Control control)
diff --git a/src/Avalonia.Controls/WrapPanel.cs b/src/Avalonia.Controls/WrapPanel.cs
index 7c88401615..d06a71a9f8 100644
--- a/src/Avalonia.Controls/WrapPanel.cs
+++ b/src/Avalonia.Controls/WrapPanel.cs
@@ -42,7 +42,7 @@ namespace Avalonia.Controls
///
static WrapPanel()
{
- AffectsMeasure(OrientationProperty);
+ AffectsMeasure(OrientationProperty, ItemWidthProperty, ItemHeightProperty);
}
///
diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs
index c84596b913..4dcf0eee53 100644
--- a/src/Avalonia.Input/MouseDevice.cs
+++ b/src/Avalonia.Input/MouseDevice.cs
@@ -14,13 +14,14 @@ namespace Avalonia.Input
///
/// Represents a mouse device.
///
- public class MouseDevice : IMouseDevice
+ public class MouseDevice : IMouseDevice, IDisposable
{
private int _clickCount;
private Rect _lastClickRect;
private ulong _lastClickTime;
private readonly Pointer _pointer;
+ private bool _disposed;
public MouseDevice(Pointer pointer = null)
{
@@ -126,7 +127,9 @@ namespace Avalonia.Input
{
Contract.Requires(e != null);
- var mouse = (IMouseDevice)e.Device;
+ var mouse = (MouseDevice)e.Device;
+ if(mouse._disposed)
+ return;
Position = e.Root.PointToScreen(e.Position);
var props = CreateProperties(e);
@@ -441,5 +444,11 @@ namespace Avalonia.Input
el = (IInputElement)el.VisualParent;
}
}
+
+ public void Dispose()
+ {
+ _disposed = true;
+ _pointer?.Dispose();
+ }
}
}
diff --git a/src/Avalonia.Input/Pointer.cs b/src/Avalonia.Input/Pointer.cs
index 80d803abb1..819d231b31 100644
--- a/src/Avalonia.Input/Pointer.cs
+++ b/src/Avalonia.Input/Pointer.cs
@@ -37,7 +37,7 @@ namespace Avalonia.Input
{
if (Captured != null)
Captured.DetachedFromVisualTree -= OnCaptureDetached;
- var oldCapture = control;
+ var oldCapture = Captured;
Captured = control;
PlatformCapture(control);
if (oldCapture != null)
diff --git a/src/Avalonia.Input/PointerPoint.cs b/src/Avalonia.Input/PointerPoint.cs
index e9f3c02b7f..1068a0d4d4 100644
--- a/src/Avalonia.Input/PointerPoint.cs
+++ b/src/Avalonia.Input/PointerPoint.cs
@@ -1,3 +1,6 @@
+// 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.Input
{
public sealed class PointerPoint
@@ -27,9 +30,9 @@ namespace Avalonia.Input
public PointerPointProperties(RawInputModifiers modifiers, PointerUpdateKind kind)
{
PointerUpdateKind = kind;
- IsLeftButtonPressed = modifiers.HasFlag(RawInputModifiers.LeftMouseButton);
- IsMiddleButtonPressed = modifiers.HasFlag(RawInputModifiers.MiddleMouseButton);
- IsRightButtonPressed = modifiers.HasFlag(RawInputModifiers.RightMouseButton);
+ IsLeftButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.LeftMouseButton);
+ IsMiddleButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.MiddleMouseButton);
+ IsRightButtonPressed = modifiers.HasFlagCustom(RawInputModifiers.RightMouseButton);
// The underlying input source might be reporting the previous state,
// so make sure that we reflect the current state
diff --git a/src/Avalonia.Input/TouchDevice.cs b/src/Avalonia.Input/TouchDevice.cs
index b231c9fff4..d6ad836f37 100644
--- a/src/Avalonia.Input/TouchDevice.cs
+++ b/src/Avalonia.Input/TouchDevice.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Input.Raw;
@@ -11,10 +12,11 @@ namespace Avalonia.Input
/// This class is supposed to be used on per-toplevel basis, don't use a shared one
///
///
- public class TouchDevice : IInputDevice
+ public class TouchDevice : IInputDevice, IDisposable
{
- Dictionary _pointers = new Dictionary();
-
+ private readonly Dictionary _pointers = new Dictionary();
+ private bool _disposed;
+
KeyModifiers GetKeyModifiers(RawInputModifiers modifiers) =>
(KeyModifiers)(modifiers & RawInputModifiers.KeyboardMask);
@@ -28,6 +30,8 @@ namespace Avalonia.Input
public void ProcessRawEvent(RawInputEventArgs ev)
{
+ if(_disposed)
+ return;
var args = (RawTouchEventArgs)ev;
if (!_pointers.TryGetValue(args.TouchPointId, out var pointer))
{
@@ -82,6 +86,17 @@ namespace Avalonia.Input
}
+
+ public void Dispose()
+ {
+ if(_disposed)
+ return;
+ var values = _pointers.Values.ToList();
+ _pointers.Clear();
+ _disposed = true;
+ foreach (var p in values)
+ p.Dispose();
+ }
}
}
diff --git a/src/Avalonia.Native/AvaloniaNativePlatform.cs b/src/Avalonia.Native/AvaloniaNativePlatform.cs
index ddb71b61bb..fab3ce36b8 100644
--- a/src/Avalonia.Native/AvaloniaNativePlatform.cs
+++ b/src/Avalonia.Native/AvaloniaNativePlatform.cs
@@ -95,7 +95,6 @@ namespace Avalonia.Native
.Bind().ToConstant(new CursorFactory(_factory.CreateCursorFactory()))
.Bind().ToSingleton()
.Bind().ToConstant(KeyboardDevice)
- .Bind().ToConstant(MouseDevice)
.Bind().ToConstant(this)
.Bind().ToConstant(this)
.Bind().ToConstant(new ClipboardImpl(_factory.CreateClipboard()))
diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs
index fe7458d583..7f1fab4b1c 100644
--- a/src/Avalonia.Native/WindowImplBase.cs
+++ b/src/Avalonia.Native/WindowImplBase.cs
@@ -24,7 +24,7 @@ namespace Avalonia.Native
private object _syncRoot = new object();
private bool _deferredRendering = false;
private bool _gpu = false;
- private readonly IMouseDevice _mouse;
+ private readonly MouseDevice _mouse;
private readonly IKeyboardDevice _keyboard;
private readonly IStandardCursorFactory _cursorFactory;
private Size _savedLogicalSize;
@@ -38,7 +38,7 @@ namespace Avalonia.Native
_deferredRendering = opts.UseDeferredRendering;
_keyboard = AvaloniaLocator.Current.GetService();
- _mouse = AvaloniaLocator.Current.GetService();
+ _mouse = new MouseDevice();
_cursorFactory = AvaloniaLocator.Current.GetService();
}
@@ -142,6 +142,7 @@ namespace Avalonia.Native
{
n?.Dispose();
}
+ _parent._mouse.Dispose();
}
void IAvnWindowBaseEvents.Activated() => _parent.Activated?.Invoke();
diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
index 558e96e132..1689f2e964 100644
--- a/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
+++ b/src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
@@ -51,7 +51,7 @@ namespace Avalonia.Rendering.SceneGraph
UpdateSize(scene);
}
- if (visual.VisualRoot != null)
+ if (visual.VisualRoot == scene.Root.Visual)
{
if (node?.Parent != null &&
visual.VisualParent != null &&
diff --git a/src/Avalonia.X11/X11Platform.cs b/src/Avalonia.X11/X11Platform.cs
index d7a7bb97fd..6ba562bb69 100644
--- a/src/Avalonia.X11/X11Platform.cs
+++ b/src/Avalonia.X11/X11Platform.cs
@@ -19,9 +19,7 @@ namespace Avalonia.X11
class AvaloniaX11Platform : IWindowingPlatform
{
private Lazy _keyboardDevice = new Lazy(() => new KeyboardDevice());
- private Lazy _mouseDevice = new Lazy(() => new MouseDevice());
public KeyboardDevice KeyboardDevice => _keyboardDevice.Value;
- public MouseDevice MouseDevice => _mouseDevice.Value;
public Dictionary> Windows = new Dictionary>();
public XI2Manager XI2;
public X11Info Info { get; private set; }
diff --git a/src/Avalonia.X11/X11Window.cs b/src/Avalonia.X11/X11Window.cs
index 17471fad10..32460fed86 100644
--- a/src/Avalonia.X11/X11Window.cs
+++ b/src/Avalonia.X11/X11Window.cs
@@ -32,7 +32,8 @@ namespace Avalonia.X11
private PixelPoint? _configurePoint;
private bool _triggeredExpose;
private IInputRoot _inputRoot;
- private readonly IMouseDevice _mouse;
+ private readonly MouseDevice _mouse;
+ private readonly TouchDevice _touch;
private readonly IKeyboardDevice _keyboard;
private PixelPoint? _position;
private PixelSize _realSize;
@@ -57,7 +58,8 @@ namespace Avalonia.X11
_platform = platform;
_popup = popupParent != null;
_x11 = platform.Info;
- _mouse = platform.MouseDevice;
+ _mouse = new MouseDevice();
+ _touch = new TouchDevice();
_keyboard = platform.KeyboardDevice;
var glfeature = AvaloniaLocator.Current.GetService();
@@ -702,6 +704,8 @@ namespace Avalonia.X11
_platform.XI2?.OnWindowDestroyed(_handle);
_handle = IntPtr.Zero;
Closed?.Invoke();
+ _mouse.Dispose();
+ _touch.Dispose();
}
if (_useRenderWindow && _renderHandle != IntPtr.Zero)
@@ -830,6 +834,8 @@ namespace Avalonia.X11
}
public IMouseDevice MouseDevice => _mouse;
+ public TouchDevice TouchDevice => _touch;
+
public IPopupImpl CreatePopup()
=> _platform.Options.OverlayPopups ? null : new X11Window(_platform, this);
diff --git a/src/Avalonia.X11/XI2Manager.cs b/src/Avalonia.X11/XI2Manager.cs
index 6989d6d26d..e37ed39bee 100644
--- a/src/Avalonia.X11/XI2Manager.cs
+++ b/src/Avalonia.X11/XI2Manager.cs
@@ -92,8 +92,6 @@ namespace Avalonia.X11
private PointerDeviceInfo _pointerDevice;
private AvaloniaX11Platform _platform;
- private readonly TouchDevice _touchDevice = new TouchDevice();
-
public bool Init(AvaloniaX11Platform platform)
{
@@ -198,7 +196,7 @@ namespace Avalonia.X11
(ev.Type == XiEventType.XI_TouchUpdate ?
RawPointerEventType.TouchUpdate :
RawPointerEventType.TouchEnd);
- client.ScheduleInput(new RawTouchEventArgs(_touchDevice,
+ client.ScheduleInput(new RawTouchEventArgs(client.TouchDevice,
ev.Timestamp, client.InputRoot, type, ev.Position, ev.Modifiers, ev.Detail));
return;
}
@@ -232,10 +230,10 @@ namespace Avalonia.X11
}
if (scrollDelta != default)
- client.ScheduleInput(new RawMouseWheelEventArgs(_platform.MouseDevice, ev.Timestamp,
+ client.ScheduleInput(new RawMouseWheelEventArgs(client.MouseDevice, ev.Timestamp,
client.InputRoot, ev.Position, scrollDelta, ev.Modifiers));
if (_pointerDevice.HasMotion(ev))
- client.ScheduleInput(new RawPointerEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot,
+ client.ScheduleInput(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
RawPointerEventType.Move, ev.Position, ev.Modifiers));
}
@@ -248,7 +246,7 @@ namespace Avalonia.X11
: ev.Button == 3 ? (down ? RawPointerEventType.RightButtonDown : RawPointerEventType.RightButtonUp)
: (RawPointerEventType?)null;
if (type.HasValue)
- client.ScheduleInput(new RawPointerEventArgs(_platform.MouseDevice, ev.Timestamp, client.InputRoot,
+ client.ScheduleInput(new RawPointerEventArgs(client.MouseDevice, ev.Timestamp, client.InputRoot,
type.Value, ev.Position, ev.Modifiers));
}
@@ -310,5 +308,7 @@ namespace Avalonia.X11
{
IInputRoot InputRoot { get; }
void ScheduleInput(RawInputEventArgs args);
+ IMouseDevice MouseDevice { get; }
+ TouchDevice TouchDevice { get; }
}
}
diff --git a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
index e7c379ad89..8f060b1b81 100644
--- a/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
+++ b/src/Windows/Avalonia.Win32/Input/WindowsMouseDevice.cs
@@ -11,19 +11,11 @@ namespace Avalonia.Win32.Input
{
class WindowsMouseDevice : MouseDevice
{
- public static WindowsMouseDevice Instance { get; } = new WindowsMouseDevice();
-
public WindowsMouseDevice() : base(new WindowsMousePointer())
{
}
- public WindowImpl CurrentWindow
- {
- get;
- set;
- }
-
class WindowsMousePointer : Pointer
{
public WindowsMousePointer() : base(Pointer.GetNextFreeId(),PointerType.Mouse, true)
diff --git a/src/Windows/Avalonia.Win32/WindowImpl.cs b/src/Windows/Avalonia.Win32/WindowImpl.cs
index 04a9303d53..2ae200a179 100644
--- a/src/Windows/Avalonia.Win32/WindowImpl.cs
+++ b/src/Windows/Avalonia.Win32/WindowImpl.cs
@@ -30,6 +30,7 @@ namespace Avalonia.Win32
private IntPtr _hwnd;
private bool _multitouch;
private TouchDevice _touchDevice = new TouchDevice();
+ private MouseDevice _mouseDevice = new WindowsMouseDevice();
private IInputRoot _owner;
private ManagedDeferredRendererLock _rendererLock = new ManagedDeferredRendererLock();
private bool _trackingMouse;
@@ -205,7 +206,7 @@ namespace Avalonia.Win32
}
}
- public IMouseDevice MouseDevice => WindowsMouseDevice.Instance;
+ public IMouseDevice MouseDevice => _mouseDevice;
public WindowState WindowState
{
@@ -333,7 +334,7 @@ namespace Avalonia.Win32
public void BeginMoveDrag(PointerPressedEventArgs e)
{
- WindowsMouseDevice.Instance.Capture(null);
+ _mouseDevice.Capture(null);
UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)UnmanagedMethods.HitTestValues.HTCAPTION), IntPtr.Zero);
e.Pointer.Capture(null);
@@ -356,7 +357,7 @@ namespace Avalonia.Win32
#if USE_MANAGED_DRAG
_managedDrag.BeginResizeDrag(edge, ScreenToClient(MouseDevice.Position));
#else
- WindowsMouseDevice.Instance.Capture(null);
+ _mouseDevice.Capture(null);
UnmanagedMethods.DefWindowProc(_hwnd, (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN,
new IntPtr((int)EdgeDic[edge]), IntPtr.Zero);
#endif
@@ -437,9 +438,7 @@ namespace Avalonia.Win32
uint timestamp = unchecked((uint)UnmanagedMethods.GetMessageTime());
RawInputEventArgs e = null;
-
- WindowsMouseDevice.Instance.CurrentWindow = this;
-
+
switch ((UnmanagedMethods.WindowsMessage)msg)
{
case UnmanagedMethods.WindowsMessage.WM_ACTIVATE:
@@ -485,6 +484,8 @@ namespace Avalonia.Win32
_parent._disabledBy.Remove(this);
_parent.UpdateEnabled();
}
+ _mouseDevice.Dispose();
+ _touchDevice?.Dispose();
//Free other resources
Dispose();
return IntPtr.Zero;
@@ -542,7 +543,7 @@ namespace Avalonia.Win32
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawPointerEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONDOWN
@@ -559,7 +560,7 @@ namespace Avalonia.Win32
if(ShouldIgnoreTouchEmulatedMessage())
break;
e = new RawPointerEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_LBUTTONUP
@@ -587,7 +588,7 @@ namespace Avalonia.Win32
}
e = new RawPointerEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
RawPointerEventType.Move,
@@ -597,7 +598,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEWHEEL:
e = new RawMouseWheelEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
PointToClient(PointFromLParam(lParam)),
@@ -606,7 +607,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSEHWHEEL:
e = new RawMouseWheelEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
PointToClient(PointFromLParam(lParam)),
@@ -616,7 +617,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_MOUSELEAVE:
_trackingMouse = false;
e = new RawPointerEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
RawPointerEventType.LeaveWindow,
@@ -627,7 +628,7 @@ namespace Avalonia.Win32
case UnmanagedMethods.WindowsMessage.WM_NCRBUTTONDOWN:
case UnmanagedMethods.WindowsMessage.WM_NCMBUTTONDOWN:
e = new RawPointerEventArgs(
- WindowsMouseDevice.Instance,
+ _mouseDevice,
timestamp,
_owner,
msg == (int)UnmanagedMethods.WindowsMessage.WM_NCLBUTTONDOWN
@@ -649,9 +650,9 @@ namespace Avalonia.Win32
{
Input?.Invoke(new RawTouchEventArgs(_touchDevice, touchInput.Time,
_owner,
- touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_UP) ?
+ touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_UP) ?
RawPointerEventType.TouchEnd :
- touchInput.Flags.HasFlag(TouchInputFlags.TOUCHEVENTF_DOWN) ?
+ touchInput.Flags.HasFlagCustom(TouchInputFlags.TOUCHEVENTF_DOWN) ?
RawPointerEventType.TouchBegin :
RawPointerEventType.TouchUpdate,
PointToClient(new PixelPoint(touchInput.X / 100, touchInput.Y / 100)),
@@ -771,11 +772,11 @@ namespace Avalonia.Win32
{
var keys = (UnmanagedMethods.ModifierKeys)ToInt32(wParam);
var modifiers = WindowsKeyboardDevice.Instance.Modifiers;
- if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
+ if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_LBUTTON))
modifiers |= RawInputModifiers.LeftMouseButton;
- if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
+ if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_RBUTTON))
modifiers |= RawInputModifiers.RightMouseButton;
- if (keys.HasFlag(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
+ if (keys.HasFlagCustom(UnmanagedMethods.ModifierKeys.MK_MBUTTON))
modifiers |= RawInputModifiers.MiddleMouseButton;
return modifiers;
}
@@ -785,7 +786,7 @@ namespace Avalonia.Win32
// Ensure that the delegate doesn't get garbage collected by storing it as a field.
_wndProcDelegate = new UnmanagedMethods.WndProc(WndProc);
- _className = "Avalonia-" + Guid.NewGuid();
+ _className = $"Avalonia-{Guid.NewGuid().ToString()}";
UnmanagedMethods.WNDCLASSEX wndClassEx = new UnmanagedMethods.WNDCLASSEX
{
diff --git a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
index b2839360ee..227d783874 100644
--- a/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
+++ b/tests/Avalonia.Controls.UnitTests/ItemsControlTests.cs
@@ -12,6 +12,7 @@ using Xunit;
using System.Collections.ObjectModel;
using Avalonia.UnitTests;
using Avalonia.Input;
+using System.Collections.Generic;
namespace Avalonia.Controls.UnitTests
{
@@ -104,6 +105,28 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new[] { child }, target.GetLogicalChildren());
}
+ [Fact]
+ public void Added_Container_Should_Have_LogicalParent_Set_To_ItemsControl()
+ {
+ var item = new Border();
+ var items = new ObservableCollection();
+
+ var target = new ItemsControl
+ {
+ Template = GetTemplate(),
+ Items = items,
+ };
+
+ var root = new TestRoot(true, target);
+
+ root.Measure(new Size(100, 100));
+ root.Arrange(new Rect(0, 0, 100, 100));
+
+ items.Add(item);
+
+ Assert.Equal(target, item.Parent);
+ }
+
[Fact]
public void Control_Item_Should_Be_Removed_From_Logical_Children_Before_ApplyTemplate()
{
@@ -522,6 +545,36 @@ namespace Avalonia.Controls.UnitTests
}
}
+ [Fact]
+ public void Presenter_Items_Should_Be_In_Sync()
+ {
+ var target = new ItemsControl
+ {
+ Template = GetTemplate(),
+ Items = new object[]
+ {
+ new Button(),
+ new Button(),
+ },
+ };
+
+ var root = new TestRoot { Child = target };
+ var otherPanel = new StackPanel();
+
+ target.ApplyTemplate();
+ target.Presenter.ApplyTemplate();
+
+ target.ItemContainerGenerator.Materialized += (s, e) =>
+ {
+ Assert.IsType