diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index c99a6b117b..874560a294 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -34,7 +34,8 @@
+ ScrollViewer.VerticalScrollBarVisibility="Disabled"
+ ScrollViewer.HorizontalScrollBarVisibility="Disabled">
diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
index d0631d2cbd..103c016298 100644
--- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
+++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
@@ -14,12 +14,19 @@
UniformGrid - Horizontal
+
-
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
index 1a607342f3..decd849adc 100644
--- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml.cs
@@ -74,7 +74,7 @@ namespace ControlCatalog.Pages
private void RepeaterClick(object sender, PointerPressedEventArgs e)
{
- var item = (e.Source as TextBlock)?.DataContext as string;
+ var item = (e.Source as TextBlock)?.DataContext as ItemsRepeaterPageViewModel.Item;
((ItemsRepeaterPageViewModel)DataContext).SelectedItem = item;
}
}
diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
index cdbf8fd2b6..0f2d4461bf 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
@@ -78,7 +78,7 @@ namespace ControlCatalog.Pages
}
}
- private string GenerateItem() => $"Item {_counter++}";
+ private string GenerateItem() => $"Item {_counter++.ToString()}";
}
}
}
diff --git a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
index 436a479441..bc2ce80714 100644
--- a/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/ItemsRepeaterPageViewModel.cs
@@ -1,4 +1,5 @@
-using System.Collections.ObjectModel;
+using System;
+using System.Collections.ObjectModel;
using System.Linq;
using ReactiveUI;
@@ -10,18 +11,44 @@ namespace ControlCatalog.ViewModels
public ItemsRepeaterPageViewModel()
{
- Items = new ObservableCollection(
- Enumerable.Range(1, 100000).Select(i => $"Item {i}"));
+ Items = new ObservableCollection- (
+ Enumerable.Range(1, 100000).Select(i => new Item
+ {
+ Text = $"Item {i.ToString()}",
+ }));
}
- public ObservableCollection Items { get; }
+ public ObservableCollection
- Items { get; }
- public string SelectedItem { get; set; }
+ public Item SelectedItem { get; set; }
public void AddItem()
{
var index = SelectedItem != null ? Items.IndexOf(SelectedItem) : -1;
- Items.Insert(index + 1, $"New Item {newItemIndex++}");
+ Items.Insert(index + 1, new Item { Text = $"New Item {newItemIndex++}" });
+ }
+
+ public void RandomizeHeights()
+ {
+ var random = new Random();
+
+ foreach (var i in Items)
+ {
+ i.Height = random.Next(240) + 10;
+ }
+ }
+
+ public class Item : ReactiveObject
+ {
+ private double _height = double.NaN;
+
+ public string Text { get; set; }
+
+ public double Height
+ {
+ get => _height;
+ set => this.RaiseAndSetIfChanged(ref _height, value);
+ }
}
}
}
diff --git a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
index b44f392ce3..0c15524362 100644
--- a/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
+++ b/src/Avalonia.Animation/DisposeAnimationInstanceSubject.cs
@@ -2,14 +2,7 @@
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Reactive.Linq;
using Avalonia.Animation.Animators;
-using Avalonia.Animation.Utils;
-using Avalonia.Collections;
-using Avalonia.Data;
-using Avalonia.Reactive;
namespace Avalonia.Animation
{
@@ -46,6 +39,7 @@ namespace Avalonia.Animation
public void OnError(Exception error)
{
_lastInstance?.Dispose();
+ _lastInstance = null;
}
void IObserver.OnNext(bool matchVal)
@@ -53,12 +47,18 @@ namespace Avalonia.Animation
if (matchVal != _lastMatch)
{
_lastInstance?.Dispose();
+
if (matchVal)
{
_lastInstance = _animator.Run(_animation, _control, _clock, _onComplete);
}
+ else
+ {
+ _lastInstance = null;
+ }
+
_lastMatch = matchVal;
}
}
}
-}
\ No newline at end of file
+}
diff --git a/src/Avalonia.Base/PriorityLevel.cs b/src/Avalonia.Base/PriorityLevel.cs
index 6366911e77..a2364083ea 100644
--- a/src/Avalonia.Base/PriorityLevel.cs
+++ b/src/Avalonia.Base/PriorityLevel.cs
@@ -3,7 +3,8 @@
using System;
using System.Collections.Generic;
-using System.Reactive.Disposables;
+using System.Diagnostics;
+using System.Threading;
using Avalonia.Data;
namespace Avalonia
@@ -181,9 +182,9 @@ namespace Avalonia
private sealed class RemoveBindingDisposable : IDisposable
{
- private readonly LinkedListNode _binding;
private readonly LinkedList _bindings;
private readonly PriorityLevel _priorityLevel;
+ private LinkedListNode _binding;
public RemoveBindingDisposable(
LinkedListNode binding,
@@ -197,11 +198,21 @@ namespace Avalonia
public void Dispose()
{
- PriorityBindingEntry entry = _binding.Value;
+ LinkedListNode binding = Interlocked.Exchange(ref _binding, null);
+
+ if (binding == null)
+ {
+ // Some system is trying to remove binding twice.
+ Debug.Assert(false);
+
+ return;
+ }
+
+ PriorityBindingEntry entry = binding.Value;
if (!entry.HasCompleted)
{
- _bindings.Remove(_binding);
+ _bindings.Remove(binding);
entry.Dispose();
diff --git a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs
index bda85f90e2..140da6750d 100644
--- a/src/Avalonia.Base/Utilities/SingleOrDictionary.cs
+++ b/src/Avalonia.Base/Utilities/SingleOrDictionary.cs
@@ -38,7 +38,7 @@ namespace Avalonia.Utilities
{
if (dictionary == null)
{
- if (!_singleValue.HasValue || !_singleValue.Value.Key.Equals(key))
+ if (!_singleValue.HasValue || !EqualityComparer.Default.Equals(_singleValue.Value.Key, key))
{
value = default(TValue);
return false;
diff --git a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
index f4cec98628..37e25d0fac 100644
--- a/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
+++ b/src/Avalonia.Base/Utilities/WeakEventHandlerManager.cs
@@ -142,10 +142,12 @@ namespace Avalonia.Utilities
_data = ndata;
}
+ MethodInfo method = s.Method;
+
var subscriber = (TSubscriber)s.Target;
- if (!s_Callers.TryGetValue(s.Method, out var caller))
- s_Callers[s.Method] = caller =
- (CallerDelegate)Delegate.CreateDelegate(typeof(CallerDelegate), null, s.Method);
+ if (!s_Callers.TryGetValue(method, out var caller))
+ s_Callers[method] = caller =
+ (CallerDelegate)Delegate.CreateDelegate(typeof(CallerDelegate), null, method);
_data[_count] = new Descriptor
{
Caller = caller,
diff --git a/src/Avalonia.Controls/Calendar/DatePicker.cs b/src/Avalonia.Controls/Calendar/DatePicker.cs
index 70de8bec16..55797ae1e3 100644
--- a/src/Avalonia.Controls/Calendar/DatePicker.cs
+++ b/src/Avalonia.Controls/Calendar/DatePicker.cs
@@ -1042,7 +1042,8 @@ namespace Avalonia.Controls
}
}
DateTime? d = SetTextBoxValue(s);
- if (!SelectedDate.Equals(d))
+
+ if (SelectedDate != d)
{
SelectedDate = d;
}
@@ -1058,7 +1059,8 @@ namespace Avalonia.Controls
else
{
DateTime? d = SetTextBoxValue(_defaultText);
- if (!SelectedDate.Equals(d))
+
+ if (SelectedDate != d)
{
SelectedDate = d;
}
diff --git a/src/Avalonia.Controls/Presenters/TextPresenter.cs b/src/Avalonia.Controls/Presenters/TextPresenter.cs
index debbb81264..5931fec350 100644
--- a/src/Avalonia.Controls/Presenters/TextPresenter.cs
+++ b/src/Avalonia.Controls/Presenters/TextPresenter.cs
@@ -244,7 +244,7 @@ namespace Avalonia.Controls.Presenters
var rect = FormattedText.HitTestTextPosition(caretIndex);
this.BringIntoView(rect);
},
- DispatcherPriority.Normal);
+ DispatcherPriority.Render);
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index a50175bdee..6869ea0822 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -1088,7 +1088,9 @@ namespace Avalonia.Controls.Primitives
}
else
{
- SelectedIndex = _updateSelectedIndex != int.MinValue ? _updateSelectedIndex : 0;
+ SelectedIndex = _updateSelectedIndex != int.MinValue ?
+ _updateSelectedIndex :
+ AlwaysSelected ? 0 : -1;
}
}
}
diff --git a/src/Avalonia.Controls/Primitives/Track.cs b/src/Avalonia.Controls/Primitives/Track.cs
index 21a7dd68f8..a569808b35 100644
--- a/src/Avalonia.Controls/Primitives/Track.cs
+++ b/src/Avalonia.Controls/Primitives/Track.cs
@@ -1,10 +1,13 @@
-// 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.
+// Portions of this source file are adapted from the Windows Presentation Foundation project.
+// (https://github.com/dotnet/wpf/)
+//
+// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
using Avalonia.Input;
using Avalonia.Layout;
using Avalonia.Metadata;
+using Avalonia.Utilities;
namespace Avalonia.Controls.Primitives
{
@@ -34,6 +37,9 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty