diff --git a/Avalonia.sln b/Avalonia.sln
index aeae8f2f1f..ffcf266b0c 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -224,6 +224,10 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.Markup.Xaml.Loader
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.Events", "src\Avalonia.ReactiveUI.Events\Avalonia.ReactiveUI.Events.csproj", "{28F18757-C3E6-4BBE-A37D-11BA2AB9177C}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avalonia.ReactiveUI.Events.UnitTests", "tests\Avalonia.ReactiveUI.Events.UnitTests\Avalonia.ReactiveUI.Events.UnitTests.csproj", "{780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sandbox", "samples\Sandbox\Sandbox.csproj", "{11BE52AF-E2DD-4CF0-B19A-05285ACAF571}"
+EndProject
Global
GlobalSection(SharedMSBuildProjectFiles) = preSolution
src\Shared\RenderHelpers\RenderHelpers.projitems*{3c4c0cb4-0c0f-4450-a37b-148c84ff905f}*SharedItemsImports = 13
@@ -2038,6 +2042,54 @@ Global
{28F18757-C3E6-4BBE-A37D-11BA2AB9177C}.Release|iPhone.Build.0 = Release|Any CPU
{28F18757-C3E6-4BBE-A37D-11BA2AB9177C}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
{28F18757-C3E6-4BBE-A37D-11BA2AB9177C}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|Any CPU.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|Any CPU.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|iPhone.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|iPhone.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Ad-Hoc|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|Any CPU.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|Any CPU.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|iPhone.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|iPhone.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.AppStore|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|iPhone.Build.0 = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|Any CPU.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|Any CPU.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhone.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhone.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhone.ActiveCfg = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhone.Build.0 = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|Any CPU.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhone.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhone.Build.0 = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571}.Release|iPhoneSimulator.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -2096,6 +2148,8 @@ Global
{351337F5-D66F-461B-A957-4EF60BDB4BA6} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
{3C84E04B-36CF-4D0D-B965-C26DD649D1F3} = {A0CC0258-D18C-4AB3-854F-7101680FC3F9}
{909A8CBD-7D0E-42FD-B841-022AD8925820} = {8B6A8209-894F-4BA1-B880-965FD453982C}
+ {780AC0FE-8DD2-419F-A1DC-AC7E3EB393F7} = {C5A00AC3-B34C-4564-9BDD-2DA473EF4D8B}
+ {11BE52AF-E2DD-4CF0-B19A-05285ACAF571} = {9B9E3891-2366-4253-A952-D08BCEB71098}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {87366D66-1391-4D90-8999-95A620AD786A}
diff --git a/Avalonia.v3.ncrunchsolution b/Avalonia.v3.ncrunchsolution
index bef7e45524..afce1018ec 100644
--- a/Avalonia.v3.ncrunchsolution
+++ b/Avalonia.v3.ncrunchsolution
@@ -6,6 +6,9 @@
src\Avalonia.Build.Tasks\bin\Debug\netstandard2.0\Mono.Cecil.dll
True
+
+ RunApiCompat = false
+
.ncrunch
True
diff --git a/build/NetFX.props b/build/NetFX.props
index ed5cb6dd69..8ffc9ec561 100644
--- a/build/NetFX.props
+++ b/build/NetFX.props
@@ -1,7 +1,7 @@
-
+
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index d7d04c7971..f2e7df36cd 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index efc90357ed..790813fda0 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -45,7 +45,10 @@
-
+
+
+
diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml
index edf3d41bf5..3521ad71a9 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml
@@ -1,35 +1,25 @@
-
- ListBox
- Hosts a collection of ListBoxItem.
-
-
-
-
-
-
-
-
-
-
-
-
- Single
- Multiple
- Toggle
- AlwaysSelected
-
-
+
+
+ ListBox
+ Hosts a collection of ListBoxItem.
-
+
+ Multiple
+ Toggle
+ AlwaysSelected
+ AutoScrollToSelectedItem
+
+
+
+
+
+
+
+
diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
index d088576998..f75bc32105 100644
--- a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
@@ -10,22 +10,39 @@ namespace ControlCatalog.ViewModels
{
public class ListBoxPageViewModel : ReactiveObject
{
+ private bool _multiple;
+ private bool _toggle;
+ private bool _alwaysSelected;
+ private bool _autoScrollToSelectedItem = true;
private int _counter;
- private SelectionMode _selectionMode;
+ private ObservableAsPropertyHelper _selectionMode;
public ListBoxPageViewModel()
{
Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
+
Selection = new SelectionModel();
Selection.Select(1);
+ _selectionMode = this.WhenAnyValue(
+ x => x.Multiple,
+ x => x.Toggle,
+ x => x.AlwaysSelected,
+ (m, t, a) =>
+ (m ? SelectionMode.Multiple : 0) |
+ (t ? SelectionMode.Toggle : 0) |
+ (a ? SelectionMode.AlwaysSelected : 0))
+ .ToProperty(this, x => x.SelectionMode);
+
AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
RemoveItemCommand = ReactiveCommand.Create(() =>
{
- while (Selection.Count > 0)
+ var items = Selection.SelectedItems.ToList();
+
+ foreach (var item in items)
{
- Items.Remove(Selection.SelectedItems.First());
+ Items.Remove(item);
}
});
@@ -42,25 +59,37 @@ namespace ControlCatalog.ViewModels
}
public ObservableCollection Items { get; }
-
public SelectionModel Selection { get; }
+ public SelectionMode SelectionMode => _selectionMode.Value;
- public ReactiveCommand AddItemCommand { get; }
+ public bool Multiple
+ {
+ get => _multiple;
+ set => this.RaiseAndSetIfChanged(ref _multiple, value);
+ }
- public ReactiveCommand RemoveItemCommand { get; }
+ public bool Toggle
+ {
+ get => _toggle;
+ set => this.RaiseAndSetIfChanged(ref _toggle, value);
+ }
- public ReactiveCommand SelectRandomItemCommand { get; }
+ public bool AlwaysSelected
+ {
+ get => _alwaysSelected;
+ set => this.RaiseAndSetIfChanged(ref _alwaysSelected, value);
+ }
- public SelectionMode SelectionMode
+ public bool AutoScrollToSelectedItem
{
- get => _selectionMode;
- set
- {
- Selection.Clear();
- this.RaiseAndSetIfChanged(ref _selectionMode, value);
- }
+ get => _autoScrollToSelectedItem;
+ set => this.RaiseAndSetIfChanged(ref _autoScrollToSelectedItem, value);
}
+ public ReactiveCommand AddItemCommand { get; }
+ public ReactiveCommand RemoveItemCommand { get; }
+ public ReactiveCommand SelectRandomItemCommand { get; }
+
private string GenerateItem() => $"Item {_counter++.ToString()}";
}
}
diff --git a/samples/Sandbox/App.axaml b/samples/Sandbox/App.axaml
new file mode 100644
index 0000000000..699781eb94
--- /dev/null
+++ b/samples/Sandbox/App.axaml
@@ -0,0 +1,8 @@
+
+
+
+
+
diff --git a/samples/Sandbox/App.axaml.cs b/samples/Sandbox/App.axaml.cs
new file mode 100644
index 0000000000..7eb8345784
--- /dev/null
+++ b/samples/Sandbox/App.axaml.cs
@@ -0,0 +1,22 @@
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+
+namespace Sandbox
+{
+ public class App : Application
+ {
+ public override void Initialize()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktopLifetime)
+ {
+ desktopLifetime.MainWindow = new MainWindow();
+ }
+ }
+ }
+}
diff --git a/samples/Sandbox/MainWindow.axaml b/samples/Sandbox/MainWindow.axaml
new file mode 100644
index 0000000000..6929f192c7
--- /dev/null
+++ b/samples/Sandbox/MainWindow.axaml
@@ -0,0 +1,4 @@
+
+
diff --git a/samples/Sandbox/MainWindow.axaml.cs b/samples/Sandbox/MainWindow.axaml.cs
new file mode 100644
index 0000000000..b7222e043d
--- /dev/null
+++ b/samples/Sandbox/MainWindow.axaml.cs
@@ -0,0 +1,20 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Sandbox
+{
+ public class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ this.InitializeComponent();
+ this.AttachDevTools();
+ }
+
+ private void InitializeComponent()
+ {
+ AvaloniaXamlLoader.Load(this);
+ }
+ }
+}
diff --git a/samples/Sandbox/Program.cs b/samples/Sandbox/Program.cs
new file mode 100644
index 0000000000..4d7eda8d9f
--- /dev/null
+++ b/samples/Sandbox/Program.cs
@@ -0,0 +1,17 @@
+using Avalonia;
+using Avalonia.ReactiveUI;
+
+namespace Sandbox
+{
+ public class Program
+ {
+ static void Main(string[] args)
+ {
+ AppBuilder.Configure()
+ .UsePlatformDetect()
+ .UseReactiveUI()
+ .LogToDebug()
+ .StartWithClassicDesktopLifetime(args);
+ }
+ }
+}
diff --git a/samples/Sandbox/Sandbox.csproj b/samples/Sandbox/Sandbox.csproj
new file mode 100644
index 0000000000..1a0a8a7ce5
--- /dev/null
+++ b/samples/Sandbox/Sandbox.csproj
@@ -0,0 +1,18 @@
+
+
+
+ WinExe
+ netcoreapp3.1
+ true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
index 8e82bf1a38..1e72a07760 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
@@ -49,8 +49,12 @@ namespace Avalonia.Controls
{
if(_binding is Avalonia.Data.Binding binding)
{
- // Force the TwoWay binding mode if there is a Path present. TwoWay binding requires a Path.
- if (!String.IsNullOrEmpty(binding.Path))
+ 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)
{
binding.Mode = BindingMode.TwoWay;
}
diff --git a/src/Avalonia.Controls/ListBox.cs b/src/Avalonia.Controls/ListBox.cs
index f7e86d697a..d1b8038581 100644
--- a/src/Avalonia.Controls/ListBox.cs
+++ b/src/Avalonia.Controls/ListBox.cs
@@ -163,6 +163,7 @@ namespace Avalonia.Controls
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
+ base.OnApplyTemplate(e);
Scroll = e.NameScope.Find("PART_ScrollViewer");
}
}
diff --git a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
index 5f8c5da2f8..c954f9fd4a 100644
--- a/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
+++ b/src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
@@ -6,7 +6,6 @@ using System.ComponentModel;
using System.Linq;
using Avalonia.Controls.Generators;
using Avalonia.Controls.Selection;
-using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Input.Platform;
@@ -70,8 +69,8 @@ namespace Avalonia.Controls.Primitives
///
/// Defines the property.
///
- protected static readonly DirectProperty SelectedItemsProperty =
- AvaloniaProperty.RegisterDirect(
+ protected static readonly DirectProperty SelectedItemsProperty =
+ AvaloniaProperty.RegisterDirect(
nameof(SelectedItems),
o => o.SelectedItems,
(o, v) => o.SelectedItems = v);
@@ -111,12 +110,13 @@ namespace Avalonia.Controls.Primitives
RoutingStrategies.Bubble);
private static readonly IList Empty = Array.Empty