diff --git a/packages.cake b/packages.cake index bcb135f6ad..7e7e722c82 100644 --- a/packages.cake +++ b/packages.cake @@ -120,6 +120,7 @@ public class Packages var SharpDXDirect3D11Version = packageVersions["SharpDX.Direct3D11"].FirstOrDefault().Item1; var SharpDXDirect3D9Version = packageVersions["SharpDX.Direct3D9"].FirstOrDefault().Item1; var SharpDXDXGIVersion = packageVersions["SharpDX.DXGI"].FirstOrDefault().Item1; + var SystemComponentModelAnnotationsVersion = packageVersions["System.ComponentModel.Annotations"].FirstOrDefault().Item1; context.Information("Package: Serilog, version: {0}", SerilogVersion); context.Information("Package: Sprache, version: {0}", SpracheVersion); @@ -238,6 +239,7 @@ public class Packages new NuSpecDependency() { Id = "Sprache", Version = SpracheVersion }, new NuSpecDependency() { Id = "System.Reactive", Version = SystemReactiveVersion }, new NuSpecDependency() { Id = "Avalonia.Remote.Protocol", Version = parameters.Version }, + new NuSpecDependency() { Id = "System.ComponentModel.Annotations", Version = SystemComponentModelAnnotationsVersion }, //.NET Core new NuSpecDependency() { Id = "System.Threading.ThreadPool", TargetFramework = "netcoreapp2.0", Version = "4.3.0" }, new NuSpecDependency() { Id = "Microsoft.Extensions.DependencyModel", TargetFramework = "netcoreapp2.0", Version = "1.1.0" }, diff --git a/readme.md b/readme.md index 2b26cbdd1a..4fe76a2faf 100644 --- a/readme.md +++ b/readme.md @@ -18,7 +18,7 @@ Avalonia is a WPF-inspired cross-platform XAML-based UI framework providing a fl ## Getting Started -Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (screenshot). Now you can write code and markup that will work on multiple platforms! +Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started. After installing it, open "New Project" dialog in Visual Studio, choose "Avalonia" in "Visual C#" section, select "Avalonia .NET Core Application" and press OK (screenshot). Now you can write code and markup that will work on multiple platforms! Avalonia is delivered via NuGet package manager. You can find the packages here: ([stable(ish)](https://www.nuget.org/packages/Avalonia/), [nightly](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed)) @@ -52,7 +52,7 @@ Please read the [contribution guidelines](http://avaloniaui.net/contributing/con ### Contributors This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing/contributing)]. - + ### Backers diff --git a/samples/ControlCatalog/DecoratedWindow.xaml.cs b/samples/ControlCatalog/DecoratedWindow.xaml.cs index d28281e476..749f83c1ab 100644 --- a/samples/ControlCatalog/DecoratedWindow.xaml.cs +++ b/samples/ControlCatalog/DecoratedWindow.xaml.cs @@ -20,7 +20,7 @@ namespace ControlCatalog ctl.Cursor = new Cursor(cursor); ctl.PointerPressed += delegate { - PlatformImpl.BeginResizeDrag(edge); + PlatformImpl?.BeginResizeDrag(edge); }; } @@ -29,7 +29,7 @@ namespace ControlCatalog AvaloniaXamlLoader.Load(this); this.FindControl("TitleBar").PointerPressed += delegate { - PlatformImpl.BeginMoveDrag(); + PlatformImpl?.BeginMoveDrag(); }; SetupSide("Left", StandardCursorType.LeftSide, WindowEdge.West); SetupSide("Right", StandardCursorType.RightSide, WindowEdge.East); diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs index 78f744cea0..041d91043a 100644 --- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs +++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/PopupImpl.cs @@ -110,7 +110,10 @@ namespace Avalonia.Android.Platform.SkiaPlatform { //Not supported } - + public void SetTopmost(bool value) + { + //Not supported + } } } \ No newline at end of file diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index 351cbf5520..96fb9be8ac 100644 --- a/src/Avalonia.Controls/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox.cs @@ -2150,7 +2150,7 @@ namespace Avalonia.Controls } // Update the view - if (e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) + if ((e.Action == NotifyCollectionChangedAction.Remove || e.Action == NotifyCollectionChangedAction.Replace) && e.OldItems != null) { for (int index = 0; index < e.OldItems.Count; index++) { diff --git a/src/Avalonia.Controls/Calendar/Calendar.cs b/src/Avalonia.Controls/Calendar/Calendar.cs index 59281c5ad0..029e4dadc8 100644 --- a/src/Avalonia.Controls/Calendar/Calendar.cs +++ b/src/Avalonia.Controls/Calendar/Calendar.cs @@ -769,7 +769,7 @@ namespace Avalonia.Controls } private static void UpdateDisplayDate(Calendar c, DateTime addedDate, DateTime removedDate) { - Debug.Assert(c != null, "c should not be null!"); + Contract.Requires(c != null); // If DisplayDate < DisplayDateStart, DisplayDate = DisplayDateStart if (DateTime.Compare(addedDate, c.DisplayDateRangeStart) < 0) @@ -1016,8 +1016,6 @@ namespace Avalonia.Controls internal CalendarDayButton FindDayButtonFromDay(DateTime day) { - CalendarDayButton b; - DateTime? d; CalendarItem monthControl = MonthControl; // REMOVE_RTM: should be updated if we support MultiCalendar @@ -1028,14 +1026,16 @@ namespace Avalonia.Controls { for (int childIndex = ColumnsPerMonth; childIndex < count; childIndex++) { - b = monthControl.MonthView.Children[childIndex] as CalendarDayButton; - d = b.DataContext as DateTime?; - - if (d.HasValue) + if (monthControl.MonthView.Children[childIndex] is CalendarDayButton b) { - if (DateTimeHelper.CompareDays(d.Value, day) == 0) + var d = b.DataContext as DateTime?; + + if (d.HasValue) { - return b; + if (DateTimeHelper.CompareDays(d.Value, day) == 0) + { + return b; + } } } } @@ -1044,20 +1044,6 @@ namespace Avalonia.Controls return null; } - private void Calendar_SizeChanged(object sender, EventArgs e) - { - Debug.Assert(sender is Calendar, "The sender should be a Calendar!"); - - var size = Bounds.Size; - RectangleGeometry rg = new RectangleGeometry(); - rg.Rect = new Rect(0, 0, size.Width, size.Height); - - if (Root != null) - { - Root.Clip = rg; - } - } - private void OnSelectedMonthChanged(DateTime? selectedMonth) { if (selectedMonth.HasValue) @@ -1090,7 +1076,6 @@ namespace Avalonia.Controls internal void ResetStates() { - CalendarDayButton d; CalendarItem monthControl = MonthControl; int count = RowsPerMonth * ColumnsPerMonth; if (monthControl != null) @@ -1099,7 +1084,7 @@ namespace Avalonia.Controls { for (int childIndex = ColumnsPerMonth; childIndex < count; childIndex++) { - d = monthControl.MonthView.Children[childIndex] as CalendarDayButton; + var d = (CalendarDayButton)monthControl.MonthView.Children[childIndex]; d.IgnoreMouseOverState(); } } @@ -1190,8 +1175,6 @@ namespace Avalonia.Controls if (HoverEnd != null && HoverStart != null) { int startIndex, endIndex, i; - CalendarDayButton b; - DateTime? d; CalendarItem monthControl = MonthControl; // This assumes a contiguous set of dates: @@ -1201,18 +1184,20 @@ namespace Avalonia.Controls for (i = startIndex; i <= endIndex; i++) { - b = monthControl.MonthView.Children[i] as CalendarDayButton; - b.IsSelected = true; - d = b.DataContext as DateTime?; - - if (d.HasValue && DateTimeHelper.CompareDays(HoverEnd.Value, d.Value) == 0) + if (monthControl.MonthView.Children[i] is CalendarDayButton b) { - if (FocusButton != null) + b.IsSelected = true; + var d = b.DataContext as DateTime?; + + if (d.HasValue && DateTimeHelper.CompareDays(HoverEnd.Value, d.Value) == 0) { - FocusButton.IsCurrent = false; + if (FocusButton != null) + { + FocusButton.IsCurrent = false; + } + b.IsCurrent = HasFocusInternal; + FocusButton = b; } - b.IsCurrent = HasFocusInternal; - FocusButton = b; } } } @@ -1228,8 +1213,6 @@ namespace Avalonia.Controls if (HoverEnd != null && HoverStart != null) { CalendarItem monthControl = MonthControl; - CalendarDayButton b; - DateTime? d; if (HoverEndIndex != null && HoverStartIndex != null) { @@ -1240,15 +1223,17 @@ namespace Avalonia.Controls { for (i = startIndex; i <= endIndex; i++) { - b = monthControl.MonthView.Children[i] as CalendarDayButton; - d = b.DataContext as DateTime?; - - if (d.HasValue) + if (monthControl.MonthView.Children[i] is CalendarDayButton b) { - if (!SelectedDates.Contains(d.Value)) + var d = b.DataContext as DateTime?; + + if (d.HasValue) { - b.IsSelected = false; - } + if (!SelectedDates.Contains(d.Value)) + { + b.IsSelected = false; + } + } } } } @@ -1257,7 +1242,7 @@ namespace Avalonia.Controls // It is SingleRange for (i = startIndex; i <= endIndex; i++) { - (monthControl.MonthView.Children[i] as CalendarDayButton).IsSelected = false; + ((CalendarDayButton)monthControl.MonthView.Children[i]).IsSelected = false; } } } @@ -1628,16 +1613,15 @@ namespace Avalonia.Controls e.Handled = true; } } - internal void Calendar_KeyDown(object sender, KeyEventArgs e) - { - Calendar c = sender as Calendar; - Debug.Assert(c != null, "c should not be null!"); - if (!e.Handled && c.IsEnabled) + internal void Calendar_KeyDown(KeyEventArgs e) + { + if (!e.Handled && IsEnabled) { e.Handled = ProcessCalendarKey(e); } } + internal bool ProcessCalendarKey(KeyEventArgs e) { if (DisplayMode == CalendarMode.Month) @@ -1976,7 +1960,7 @@ namespace Avalonia.Controls } } } - private void Calendar_KeyUp(object sender, KeyEventArgs e) + private void Calendar_KeyUp(KeyEventArgs e) { if (!e.Handled && (e.Key == Key.LeftShift || e.Key == Key.RightShift)) { @@ -2083,6 +2067,9 @@ namespace Avalonia.Controls DisplayDateProperty.Changed.AddClassHandler(x => x.OnDisplayDateChanged); DisplayDateStartProperty.Changed.AddClassHandler(x => x.OnDisplayDateStartChanged); DisplayDateEndProperty.Changed.AddClassHandler(x => x.OnDisplayDateEndChanged); + KeyDownEvent.AddClassHandler(x => x.Calendar_KeyDown); + KeyUpEvent.AddClassHandler(x => x.Calendar_KeyUp); + } /// @@ -2122,10 +2109,6 @@ namespace Avalonia.Controls month.Owner = this; } } - - LayoutUpdated += Calendar_SizeChanged; - KeyDown += Calendar_KeyDown; - KeyUp += Calendar_KeyUp; } } diff --git a/src/Avalonia.Controls/Calendar/CalendarDateRange.cs b/src/Avalonia.Controls/Calendar/CalendarDateRange.cs index 273cda8c5b..718cc7142b 100644 --- a/src/Avalonia.Controls/Calendar/CalendarDateRange.cs +++ b/src/Avalonia.Controls/Calendar/CalendarDateRange.cs @@ -66,7 +66,7 @@ namespace Avalonia.Controls /// Inherited code: Requires comment 2. internal bool ContainsAny(CalendarDateRange range) { - Debug.Assert(range != null, "range should not be null!"); + Contract.Requires(range != null); int start = DateTime.Compare(Start, range.Start); diff --git a/src/Avalonia.Controls/Calendar/CalendarItem.cs b/src/Avalonia.Controls/Calendar/CalendarItem.cs index 3432fa549d..b0cbd0be53 100644 --- a/src/Avalonia.Controls/Calendar/CalendarItem.cs +++ b/src/Avalonia.Controls/Calendar/CalendarItem.cs @@ -517,7 +517,7 @@ namespace Avalonia.Controls.Primitives for (int childIndex = Calendar.ColumnsPerMonth; childIndex < count; childIndex++) { CalendarDayButton childButton = MonthView.Children[childIndex] as CalendarDayButton; - Debug.Assert(childButton != null, "childButton should not be null!"); + Contract.Requires(childButton != null); childButton.Index = childIndex; SetButtonState(childButton, dateToAdd); @@ -554,7 +554,7 @@ namespace Avalonia.Controls.Primitives for (int i = childIndex; i < count; i++) { childButton = MonthView.Children[i] as CalendarDayButton; - Debug.Assert(childButton != null, "childButton should not be null!"); + Contract.Requires(childButton != null); // button needs a content to occupy the necessary space // for the content presenter childButton.Content = i.ToString(DateTimeHelper.GetCurrentDateFormat()); @@ -650,7 +650,7 @@ namespace Avalonia.Controls.Primitives foreach (object child in YearView.Children) { CalendarButton childButton = child as CalendarButton; - Debug.Assert(childButton != null, "childButton should not be null!"); + Contract.Requires(childButton != null); // There should be no time component. Time is 12:00 AM DateTime day = new DateTime(_currentMonth.Year, count + 1, 1); childButton.DataContext = day; @@ -746,7 +746,7 @@ namespace Avalonia.Controls.Primitives foreach (object child in YearView.Children) { CalendarButton childButton = child as CalendarButton; - Debug.Assert(childButton != null, "childButton should not be null!"); + Contract.Requires(childButton != null); year = decade + count; if (year <= DateTime.MaxValue.Year && year >= DateTime.MinValue.Year) @@ -826,7 +826,7 @@ namespace Avalonia.Controls.Primitives { Owner.Focus(); } - Button b = sender as Button; + Button b = (Button)sender; DateTime d; if (b.IsEnabled) @@ -863,7 +863,7 @@ namespace Avalonia.Controls.Primitives Owner.Focus(); } - Button b = sender as Button; + Button b = (Button)sender; if (b.IsEnabled) { Owner.OnPreviousClick(); @@ -878,7 +878,7 @@ namespace Avalonia.Controls.Primitives { Owner.Focus(); } - Button b = sender as Button; + Button b = (Button)sender; if (b.IsEnabled) { @@ -891,8 +891,7 @@ namespace Avalonia.Controls.Primitives { if (Owner != null) { - CalendarDayButton b = sender as CalendarDayButton; - if (_isMouseLeftButtonDown && b != null && b.IsEnabled && !b.IsBlackout) + if (_isMouseLeftButtonDown && sender is CalendarDayButton b && b.IsEnabled && !b.IsBlackout) { // Update the states of all buttons to be selected starting // from HoverStart to b @@ -918,7 +917,7 @@ namespace Avalonia.Controls.Primitives Debug.Assert(b.DataContext != null, "The DataContext should not be null!"); Owner.UnHighlightDays(); Owner.HoverEndIndex = b.Index; - Owner.HoverEnd = (DateTime)b.DataContext; + Owner.HoverEnd = (DateTime?)b.DataContext; // Update the States of the buttons Owner.HighlightDays(); return; @@ -931,7 +930,7 @@ namespace Avalonia.Controls.Primitives { if (_isMouseLeftButtonDown) { - CalendarDayButton b = sender as CalendarDayButton; + CalendarDayButton b = (CalendarDayButton)sender; // The button is in Pressed state. Change the state to normal. if (e.Device.Captured == b) e.Device.Capture(null); @@ -973,7 +972,7 @@ namespace Avalonia.Controls.Primitives if (b.IsEnabled && !b.IsBlackout) { DateTime selectedDate = (DateTime)b.DataContext; - Debug.Assert(selectedDate != null, "selectedDate should not be null!"); + Contract.Requires(selectedDate != null); _isMouseLeftButtonDown = true; // null check is added for unit tests if (e != null) @@ -1149,7 +1148,7 @@ namespace Avalonia.Controls.Primitives if (_isControlPressed && Owner.SelectionMode == CalendarSelectionMode.MultipleRange) { CalendarDayButton b = sender as CalendarDayButton; - Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!"); + Contract.Requires(b != null); if (b.IsSelected) { @@ -1169,7 +1168,7 @@ namespace Avalonia.Controls.Primitives private void Month_CalendarButtonMouseDown(object sender, PointerPressedEventArgs e) { CalendarButton b = sender as CalendarButton; - Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!"); + Contract.Requires(b != null); _isMouseLeftButtonDownYearView = true; @@ -1208,7 +1207,7 @@ namespace Avalonia.Controls.Primitives if (_isMouseLeftButtonDownYearView) { CalendarButton b = sender as CalendarButton; - Debug.Assert(b != null, "The sender should be a non-null CalendarDayButton!"); + Contract.Requires(b != null); UpdateYearViewSelection(b); } } @@ -1217,7 +1216,7 @@ namespace Avalonia.Controls.Primitives { if (_isMouseLeftButtonDownYearView) { - CalendarButton b = sender as CalendarButton; + CalendarButton b = (CalendarButton)sender; // The button is in Pressed state. Change the state to normal. if (e.Device.Captured == b) e.Device.Capture(null); diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/DatePicker.cs index 418ef50b2c..08608ad359 100644 --- a/src/Avalonia.Controls/Calendar/DatePicker.cs +++ b/src/Avalonia.Controls/Calendar/DatePicker.cs @@ -842,7 +842,7 @@ namespace Avalonia.Controls private void Calendar_KeyDown(object sender, KeyEventArgs e) { Calendar c = sender as Calendar; - Debug.Assert(c != null, "The Calendar should not be null!"); + Contract.Requires(c != null); if (!e.Handled && (e.Key == Key.Enter || e.Key == Key.Space || e.Key == Key.Escape) && c.DisplayMode == CalendarMode.Month) { diff --git a/src/Avalonia.Controls/Design.cs b/src/Avalonia.Controls/Design.cs index ce52891749..894240a09f 100644 --- a/src/Avalonia.Controls/Design.cs +++ b/src/Avalonia.Controls/Design.cs @@ -1,5 +1,6 @@ using System.Runtime.CompilerServices; +using Avalonia.Styling; namespace Avalonia.Controls { @@ -45,23 +46,18 @@ namespace Avalonia.Controls { return control.GetValue(DataContextProperty); } - - static readonly ConditionalWeakTable Substitutes = new ConditionalWeakTable(); - + public static readonly AttachedProperty PreviewWithProperty = AvaloniaProperty - .RegisterAttached("PreviewWith", typeof (Design)); + .RegisterAttached("PreviewWith", typeof (Design)); - public static void SetPreviewWith(object target, Control control) + public static void SetPreviewWith(Style target, Control control) { - Substitutes.Remove(target); - Substitutes.Add(target, control); + target.SetValue(PreviewWithProperty, control); } - public static Control GetPreviewWith(object target) + public static Control GetPreviewWith(Style target) { - Control rv; - Substitutes.TryGetValue(target, out rv); - return rv; + return target.GetValue(PreviewWithProperty); } public static void ApplyDesignModeProperties(Control target, Control source) diff --git a/src/Avalonia.Controls/DropDownItem.cs b/src/Avalonia.Controls/DropDownItem.cs index 3fd80c4562..fb465e93ec 100644 --- a/src/Avalonia.Controls/DropDownItem.cs +++ b/src/Avalonia.Controls/DropDownItem.cs @@ -22,14 +22,13 @@ namespace Avalonia.Controls static DropDownItem() { FocusableProperty.OverrideDefaultValue(true); - IsFocusedProperty.Changed.Subscribe(x => - { - var sender = x.Sender as IControl; + } - if (sender != null) - { - ((IPseudoClasses)sender.Classes).Set(":selected", (bool)x.NewValue); - } + public DropDownItem() + { + this.GetObservable(DropDownItem.IsFocusedProperty).Subscribe(focused => + { + PseudoClasses.Set(":selected", focused); }); } diff --git a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs index cd2da692ba..4db16c71a5 100644 --- a/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs +++ b/src/Avalonia.Controls/Embedding/Offscreen/OffscreenTopLevel.cs @@ -57,7 +57,7 @@ namespace Avalonia.Controls.Embedding.Offscreen Type IStyleable.StyleKey => typeof(EmbeddableControlRoot); public void Dispose() { - PlatformImpl.Dispose(); + PlatformImpl?.Dispose(); } } } diff --git a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs index 4f7ac82df7..9ba68f584e 100644 --- a/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs +++ b/src/Avalonia.Controls/Platform/IWindowBaseImpl.cs @@ -72,6 +72,11 @@ namespace Avalonia.Platform /// void SetMinMaxSize(Size minSize, Size maxSize); + /// + /// Sets whether this window appears on top of all other windows + /// + void SetTopmost(bool value); + /// /// Gets platform specific display information /// diff --git a/src/Avalonia.Controls/Platform/InProcessDragSource.cs b/src/Avalonia.Controls/Platform/InProcessDragSource.cs index e136efe2a9..52e09aba45 100644 --- a/src/Avalonia.Controls/Platform/InProcessDragSource.cs +++ b/src/Avalonia.Controls/Platform/InProcessDragSource.cs @@ -62,7 +62,7 @@ namespace Avalonia.Platform RawDragEvent rawEvent = new RawDragEvent(_dragDrop, type, root, pt, _draggedData, _allowedEffects); var tl = root.GetSelfAndVisualAncestors().OfType().FirstOrDefault(); - tl.PlatformImpl.Input(rawEvent); + tl.PlatformImpl?.Input(rawEvent); var effect = GetPreferredEffect(rawEvent.Effects & _allowedEffects, modifiers); UpdateCursor(root, effect); diff --git a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs index c6ef5a14e9..e438843078 100644 --- a/src/Avalonia.Controls/Presenters/CarouselPresenter.cs +++ b/src/Avalonia.Controls/Presenters/CarouselPresenter.cs @@ -106,7 +106,6 @@ namespace Avalonia.Controls.Presenters /// protected override void ItemsChanged(NotifyCollectionChangedEventArgs e) { - // TODO: Handle items changing. switch (e.Action) { case NotifyCollectionChangedAction.Remove: @@ -115,9 +114,35 @@ namespace Avalonia.Controls.Presenters var generator = ItemContainerGenerator; var containers = generator.RemoveRange(e.OldStartingIndex, e.OldItems.Count); Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl)); + + MoveToPage(-1, SelectedIndex); } break; + case NotifyCollectionChangedAction.Reset: + { + var generator = ItemContainerGenerator; + var containers = generator.Containers.ToList(); + generator.Clear(); + Panel.Children.RemoveAll(containers.Select(x => x.ContainerControl)); + + var newIndex = SelectedIndex; + + if(SelectedIndex < 0) + { + if(Items != null && Items.Count() > 0) + { + newIndex = 0; + } + else + { + newIndex = -1; + } + } + + MoveToPage(-1, newIndex); + } + break; } } diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 656f3890cd..005717d681 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -70,6 +70,12 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty StaysOpenProperty = AvaloniaProperty.Register(nameof(StaysOpen), true); + /// + /// Defines the property. + /// + public static readonly StyledProperty TopmostProperty = + AvaloniaProperty.Register(nameof(Topmost)); + private bool _isOpen; private PopupRoot _popupRoot; private TopLevel _topLevel; @@ -84,6 +90,7 @@ namespace Avalonia.Controls.Primitives IsHitTestVisibleProperty.OverrideDefaultValue(false); ChildProperty.Changed.AddClassHandler(x => x.ChildChanged); IsOpenProperty.Changed.AddClassHandler(x => x.IsOpenChanged); + TopmostProperty.Changed.AddClassHandler((p, e) => p.PopupRoot.Topmost = (bool)e.NewValue); } /// @@ -194,6 +201,15 @@ namespace Avalonia.Controls.Primitives set { SetValue(StaysOpenProperty, value); } } + /// + /// Gets or sets whether this popup appears on top of all other windows + /// + public bool Topmost + { + get { return GetValue(TopmostProperty); } + set { SetValue(TopmostProperty, value); } + } + /// /// Gets the root of the popup window. /// diff --git a/src/Avalonia.Controls/Primitives/ScrollBar.cs b/src/Avalonia.Controls/Primitives/ScrollBar.cs index 0057b15150..3ddcb06303 100644 --- a/src/Avalonia.Controls/Primitives/ScrollBar.cs +++ b/src/Avalonia.Controls/Primitives/ScrollBar.cs @@ -6,9 +6,21 @@ using System.Reactive; using System.Reactive.Linq; using Avalonia.Data; using Avalonia.Interactivity; +using Avalonia.Input; namespace Avalonia.Controls.Primitives { + public class ScrollEventArgs : EventArgs + { + public ScrollEventArgs(ScrollEventType eventType, double newValue) + { + ScrollEventType = eventType; + NewValue = newValue; + } + public double NewValue { get; private set; } + public ScrollEventType ScrollEventType { get; private set; } + } + /// /// A scrollbar control. /// @@ -44,6 +56,9 @@ namespace Avalonia.Controls.Primitives { PseudoClass(OrientationProperty, o => o == Orientation.Vertical, ":vertical"); PseudoClass(OrientationProperty, o => o == Orientation.Horizontal, ":horizontal"); + + Thumb.DragDeltaEvent.AddClassHandler(o => o.OnThumbDragDelta, RoutingStrategies.Bubble); + Thumb.DragCompletedEvent.AddClassHandler(o => o.OnThumbDragComplete, RoutingStrategies.Bubble); } /// @@ -88,6 +103,8 @@ namespace Avalonia.Controls.Primitives set { SetValue(OrientationProperty, value); } } + public event EventHandler Scroll; + /// /// Calculates whether the scrollbar should be visible. /// @@ -140,6 +157,8 @@ namespace Avalonia.Controls.Primitives _pageUpButton = e.NameScope.Find