diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 9d49025398..7fa6614d4d 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -2068,17 +2068,17 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
-(void)becomeKeyWindow
{
+ [self showWindowMenuWithAppMenu];
+
if([self activateAppropriateChild: true])
{
- [self showWindowMenuWithAppMenu];
-
if(_parent != nullptr)
{
_parent->BaseEvents->Activated();
}
-
- [super becomeKeyWindow];
}
+
+ [super becomeKeyWindow];
}
-(void) restoreParentWindow;
diff --git a/samples/ControlCatalog/Pages/AcrylicPage.xaml b/samples/ControlCatalog/Pages/AcrylicPage.xaml
index 96cfcc5288..7635e1ccc3 100644
--- a/samples/ControlCatalog/Pages/AcrylicPage.xaml
+++ b/samples/ControlCatalog/Pages/AcrylicPage.xaml
@@ -16,13 +16,13 @@
-
-
+
+
-
-
+
+
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index 6817d0698e..323eaa3463 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -1,5 +1,5 @@
@@ -26,7 +26,8 @@
-
+
+
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml.cs b/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
index 2a30f4d91b..dc5cc49a90 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
@@ -24,8 +24,10 @@ namespace ControlCatalog.Pages
dg1.LoadingRow += Dg1_LoadingRow;
dg1.Sorting += (s, a) =>
{
- var property = ((a.Column as DataGridBoundColumn)?.Binding as Binding).Path;
- if (property == dataGridSortDescription.PropertyPath
+ var binding = (a.Column as DataGridBoundColumn)?.Binding as Binding;
+
+ if (binding?.Path is string property
+ && property == dataGridSortDescription.PropertyPath
&& !collectionView1.SortDescriptions.Contains(dataGridSortDescription))
{
collectionView1.SortDescriptions.Add(dataGridSortDescription);
diff --git a/samples/ControlCatalog/Pages/ProgressBarPage.xaml b/samples/ControlCatalog/Pages/ProgressBarPage.xaml
index 2ec0b48c76..da8ef6cf07 100644
--- a/samples/ControlCatalog/Pages/ProgressBarPage.xaml
+++ b/samples/ControlCatalog/Pages/ProgressBarPage.xaml
@@ -15,6 +15,13 @@
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml
index eeb198976b..b4901ec780 100644
--- a/samples/ControlCatalog/Pages/SliderPage.xaml
+++ b/samples/ControlCatalog/Pages/SliderPage.xaml
@@ -45,6 +45,12 @@
+
+
diff --git a/src/Avalonia.Base/Data/BindingOperations.cs b/src/Avalonia.Base/Data/BindingOperations.cs
index dc8421fb35..42f941da0c 100644
--- a/src/Avalonia.Base/Data/BindingOperations.cs
+++ b/src/Avalonia.Base/Data/BindingOperations.cs
@@ -45,7 +45,7 @@ namespace Avalonia.Data
case BindingMode.OneWay:
return target.Bind(property, binding.Observable ?? binding.Subject, binding.Priority);
case BindingMode.TwoWay:
- return new CompositeDisposable(
+ return new TwoWayBindingDisposable(
target.Bind(property, binding.Subject, binding.Priority),
target.GetObservable(property).Subscribe(binding.Subject));
case BindingMode.OneTime:
@@ -88,6 +88,32 @@ namespace Avalonia.Data
throw new ArgumentException("Invalid binding mode.");
}
}
+
+ private sealed class TwoWayBindingDisposable : IDisposable
+ {
+ private readonly IDisposable _first;
+ private readonly IDisposable _second;
+ private bool _isDisposed;
+
+ public TwoWayBindingDisposable(IDisposable first, IDisposable second)
+ {
+ _first = first;
+ _second = second;
+ }
+
+ public void Dispose()
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ _first.Dispose();
+ _second.Dispose();
+
+ _isDisposed = true;
+ }
+ }
}
public sealed class DoNothingType
diff --git a/src/Avalonia.Base/EnumExtensions.cs b/src/Avalonia.Base/EnumExtensions.cs
index 1e4864283f..bc1f8d36a9 100644
--- a/src/Avalonia.Base/EnumExtensions.cs
+++ b/src/Avalonia.Base/EnumExtensions.cs
@@ -11,10 +11,32 @@ namespace Avalonia
[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;
+ if (sizeof(T) == 1)
+ {
+ var byteValue = Unsafe.As(ref value);
+ var byteFlag = Unsafe.As(ref flag);
+ return (byteValue & byteFlag) == byteFlag;
+ }
+ else if (sizeof(T) == 2)
+ {
+ var shortValue = Unsafe.As(ref value);
+ var shortFlag = Unsafe.As(ref flag);
+ return (shortValue & shortFlag) == shortFlag;
+ }
+ else if (sizeof(T) == 4)
+ {
+ var intValue = Unsafe.As(ref value);
+ var intFlag = Unsafe.As(ref flag);
+ return (intValue & intFlag) == intFlag;
+ }
+ else if (sizeof(T) == 8)
+ {
+ var longValue = Unsafe.As(ref value);
+ var longFlag = Unsafe.As(ref flag);
+ return (longValue & longFlag) == longFlag;
+ }
+ else
+ throw new NotSupportedException("Enum with size of " + Unsafe.SizeOf() + " are not supported");
}
}
}
diff --git a/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs b/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
index 238aba5c96..6a3f9b0b30 100644
--- a/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
+++ b/src/Avalonia.Base/Reactive/AvaloniaPropertyObservable.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
namespace Avalonia.Reactive
{
@@ -55,9 +56,9 @@ namespace Avalonia.Reactive
newValue = (T)e.Sender.GetValue(e.Property);
}
- if (!Equals(newValue, _value))
+ if (!EqualityComparer.Default.Equals(newValue, _value))
{
- _value = (T)newValue;
+ _value = newValue;
PublishNext(_value);
}
}
diff --git a/src/Avalonia.Base/Utilities/TypeUtilities.cs b/src/Avalonia.Base/Utilities/TypeUtilities.cs
index d0d88166a7..097731bc60 100644
--- a/src/Avalonia.Base/Utilities/TypeUtilities.cs
+++ b/src/Avalonia.Base/Utilities/TypeUtilities.cs
@@ -372,8 +372,8 @@ namespace Avalonia.Utilities
const string implicitName = "op_Implicit";
const string explicitName = "op_Explicit";
- bool allowImplicit = (operatorType & OperatorType.Implicit) != 0;
- bool allowExplicit = (operatorType & OperatorType.Explicit) != 0;
+ bool allowImplicit = operatorType.HasFlagCustom(OperatorType.Implicit);
+ bool allowExplicit = operatorType.HasFlagCustom(OperatorType.Explicit);
foreach (MethodInfo method in fromType.GetMethods())
{
diff --git a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs
index 92734b128d..b97f2a2bcb 100644
--- a/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs
+++ b/src/Avalonia.Controls.DataGrid/Collections/DataGridCollectionView.cs
@@ -2595,7 +2595,7 @@ namespace Avalonia.Collections
/// Whether the specified flag is set
private bool CheckFlag(CollectionViewFlags flags)
{
- return (_flags & flags) != 0;
+ return _flags.HasFlagCustom(flags);
}
///
diff --git a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
index 1e72a07760..90401a00a2 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
@@ -10,7 +10,8 @@ using System.Reactive.Disposables;
using System.Reactive.Subjects;
using Avalonia.Reactive;
using System.Diagnostics;
-using Avalonia.Controls.Utils;
+using Avalonia.Controls.Utils;
+using Avalonia.Markup.Xaml.MarkupExtensions;
namespace Avalonia.Controls
{
@@ -47,14 +48,15 @@ namespace Avalonia.Controls
if (_binding != null)
{
- if(_binding is Avalonia.Data.Binding binding)
+ if(_binding is BindingBase binding)
{
if (binding.Mode == BindingMode.OneWayToSource)
{
throw new InvalidOperationException("DataGridColumn doesn't support BindingMode.OneWayToSource. Use BindingMode.TwoWay instead.");
}
- if (!String.IsNullOrEmpty(binding.Path) && binding.Mode == BindingMode.Default)
+ var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
+ if (!string.IsNullOrEmpty(path) && binding.Mode == BindingMode.Default)
{
binding.Mode = BindingMode.TwoWay;
}
@@ -136,13 +138,16 @@ namespace Avalonia.Controls
internal void SetHeaderFromBinding()
{
if (OwningGrid != null && OwningGrid.DataConnection.DataType != null
- && Header == null && Binding != null && Binding is Binding binding
- && !String.IsNullOrWhiteSpace(binding.Path))
+ && Header == null && Binding != null && Binding is BindingBase binding)
{
- string header = OwningGrid.DataConnection.DataType.GetDisplayName(binding.Path);
- if (header != null)
+ var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
+ if (!string.IsNullOrWhiteSpace(path))
{
- Header = header;
+ var header = OwningGrid.DataConnection.DataType.GetDisplayName(path);
+ if (header != null)
+ {
+ Header = header;
+ }
}
}
}
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
index 92ddd4e736..407d6ff058 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs
@@ -12,6 +12,7 @@ using System;
using System.Linq;
using System.Diagnostics;
using Avalonia.Controls.Utils;
+using Avalonia.Markup.Xaml.MarkupExtensions;
namespace Avalonia.Controls
{
@@ -1033,13 +1034,16 @@ namespace Avalonia.Controls
if (String.IsNullOrEmpty(result))
{
-
- if(this is DataGridBoundColumn boundColumn &&
- boundColumn.Binding != null &&
- boundColumn.Binding is Binding binding &&
- binding.Path != null)
+ if (this is DataGridBoundColumn boundColumn)
{
- result = binding.Path;
+ if (boundColumn.Binding is Binding binding)
+ {
+ result = binding.Path;
+ }
+ else if (boundColumn.Binding is CompiledBindingExtension compiledBinding)
+ {
+ result = compiledBinding.Path.ToString();
+ }
}
}
diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
index 46bcd0d347..a4577ee952 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridColumns.cs
@@ -5,6 +5,7 @@
using Avalonia.Controls.Utils;
using Avalonia.Data;
+using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Utilities;
using System;
using System.Collections.Generic;
@@ -141,9 +142,9 @@ namespace Avalonia.Controls
Debug.Assert(dataGridColumn != null);
if (dataGridColumn is DataGridBoundColumn dataGridBoundColumn &&
- dataGridBoundColumn.Binding is Binding binding)
+ dataGridBoundColumn.Binding is BindingBase binding)
{
- string path = binding.Path;
+ var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (string.IsNullOrWhiteSpace(path))
{
diff --git a/src/Avalonia.Controls/ComboBox.cs b/src/Avalonia.Controls/ComboBox.cs
index 7f2acb58fe..20ca41bc57 100644
--- a/src/Avalonia.Controls/ComboBox.cs
+++ b/src/Avalonia.Controls/ComboBox.cs
@@ -188,7 +188,7 @@ namespace Avalonia.Controls
return;
if (e.Key == Key.F4 ||
- ((e.Key == Key.Down || e.Key == Key.Up) && ((e.KeyModifiers & KeyModifiers.Alt) != 0)))
+ ((e.Key == Key.Down || e.Key == Key.Up) && e.KeyModifiers.HasFlagCustom(KeyModifiers.Alt)))
{
IsDropDownOpen = !IsDropDownOpen;
e.Handled = true;
diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs
index fb8080f0d4..57e4909e39 100644
--- a/src/Avalonia.Controls/ContextMenu.cs
+++ b/src/Avalonia.Controls/ContextMenu.cs
@@ -269,7 +269,43 @@ namespace Avalonia.Controls
}
control ??= _attachedControls![0];
+ Open(control, PlacementTarget ?? control);
+ }
+
+ ///
+ /// Closes the menu.
+ ///
+ public override void Close()
+ {
+ if (!IsOpen)
+ {
+ return;
+ }
+ if (_popup != null && _popup.IsVisible)
+ {
+ _popup.IsOpen = false;
+ }
+ }
+
+ void ISetterValue.Initialize(ISetter setter)
+ {
+ // ContextMenu can be assigned to the ContextMenu property in a setter. This overrides
+ // the behavior defined in Control which requires controls to be wrapped in a .
+ if (!(setter is Setter s && s.Property == ContextMenuProperty))
+ {
+ throw new InvalidOperationException(
+ "Cannot use a control as a Setter value. Wrap the control in a .");
+ }
+ }
+
+ protected override IItemContainerGenerator CreateItemContainerGenerator()
+ {
+ return new MenuItemContainerGenerator(this);
+ }
+
+ private void Open(Control control, Control placementTarget)
+ {
if (IsOpen)
{
return;
@@ -286,7 +322,6 @@ namespace Avalonia.Controls
PlacementGravity = PlacementGravity,
PlacementMode = PlacementMode,
PlacementRect = PlacementRect,
- PlacementTarget = PlacementTarget ?? control,
IsLightDismissEnabled = true,
OverlayDismissEventPassThrough = true,
WindowManagerAddShadowHint = WindowManagerAddShadowHint,
@@ -302,11 +337,7 @@ namespace Avalonia.Controls
((ISetLogicalParent)_popup).SetParent(control);
}
- if (PlacementTarget is null && _popup.PlacementTarget != control)
- {
- _popup.PlacementTarget = control;
- }
-
+ _popup.PlacementTarget = placementTarget;
_popup.Child = this;
IsOpen = true;
_popup.IsOpen = true;
@@ -318,38 +349,6 @@ namespace Avalonia.Controls
});
}
- ///
- /// Closes the menu.
- ///
- public override void Close()
- {
- if (!IsOpen)
- {
- return;
- }
-
- if (_popup != null && _popup.IsVisible)
- {
- _popup.IsOpen = false;
- }
- }
-
- void ISetterValue.Initialize(ISetter setter)
- {
- // ContextMenu can be assigned to the ContextMenu property in a setter. This overrides
- // the behavior defined in Control which requires controls to be wrapped in a .
- if (!(setter is Setter s && s.Property == ContextMenuProperty))
- {
- throw new InvalidOperationException(
- "Cannot use a control as a Setter value. Wrap the control in a .");
- }
- }
-
- protected override IItemContainerGenerator CreateItemContainerGenerator()
- {
- return new MenuItemContainerGenerator(this);
- }
-
private void PopupOpened(object sender, EventArgs e)
{
_previousFocus = FocusManager.Instance?.Current;
@@ -403,7 +402,7 @@ namespace Avalonia.Controls
if (contextMenu.CancelOpening())
return;
- contextMenu.Open(control);
+ contextMenu.Open(control, e.Source as Control ?? control);
e.Handled = true;
}
}
diff --git a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
index d2e05ee136..840a1f66f1 100644
--- a/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
+++ b/src/Avalonia.Controls/Generators/TabItemContainerGenerator.cs
@@ -1,4 +1,10 @@
+using System;
+using System.Collections.Generic;
using Avalonia.Controls.Primitives;
+using Avalonia.Controls.Templates;
+using Avalonia.LogicalTree;
+using Avalonia.Reactive;
+using Avalonia.VisualTree;
namespace Avalonia.Controls.Generators
{
@@ -16,11 +22,15 @@ namespace Avalonia.Controls.Generators
{
var tabItem = (TabItem)base.CreateContainer(item);
- tabItem[~TabControl.TabStripPlacementProperty] = Owner[~TabControl.TabStripPlacementProperty];
+ tabItem.Bind(TabItem.TabStripPlacementProperty, new OwnerBinding(
+ tabItem,
+ TabControl.TabStripPlacementProperty));
if (tabItem.HeaderTemplate == null)
{
- tabItem[~HeaderedContentControl.HeaderTemplateProperty] = Owner[~ItemsControl.ItemTemplateProperty];
+ tabItem.Bind(TabItem.HeaderTemplateProperty, new OwnerBinding(
+ tabItem,
+ TabControl.ItemTemplateProperty));
}
if (tabItem.Header == null)
@@ -40,10 +50,49 @@ namespace Avalonia.Controls.Generators
if (!(tabItem.Content is IControl))
{
- tabItem[~ContentControl.ContentTemplateProperty] = Owner[~TabControl.ContentTemplateProperty];
+ tabItem.Bind(TabItem.ContentTemplateProperty, new OwnerBinding(
+ tabItem,
+ TabControl.ContentTemplateProperty));
}
return tabItem;
}
+
+ private class OwnerBinding : SingleSubscriberObservableBase
+ {
+ private readonly TabItem _item;
+ private readonly StyledProperty _ownerProperty;
+ private IDisposable _ownerSubscription;
+ private IDisposable _propertySubscription;
+
+ public OwnerBinding(TabItem item, StyledProperty ownerProperty)
+ {
+ _item = item;
+ _ownerProperty = ownerProperty;
+ }
+
+ protected override void Subscribed()
+ {
+ _ownerSubscription = ControlLocator.Track(_item, 0, typeof(TabControl)).Subscribe(OwnerChanged);
+ }
+
+ protected override void Unsubscribed()
+ {
+ _ownerSubscription?.Dispose();
+ _ownerSubscription = null;
+ }
+
+ private void OwnerChanged(ILogical c)
+ {
+ _propertySubscription?.Dispose();
+ _propertySubscription = null;
+
+ if (c is TabControl tabControl)
+ {
+ _propertySubscription = tabControl.GetObservable(_ownerProperty)
+ .Subscribe(x => PublishNext(x));
+ }
+ }
+ }
}
}
diff --git a/src/Avalonia.Controls/Grid.cs b/src/Avalonia.Controls/Grid.cs
index 6357ec98a8..66266c3b61 100644
--- a/src/Avalonia.Controls/Grid.cs
+++ b/src/Avalonia.Controls/Grid.cs
@@ -637,7 +637,7 @@ namespace Avalonia.Controls
///
internal bool MeasureOverrideInProgress
{
- get { return (CheckFlagsAnd(Flags.MeasureOverrideInProgress)); }
+ get { return CheckFlags(Flags.MeasureOverrideInProgress); }
set { SetFlags(value, Flags.MeasureOverrideInProgress); }
}
@@ -646,7 +646,7 @@ namespace Avalonia.Controls
///
internal bool ArrangeOverrideInProgress
{
- get { return (CheckFlagsAnd(Flags.ArrangeOverrideInProgress)); }
+ get { return CheckFlags(Flags.ArrangeOverrideInProgress); }
set { SetFlags(value, Flags.ArrangeOverrideInProgress); }
}
@@ -2350,25 +2350,12 @@ namespace Avalonia.Controls
}
///
- /// CheckFlagsAnd returns true if all the flags in the
+ /// CheckFlags returns true if all the flags in the
/// given bitmask are set on the object.
///
- private bool CheckFlagsAnd(Flags flags)
+ private bool CheckFlags(Flags flags)
{
- return ((_flags & flags) == flags);
- }
-
- ///
- /// CheckFlagsOr returns true if at least one flag in the
- /// given bitmask is set.
- ///
- ///
- /// If no bits are set in the given bitmask, the method returns
- /// true.
- ///
- private bool CheckFlagsOr(Flags flags)
- {
- return (flags == 0 || (_flags & flags) != 0);
+ return _flags.HasFlagCustom(flags);
}
private static void OnShowGridLinesPropertyChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
@@ -2535,7 +2522,7 @@ namespace Avalonia.Controls
///
private bool CellsStructureDirty
{
- get { return (!CheckFlagsAnd(Flags.ValidCellsStructure)); }
+ get { return !CheckFlags(Flags.ValidCellsStructure); }
set { SetFlags(!value, Flags.ValidCellsStructure); }
}
@@ -2544,7 +2531,7 @@ namespace Avalonia.Controls
///
private bool ListenToNotifications
{
- get { return (CheckFlagsAnd(Flags.ListenToNotifications)); }
+ get { return CheckFlags(Flags.ListenToNotifications); }
set { SetFlags(value, Flags.ListenToNotifications); }
}
@@ -2553,7 +2540,7 @@ namespace Avalonia.Controls
///
private bool SizeToContentU
{
- get { return (CheckFlagsAnd(Flags.SizeToContentU)); }
+ get { return CheckFlags(Flags.SizeToContentU); }
set { SetFlags(value, Flags.SizeToContentU); }
}
@@ -2562,7 +2549,7 @@ namespace Avalonia.Controls
///
private bool SizeToContentV
{
- get { return (CheckFlagsAnd(Flags.SizeToContentV)); }
+ get { return CheckFlags(Flags.SizeToContentV); }
set { SetFlags(value, Flags.SizeToContentV); }
}
@@ -2571,7 +2558,7 @@ namespace Avalonia.Controls
///
private bool HasStarCellsU
{
- get { return (CheckFlagsAnd(Flags.HasStarCellsU)); }
+ get { return CheckFlags(Flags.HasStarCellsU); }
set { SetFlags(value, Flags.HasStarCellsU); }
}
@@ -2580,7 +2567,7 @@ namespace Avalonia.Controls
///
private bool HasStarCellsV
{
- get { return (CheckFlagsAnd(Flags.HasStarCellsV)); }
+ get { return CheckFlags(Flags.HasStarCellsV); }
set { SetFlags(value, Flags.HasStarCellsV); }
}
@@ -2589,7 +2576,7 @@ namespace Avalonia.Controls
///
private bool HasGroup3CellsInAutoRows
{
- get { return (CheckFlagsAnd(Flags.HasGroup3CellsInAutoRows)); }
+ get { return CheckFlags(Flags.HasGroup3CellsInAutoRows); }
set { SetFlags(value, Flags.HasGroup3CellsInAutoRows); }
}
@@ -2803,10 +2790,10 @@ namespace Avalonia.Controls
internal LayoutTimeSizeType SizeTypeU;
internal LayoutTimeSizeType SizeTypeV;
internal int Next;
- internal bool IsStarU { get { return ((SizeTypeU & LayoutTimeSizeType.Star) != 0); } }
- internal bool IsAutoU { get { return ((SizeTypeU & LayoutTimeSizeType.Auto) != 0); } }
- internal bool IsStarV { get { return ((SizeTypeV & LayoutTimeSizeType.Star) != 0); } }
- internal bool IsAutoV { get { return ((SizeTypeV & LayoutTimeSizeType.Auto) != 0); } }
+ internal bool IsStarU => SizeTypeU.HasFlagCustom(LayoutTimeSizeType.Star);
+ internal bool IsAutoU => SizeTypeU.HasFlagCustom(LayoutTimeSizeType.Auto);
+ internal bool IsStarV => SizeTypeV.HasFlagCustom(LayoutTimeSizeType.Star);
+ internal bool IsAutoV => SizeTypeV.HasFlagCustom(LayoutTimeSizeType.Auto);
}
///
diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs
index d1b8038581..b6b3cc786c 100644
--- a/src/Avalonia.Controls/ListBox.cs
+++ b/src/Avalonia.Controls/ListBox.cs
@@ -135,8 +135,8 @@ namespace Avalonia.Controls
e.Handled = UpdateSelectionFromEventSource(
e.Source,
true,
- (e.KeyModifiers & KeyModifiers.Shift) != 0,
- (e.KeyModifiers & KeyModifiers.Control) != 0);
+ e.KeyModifiers.HasFlagCustom(KeyModifiers.Shift),
+ e.KeyModifiers.HasFlagCustom(KeyModifiers.Control));
}
}
@@ -154,8 +154,8 @@ namespace Avalonia.Controls
e.Handled = UpdateSelectionFromEventSource(
e.Source,
true,
- (e.KeyModifiers & KeyModifiers.Shift) != 0,
- (e.KeyModifiers & KeyModifiers.Control) != 0,
+ e.KeyModifiers.HasFlagCustom(KeyModifiers.Shift),
+ e.KeyModifiers.HasFlagCustom(KeyModifiers.Control),
point.Properties.IsRightButtonPressed);
}
}
diff --git a/src/Avalonia.Controls/NativeControlHost.cs b/src/Avalonia.Controls/NativeControlHost.cs
index 20eac11c2c..64414b1f47 100644
--- a/src/Avalonia.Controls/NativeControlHost.cs
+++ b/src/Avalonia.Controls/NativeControlHost.cs
@@ -157,10 +157,14 @@ namespace Avalonia.Controls
var needsShow = IsEffectivelyVisible && bounds.HasValue;
if (needsShow)
+ {
+ if (bounds.Value.IsEmpty)
+ return false;
_attachment?.ShowInBounds(bounds.Value);
+ }
else
_attachment?.HideWithSize(Bounds.Size);
- return false;
+ return true;
}
private void CheckDestruction()
diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
index 9d644aaa00..7e1a7378c7 100644
--- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs
+++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs
@@ -73,20 +73,20 @@ namespace Avalonia.Platform
{
if (effect == DragDropEffects.Copy || effect == DragDropEffects.Move || effect == DragDropEffects.Link || effect == DragDropEffects.None)
return effect; // No need to check for the modifiers.
- if (effect.HasFlag(DragDropEffects.Link) && modifiers.HasFlag(RawInputModifiers.Alt))
+ if (effect.HasFlagCustom(DragDropEffects.Link) && modifiers.HasFlagCustom(RawInputModifiers.Alt))
return DragDropEffects.Link;
- if (effect.HasFlag(DragDropEffects.Copy) && modifiers.HasFlag(RawInputModifiers.Control))
+ if (effect.HasFlagCustom(DragDropEffects.Copy) && modifiers.HasFlagCustom(RawInputModifiers.Control))
return DragDropEffects.Copy;
return DragDropEffects.Move;
}
private StandardCursorType GetCursorForDropEffect(DragDropEffects effects)
{
- if (effects.HasFlag(DragDropEffects.Copy))
+ if (effects.HasFlagCustom(DragDropEffects.Copy))
return StandardCursorType.DragCopy;
- if (effects.HasFlag(DragDropEffects.Move))
+ if (effects.HasFlagCustom(DragDropEffects.Move))
return StandardCursorType.DragMove;
- if (effects.HasFlag(DragDropEffects.Link))
+ if (effects.HasFlagCustom(DragDropEffects.Link))
return StandardCursorType.DragLink;
return StandardCursorType.No;
}
@@ -161,7 +161,7 @@ namespace Avalonia.Platform
void CheckDraggingAccepted(RawInputModifiers changedMouseButton)
{
- if (_initialInputModifiers.Value.HasFlag(changedMouseButton))
+ if (_initialInputModifiers.Value.HasFlagCustom(changedMouseButton))
{
var result = RaiseEventAndUpdateCursor(RawDragEventType.Drop, e.Root, e.Position, e.InputModifiers);
UpdateCursor(null, DragDropEffects.None);
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index 6bbb1c13bf..3bec46a9ac 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -80,7 +80,9 @@ namespace Avalonia.Controls.Presenters
static TextPresenter()
{
AffectsRender(SelectionBrushProperty, TextBlock.ForegroundProperty,
- SelectionForegroundBrushProperty, CaretBrushProperty);
+ SelectionForegroundBrushProperty, CaretBrushProperty,
+ SelectionStartProperty, SelectionEndProperty);
+
AffectsMeasure(TextProperty, PasswordCharProperty, RevealPasswordProperty,
TextAlignmentProperty, TextWrappingProperty, TextBlock.FontSizeProperty,
TextBlock.FontStyleProperty, TextBlock.FontWeightProperty, TextBlock.FontFamilyProperty);
diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
index aed7dff0fe..545034239f 100644
--- a/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
+++ b/src/Avalonia.Controls/Primitives/PopupPositioning/IPopupPositioner.cs
@@ -253,9 +253,8 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
{
public static void ValidateEdge(this PopupAnchor edge)
{
- if (((edge & PopupAnchor.Left) != 0 && (edge & PopupAnchor.Right) != 0)
- ||
- ((edge & PopupAnchor.Top) != 0 && (edge & PopupAnchor.Bottom) != 0))
+ if (edge.HasFlagCustom(PopupAnchor.Left) && edge.HasFlagCustom(PopupAnchor.Right) ||
+ edge.HasFlagCustom(PopupAnchor.Top) && edge.HasFlagCustom(PopupAnchor.Bottom))
throw new ArgumentException("Opposite edges specified");
}
@@ -266,25 +265,25 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
public static PopupAnchor Flip(this PopupAnchor edge)
{
- var hmask = PopupAnchor.Left | PopupAnchor.Right;
- var vmask = PopupAnchor.Top | PopupAnchor.Bottom;
- if ((edge & hmask) != 0)
- edge ^= hmask;
- if ((edge & vmask) != 0)
- edge ^= vmask;
+ if (edge.HasFlagCustom(PopupAnchor.HorizontalMask))
+ edge ^= PopupAnchor.HorizontalMask;
+
+ if (edge.HasFlagCustom(PopupAnchor.VerticalMask))
+ edge ^= PopupAnchor.VerticalMask;
+
return edge;
}
public static PopupAnchor FlipX(this PopupAnchor edge)
{
- if ((edge & PopupAnchor.HorizontalMask) != 0)
+ if (edge.HasFlagCustom(PopupAnchor.HorizontalMask))
edge ^= PopupAnchor.HorizontalMask;
return edge;
}
public static PopupAnchor FlipY(this PopupAnchor edge)
{
- if ((edge & PopupAnchor.VerticalMask) != 0)
+ if (edge.HasFlagCustom(PopupAnchor.VerticalMask))
edge ^= PopupAnchor.VerticalMask;
return edge;
}
diff --git a/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs b/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
index 7f1dbdf592..80b32b5ef8 100644
--- a/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
+++ b/src/Avalonia.Controls/Primitives/PopupPositioning/ManagedPopupPositioner.cs
@@ -42,16 +42,16 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
private static Point GetAnchorPoint(Rect anchorRect, PopupAnchor edge)
{
double x, y;
- if ((edge & PopupAnchor.Left) != 0)
+ if (edge.HasFlagCustom(PopupAnchor.Left))
x = anchorRect.X;
- else if ((edge & PopupAnchor.Right) != 0)
+ else if (edge.HasFlagCustom(PopupAnchor.Right))
x = anchorRect.Right;
else
x = anchorRect.X + anchorRect.Width / 2;
- if ((edge & PopupAnchor.Top) != 0)
+ if (edge.HasFlagCustom(PopupAnchor.Top))
y = anchorRect.Y;
- else if ((edge & PopupAnchor.Bottom) != 0)
+ else if (edge.HasFlagCustom(PopupAnchor.Bottom))
y = anchorRect.Bottom;
else
y = anchorRect.Y + anchorRect.Height / 2;
@@ -61,16 +61,16 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
private static Point Gravitate(Point anchorPoint, Size size, PopupGravity gravity)
{
double x, y;
- if ((gravity & PopupGravity.Left) != 0)
+ if (gravity.HasFlagCustom(PopupGravity.Left))
x = -size.Width;
- else if ((gravity & PopupGravity.Right) != 0)
+ else if (gravity.HasFlagCustom(PopupGravity.Right))
x = 0;
else
x = -size.Width / 2;
- if ((gravity & PopupGravity.Top) != 0)
+ if (gravity.HasFlagCustom(PopupGravity.Top))
y = -size.Height;
- else if ((gravity & PopupGravity.Bottom) != 0)
+ else if (gravity.HasFlagCustom(PopupGravity.Bottom))
y = 0;
else
y = -size.Height / 2;
@@ -125,21 +125,13 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
bool FitsInBounds(Rect rc, PopupAnchor edge = PopupAnchor.AllMask)
{
- if ((edge & PopupAnchor.Left) != 0
- && rc.X < bounds.X)
- return false;
-
- if ((edge & PopupAnchor.Top) != 0
- && rc.Y < bounds.Y)
- return false;
-
- if ((edge & PopupAnchor.Right) != 0
- && rc.Right > bounds.Right)
- return false;
-
- if ((edge & PopupAnchor.Bottom) != 0
- && rc.Bottom > bounds.Bottom)
+ if (edge.HasFlagCustom(PopupAnchor.Left) && rc.X < bounds.X ||
+ edge.HasFlagCustom(PopupAnchor.Top) && rc.Y < bounds.Y ||
+ edge.HasFlagCustom(PopupAnchor.Right) && rc.Right > bounds.Right ||
+ edge.HasFlagCustom(PopupAnchor.Bottom) && rc.Bottom > bounds.Bottom)
+ {
return false;
+ }
return true;
}
@@ -155,7 +147,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
// If flipping geometry and anchor is allowed and helps, use the flipped one,
// otherwise leave it as is
if (!FitsInBounds(geo, PopupAnchor.HorizontalMask)
- && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipX) != 0)
+ && constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.FlipX))
{
var flipped = GetUnconstrained(anchor.FlipX(), gravity.FlipX());
if (FitsInBounds(flipped, PopupAnchor.HorizontalMask))
@@ -163,7 +155,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
// If sliding is allowed, try moving the rect into the bounds
- if ((constraintAdjustment & PopupPositionerConstraintAdjustment.SlideX) != 0)
+ if (constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.SlideX))
{
geo = geo.WithX(Math.Max(geo.X, bounds.X));
if (geo.Right > bounds.Right)
@@ -171,7 +163,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
// Resize the rect horizontally if allowed.
- if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeX) != 0)
+ if (constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.ResizeX))
{
var unconstrainedRect = geo;
@@ -194,7 +186,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
// If flipping geometry and anchor is allowed and helps, use the flipped one,
// otherwise leave it as is
if (!FitsInBounds(geo, PopupAnchor.VerticalMask)
- && (constraintAdjustment & PopupPositionerConstraintAdjustment.FlipY) != 0)
+ && constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.FlipY))
{
var flipped = GetUnconstrained(anchor.FlipY(), gravity.FlipY());
if (FitsInBounds(flipped, PopupAnchor.VerticalMask))
@@ -202,7 +194,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
// If sliding is allowed, try moving the rect into the bounds
- if ((constraintAdjustment & PopupPositionerConstraintAdjustment.SlideY) != 0)
+ if (constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.SlideY))
{
geo = geo.WithY(Math.Max(geo.Y, bounds.Y));
if (geo.Bottom > bounds.Bottom)
@@ -210,7 +202,7 @@ namespace Avalonia.Controls.Primitives.PopupPositioning
}
// Resize the rect vertically if allowed.
- if ((constraintAdjustment & PopupPositionerConstraintAdjustment.ResizeY) != 0)
+ if (constraintAdjustment.HasFlagCustom(PopupPositionerConstraintAdjustment.ResizeY))
{
var unconstrainedRect = geo;
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 280f46be9f..2cd69793dc 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -321,7 +321,7 @@ namespace Avalonia.Controls.Primitives
///
/// Gets a value indicating whether is set.
///
- protected bool AlwaysSelected => (SelectionMode & SelectionMode.AlwaysSelected) != 0;
+ protected bool AlwaysSelected => SelectionMode.HasFlagCustom(SelectionMode.AlwaysSelected);
///
public override void BeginInit()
@@ -487,7 +487,7 @@ namespace Avalonia.Controls.Primitives
if (ItemCount > 0 &&
Match(keymap.SelectAll) &&
- SelectionMode.HasFlag(SelectionMode.Multiple))
+ SelectionMode.HasFlagCustom(SelectionMode.Multiple))
{
Selection.SelectAll();
e.Handled = true;
@@ -577,8 +577,8 @@ namespace Avalonia.Controls.Primitives
}
var mode = SelectionMode;
- var multi = (mode & SelectionMode.Multiple) != 0;
- var toggle = (toggleModifier || (mode & SelectionMode.Toggle) != 0);
+ var multi = mode.HasFlagCustom(SelectionMode.Multiple);
+ var toggle = toggleModifier || mode.HasFlagCustom(SelectionMode.Toggle);
var range = multi && rangeModifier;
if (!select)
diff --git a/src/Avalonia.Controls/Repeater/RepeaterLayoutContext.cs b/src/Avalonia.Controls/Repeater/RepeaterLayoutContext.cs
index fd33eeaf39..4eadced423 100644
--- a/src/Avalonia.Controls/Repeater/RepeaterLayoutContext.cs
+++ b/src/Avalonia.Controls/Repeater/RepeaterLayoutContext.cs
@@ -53,8 +53,8 @@ namespace Avalonia.Controls
{
return _owner.GetElementImpl(
index,
- (options & ElementRealizationOptions.ForceCreate) != 0,
- (options & ElementRealizationOptions.SuppressAutoRecycle) != 0);
+ options.HasFlagCustom(ElementRealizationOptions.ForceCreate),
+ options.HasFlagCustom(ElementRealizationOptions.SuppressAutoRecycle));
}
protected override object GetItemAtCore(int index) => _owner.ItemsSourceView.GetAt(index);
diff --git a/src/Avalonia.Controls/Slider.cs b/src/Avalonia.Controls/Slider.cs
index 74de33529a..e02efc2bd2 100644
--- a/src/Avalonia.Controls/Slider.cs
+++ b/src/Avalonia.Controls/Slider.cs
@@ -49,6 +49,12 @@ namespace Avalonia.Controls
public static readonly StyledProperty OrientationProperty =
ScrollBar.OrientationProperty.AddOwner();
+ ///
+ /// Defines the property.
+ ///
+ public static readonly StyledProperty IsDirectionReversedProperty =
+ Track.IsDirectionReversedProperty.AddOwner();
+
///
/// Defines the property.
///
@@ -83,7 +89,6 @@ namespace Avalonia.Controls
private IDisposable _increaseButtonSubscription;
private IDisposable _increaseButtonReleaseDispose;
private IDisposable _pointerMovedDispose;
- private IDisposable _trackOnKeyDownDispose;
private const double Tolerance = 0.0001;
@@ -93,6 +98,7 @@ namespace Avalonia.Controls
static Slider()
{
PressedMixin.Attach();
+ FocusableProperty.OverrideDefaultValue(true);
OrientationProperty.OverrideDefaultValue(typeof(Slider), Orientation.Horizontal);
Thumb.DragStartedEvent.AddClassHandler((x, e) => x.OnThumbDragStarted(e), RoutingStrategies.Bubble);
Thumb.DragCompletedEvent.AddClassHandler((x, e) => x.OnThumbDragCompleted(e),
@@ -127,6 +133,19 @@ namespace Avalonia.Controls
set { SetValue(OrientationProperty, value); }
}
+ ///
+ /// Gets or sets the direction of increasing value.
+ ///
+ ///
+ /// true if the direction of increasing value is to the left for a horizontal slider or
+ /// down for a vertical slider; otherwise, false. The default is false.
+ ///
+ public bool IsDirectionReversed
+ {
+ get { return GetValue(IsDirectionReversedProperty); }
+ set { SetValue(IsDirectionReversedProperty, value); }
+ }
+
///
/// Gets or sets a value that indicates whether the automatically moves the to the closest tick mark.
///
@@ -165,7 +184,6 @@ namespace Avalonia.Controls
_increaseButtonSubscription?.Dispose();
_increaseButtonReleaseDispose?.Dispose();
_pointerMovedDispose?.Dispose();
- _trackOnKeyDownDispose?.Dispose();
_decreaseButton = e.NameScope.Find