diff --git a/Avalonia.sln b/Avalonia.sln
index 3ee107707f..c2b8243688 100644
--- a/Avalonia.sln
+++ b/Avalonia.sln
@@ -121,10 +121,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ControlCatalog.NetCore", "s
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1-27F5-4255-9AFC-04ABFD11683A}"
ProjectSection(SolutionItems) = preProject
+ build\AndroidWorkarounds.props = build\AndroidWorkarounds.props
build\Base.props = build\Base.props
build\Binding.props = build\Binding.props
- build\BuildTargets.targets = build\BuildTargets.targets
+ build\CoreLibraries.props = build\CoreLibraries.props
+ build\EmbedXaml.props = build\EmbedXaml.props
build\HarfBuzzSharp.props = build\HarfBuzzSharp.props
+ build\iOSWorkarounds.props = build\iOSWorkarounds.props
build\JetBrains.Annotations.props = build\JetBrains.Annotations.props
build\JetBrains.dotMemoryUnit.props = build\JetBrains.dotMemoryUnit.props
build\Magick.NET-Q16-AnyCPU.props = build\Magick.NET-Q16-AnyCPU.props
@@ -134,17 +137,25 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Props", "Props", "{F3AC8BC1
build\NetCore.props = build\NetCore.props
build\NetFX.props = build\NetFX.props
build\ReactiveUI.props = build\ReactiveUI.props
+ build\ReferenceCoreLibraries.props = build\ReferenceCoreLibraries.props
build\Rx.props = build\Rx.props
build\SampleApp.props = build\SampleApp.props
+ build\SharedVersion.props = build\SharedVersion.props
build\SharpDX.props = build\SharpDX.props
build\SkiaSharp.props = build\SkiaSharp.props
+ build\SourceLink.props = build\SourceLink.props
+ build\System.Drawing.Common.props = build\System.Drawing.Common.props
build\System.Memory.props = build\System.Memory.props
+ build\UnitTests.NetFX.props = build\UnitTests.NetFX.props
build\XUnit.props = build\XUnit.props
+ build\ApiDiff.props = build\ApiDiff.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Targets", "Targets", "{4D6FAF79-58B4-482F-9122-0668C346364C}"
ProjectSection(SolutionItems) = preProject
build\UnitTests.NetCore.targets = build\UnitTests.NetCore.targets
+ build\BuildTargets.targets = build\BuildTargets.targets
+ build\LegacyProject.targets = build\LegacyProject.targets
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Linux", "Linux", "{86C53C40-57AA-45B8-AD42-FAE0EFDF0F2B}"
diff --git a/NuGet.Config b/NuGet.Config
index 2a1e0af74d..3abd236d42 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -1,7 +1,9 @@
+
+
diff --git a/build/ApiDiff.props b/build/ApiDiff.props
new file mode 100644
index 0000000000..da82fbcc51
--- /dev/null
+++ b/build/ApiDiff.props
@@ -0,0 +1,12 @@
+
+
+ 0.10.0-preview3
+ $(PackageId)
+ Avalonia
+
+
+
+
+
+
+
diff --git a/build/ReactiveUI.props b/build/ReactiveUI.props
index f827cb9a32..d8e86e917e 100644
--- a/build/ReactiveUI.props
+++ b/build/ReactiveUI.props
@@ -1,5 +1,5 @@
-
+
diff --git a/build/SharedVersion.props b/build/SharedVersion.props
index bd183faab3..d3cebef418 100644
--- a/build/SharedVersion.props
+++ b/build/SharedVersion.props
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
Avalonia
- 0.9.999
+ 0.10.999
Copyright 2020 © The AvaloniaUI Project
https://avaloniaui.net
https://github.com/AvaloniaUI/Avalonia/
diff --git a/build/SkiaSharp.props b/build/SkiaSharp.props
index a8d9332c57..d7d04c7971 100644
--- a/build/SkiaSharp.props
+++ b/build/SkiaSharp.props
@@ -1,6 +1,6 @@
-
-
+
+
diff --git a/native/Avalonia.Native/src/OSX/Screens.mm b/native/Avalonia.Native/src/OSX/Screens.mm
index 278daf9a18..455cfa2e41 100644
--- a/native/Avalonia.Native/src/OSX/Screens.mm
+++ b/native/Avalonia.Native/src/OSX/Screens.mm
@@ -4,6 +4,14 @@ class Screens : public ComSingleObject
{
public:
FORWARD_IUNKNOWN()
+
+ private:
+ CGFloat PrimaryDisplayHeight()
+ {
+ return NSMaxY([[[NSScreen screens] firstObject] frame]);
+ }
+
+public:
virtual HRESULT GetScreenCount (int* ret) override
{
@autoreleasepool
@@ -25,15 +33,15 @@ class Screens : public ComSingleObject
auto screen = [[NSScreen screens] objectAtIndex:index];
- ret->Bounds.X = [screen frame].origin.x;
- ret->Bounds.Y = [screen frame].origin.y;
ret->Bounds.Height = [screen frame].size.height;
ret->Bounds.Width = [screen frame].size.width;
+ ret->Bounds.X = [screen frame].origin.x;
+ ret->Bounds.Y = PrimaryDisplayHeight() - [screen frame].origin.y - ret->Bounds.Height;
- ret->WorkingArea.X = [screen visibleFrame].origin.x;
- ret->WorkingArea.Y = [screen visibleFrame].origin.y;
ret->WorkingArea.Height = [screen visibleFrame].size.height;
ret->WorkingArea.Width = [screen visibleFrame].size.width;
+ ret->WorkingArea.X = [screen visibleFrame].origin.x;
+ ret->WorkingArea.Y = ret->Bounds.Height - [screen visibleFrame].origin.y - ret->WorkingArea.Height;
ret->PixelDensity = [screen backingScaleFactor];
diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm
index 872269bb26..dd241409c7 100644
--- a/native/Avalonia.Native/src/OSX/window.mm
+++ b/native/Avalonia.Native/src/OSX/window.mm
@@ -27,6 +27,7 @@ public:
AvnPoint lastPositionSet;
NSString* _lastTitle;
IAvnMenu* _mainMenu;
+
bool _shown;
WindowBaseImpl(IAvnWindowBaseEvents* events, IAvnGlContext* gl)
@@ -230,6 +231,29 @@ public:
{
@autoreleasepool
{
+ auto maxSize = [Window maxSize];
+ auto minSize = [Window minSize];
+
+ if (x < minSize.width)
+ {
+ x = minSize.width;
+ }
+
+ if (y < minSize.height)
+ {
+ y = minSize.height;
+ }
+
+ if (x > maxSize.width)
+ {
+ x = maxSize.width;
+ }
+
+ if (y > maxSize.height)
+ {
+ y = maxSize.height;
+ }
+
[Window setContentSize:NSSize{x, y}];
return S_OK;
@@ -1291,10 +1315,15 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent
_parent->UpdateCursor();
auto fsize = [self convertSizeToBacking: [self frame].size];
- _lastPixelSize.Width = (int)fsize.width;
- _lastPixelSize.Height = (int)fsize.height;
- [self updateRenderTarget];
- _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
+
+ if(_lastPixelSize.Width != (int)fsize.width || _lastPixelSize.Height != (int)fsize.height)
+ {
+ _lastPixelSize.Width = (int)fsize.width;
+ _lastPixelSize.Height = (int)fsize.height;
+ [self updateRenderTarget];
+
+ _parent->BaseEvents->Resized(AvnSize{newSize.width, newSize.height});
+ }
}
- (void)updateLayer
diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs
index fe877dc49c..fbfbf47e1b 100644
--- a/nukebuild/Build.cs
+++ b/nukebuild/Build.cs
@@ -128,7 +128,9 @@ partial class Build : NukeBuild
{
var webappDir = RootDirectory / "src" / "Avalonia.DesignerSupport" / "Remote" / "HtmlTransport" / "webapp";
- NpmTasks.NpmInstall(c => c.SetWorkingDirectory(webappDir));
+ NpmTasks.NpmInstall(c => c
+ .SetWorkingDirectory(webappDir)
+ .SetArgumentConfigurator(a => a.Add("--silent")));
NpmTasks.NpmRun(c => c
.SetWorkingDirectory(webappDir)
.SetCommand("dist"));
diff --git a/readme.md b/readme.md
index 19a9a8420d..ccdbbfb967 100644
--- a/readme.md
+++ b/readme.md
@@ -1,4 +1,4 @@
-[](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [](#backers) [](#sponsors) 
+[](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) []( https://aka.ms/dotnet-discord) [](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [](#backers) [](#sponsors) 
[](https://www.nuget.org/packages/Avalonia) [](https://www.nuget.org/packages/Avalonia) [](https://www.myget.org/gallery/avalonia-ci) 
@@ -16,7 +16,7 @@ To see the status of some of our features, please see our [Roadmap](https://gith
## 🚀 Getting Started
-The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](http://avaloniaui.net/docs/quickstart/create-new-project).
+The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://avaloniaui.net/docs/quickstart/create-new-project).
Avalonia is delivered via NuGet package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
@@ -47,7 +47,7 @@ We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using
## Documentation
-Documentation can be found on our website at http://avaloniaui.net/docs/. We also have a [tutorial](http://avaloniaui.net/docs/tutorial/) over there for newcomers.
+Documentation can be found on our website at https://avaloniaui.net/docs/. We also have a [tutorial](https://avaloniaui.net/docs/tutorial/) over there for newcomers.
## Building and Using
@@ -68,7 +68,7 @@ Avalonia is licenced under the [MIT licence](licence.md).
## Contributors
-This project exists thanks to all the people who contribute. [[Contribute](http://avaloniaui.net/contributing)].
+This project exists thanks to all the people who contribute. [[Contribute](https://avaloniaui.net/contributing)].
### Backers
diff --git a/samples/BindingDemo/MainWindow.xaml b/samples/BindingDemo/MainWindow.xaml
index 14c371efef..b583503327 100644
--- a/samples/BindingDemo/MainWindow.xaml
+++ b/samples/BindingDemo/MainWindow.xaml
@@ -116,6 +116,7 @@
+
diff --git a/samples/BindingDemo/ViewModels/MainWindowViewModel.cs b/samples/BindingDemo/ViewModels/MainWindowViewModel.cs
index 66800a606c..f0241cad48 100644
--- a/samples/BindingDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/BindingDemo/ViewModels/MainWindowViewModel.cs
@@ -7,6 +7,8 @@ using System.Threading.Tasks;
using System.Threading;
using ReactiveUI;
using Avalonia.Controls;
+using Avalonia.Metadata;
+using Avalonia.Controls.Selection;
namespace BindingDemo.ViewModels
{
@@ -28,7 +30,7 @@ namespace BindingDemo.ViewModels
Detail = "Item " + x + " details",
}));
- Selection = new SelectionModel();
+ Selection = new SelectionModel { SingleSelect = false };
ShuffleItems = ReactiveCommand.Create(() =>
{
@@ -57,7 +59,7 @@ namespace BindingDemo.ViewModels
}
public ObservableCollection Items { get; }
- public SelectionModel Selection { get; }
+ public SelectionModel Selection { get; }
public ReactiveCommand ShuffleItems { get; }
public string BooleanString
@@ -102,5 +104,16 @@ namespace BindingDemo.ViewModels
get { return _nested; }
private set { this.RaiseAndSetIfChanged(ref _nested, value); }
}
+
+ public void Do(object parameter)
+ {
+
+ }
+
+ [DependsOn(nameof(BooleanFlag))]
+ bool CanDo(object parameter)
+ {
+ return BooleanFlag;
+ }
}
}
diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml
index c7a75f5a70..9bac320c79 100644
--- a/samples/ControlCatalog/App.xaml
+++ b/samples/ControlCatalog/App.xaml
@@ -1,17 +1,16 @@
-
-
+
diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index 3f1ec289d1..cb50cba540 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -9,12 +9,23 @@ namespace ControlCatalog
{
public class App : Application
{
+ private static readonly StyleInclude DataGridFluent = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
+ {
+ Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml")
+ };
+
+ private static readonly StyleInclude DataGridDefault = new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
+ {
+ Source = new Uri("avares://Avalonia.Controls.DataGrid/Themes/Default.xaml")
+ };
+
public static Styles FluentDark = new Styles
{
new StyleInclude(new Uri("avares://ControlCatalog/Styles"))
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentDark.xaml")
},
+ DataGridFluent
};
public static Styles FluentLight = new Styles
@@ -23,6 +34,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Fluent/Accents/FluentLight.xaml")
},
+ DataGridFluent
};
public static Styles DefaultLight = new Styles
@@ -43,6 +55,7 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
},
+ DataGridDefault
};
public static Styles DefaultDark = new Styles
@@ -63,13 +76,14 @@ namespace ControlCatalog
{
Source = new Uri("avares://Avalonia.Themes.Default/DefaultTheme.xaml")
},
+ DataGridDefault
};
public override void Initialize()
{
- AvaloniaXamlLoader.Load(this);
-
Styles.Insert(0, FluentDark);
+
+ AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index af95e3c356..efc90357ed 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -1,9 +1,7 @@
+ x:Class="ControlCatalog.MainView">
diff --git a/samples/ControlCatalog/Pages/ContextMenuPage.xaml b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
index 8ccd8e97f7..260162ddb9 100644
--- a/samples/ControlCatalog/Pages/ContextMenuPage.xaml
+++ b/samples/ControlCatalog/Pages/ContextMenuPage.xaml
@@ -14,13 +14,14 @@
Padding="48,48,48,48">
-
+
+
-
+
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index d1742c12b7..d045626c2c 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -18,7 +18,7 @@
-
+
@@ -44,7 +44,8 @@
-
+
+
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml.cs b/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
index b8f63cf3e3..0b7fb12aff 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml.cs
@@ -13,7 +13,7 @@ namespace ControlCatalog.Pages
this.InitializeComponent();
var dg1 = this.FindControl("dataGrid1");
dg1.IsReadOnly = true;
-
+ dg1.LoadingRow += Dg1_LoadingRow;
var collectionView1 = new DataGridCollectionView(Countries.All);
//collectionView.GroupDescriptions.Add(new PathGroupDescription("Region"));
@@ -33,7 +33,7 @@ namespace ControlCatalog.Pages
var items = new List
{
new Person { FirstName = "John", LastName = "Doe" },
- new Person { FirstName = "Elizabeth", LastName = "Thomas" },
+ new Person { FirstName = "Elizabeth", LastName = "Thomas", IsBanned = true },
new Person { FirstName = "Zack", LastName = "Ward" }
};
var collectionView3 = new DataGridCollectionView(items);
@@ -44,6 +44,11 @@ namespace ControlCatalog.Pages
addButton.Click += (a, b) => collectionView3.AddNew();
}
+ private void Dg1_LoadingRow(object sender, DataGridRowEventArgs e)
+ {
+ e.Row.Header = e.Row.GetIndex() + 1;
+ }
+
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
diff --git a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
index 304782dbf9..392ccb57c3 100644
--- a/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
+++ b/samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
@@ -43,7 +43,7 @@
-
+
diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml b/samples/ControlCatalog/Pages/ListBoxPage.xaml
index 47b4ce7151..edf3d41bf5 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml
@@ -10,7 +10,12 @@
HorizontalAlignment="Center"
Spacing="16">
-
+
diff --git a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
index 0f2d4461bf..59c8fc0cbe 100644
--- a/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
+++ b/samples/ControlCatalog/Pages/ListBoxPage.xaml.cs
@@ -1,10 +1,6 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Linq;
-using System.Reactive;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
-using ReactiveUI;
+using ControlCatalog.ViewModels;
namespace ControlCatalog.Pages
{
@@ -13,72 +9,12 @@ namespace ControlCatalog.Pages
public ListBoxPage()
{
InitializeComponent();
- DataContext = new PageViewModel();
+ DataContext = new ListBoxPageViewModel();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
-
- private class PageViewModel : ReactiveObject
- {
- private int _counter;
- private SelectionMode _selectionMode;
-
- public PageViewModel()
- {
- Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
- SelectedItems = new ObservableCollection();
-
- AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
-
- RemoveItemCommand = ReactiveCommand.Create(() =>
- {
- while (SelectedItems.Count > 0)
- {
- Items.Remove(SelectedItems[0]);
- }
- });
-
- SelectRandomItemCommand = ReactiveCommand.Create(() =>
- {
- var random = new Random();
-
- SelectedItem = Items[random.Next(Items.Count - 1)];
- });
- }
-
- public ObservableCollection Items { get; }
-
- private string _selectedItem;
-
- public string SelectedItem
- {
- get { return _selectedItem; }
- set { this.RaiseAndSetIfChanged(ref _selectedItem, value); }
- }
-
-
- public ObservableCollection SelectedItems { get; }
-
- public ReactiveCommand AddItemCommand { get; }
-
- public ReactiveCommand RemoveItemCommand { get; }
-
- public ReactiveCommand SelectRandomItemCommand { get; }
-
- public SelectionMode SelectionMode
- {
- get => _selectionMode;
- set
- {
- SelectedItems.Clear();
- this.RaiseAndSetIfChanged(ref _selectionMode, value);
- }
- }
-
- private string GenerateItem() => $"Item {_counter++.ToString()}";
- }
}
}
diff --git a/samples/ControlCatalog/Pages/MenuPage.xaml b/samples/ControlCatalog/Pages/MenuPage.xaml
index de9ea34e80..2c09cb9b4d 100644
--- a/samples/ControlCatalog/Pages/MenuPage.xaml
+++ b/samples/ControlCatalog/Pages/MenuPage.xaml
@@ -16,11 +16,17 @@
Defined in XAML
+
+
+
+ Mixed
+
+
diff --git a/samples/ControlCatalog/Pages/ScreenPage.cs b/samples/ControlCatalog/Pages/ScreenPage.cs
index d775eb9635..c39f414b44 100644
--- a/samples/ControlCatalog/Pages/ScreenPage.cs
+++ b/samples/ControlCatalog/Pages/ScreenPage.cs
@@ -29,7 +29,8 @@ namespace ControlCatalog.Pages
var screens = w.Screens.All;
var scaling = ((IRenderRoot)w).RenderScaling;
- Pen p = new Pen(Brushes.Black);
+ var drawBrush = Brushes.Green;
+ Pen p = new Pen(drawBrush);
if (screens != null)
foreach (Screen screen in screens)
{
@@ -53,19 +54,19 @@ namespace ControlCatalog.Pages
};
text.Text = $"Bounds: {screen.Bounds.Width}:{screen.Bounds.Height}";
- context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height), text);
+ context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height), text);
text.Text = $"WorkArea: {screen.WorkingArea.Width}:{screen.WorkingArea.Height}";
- context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
+ context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 20), text);
text.Text = $"Scaling: {screen.PixelDensity * 100}%";
- context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
+ context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 40), text);
text.Text = $"Primary: {screen.Primary}";
- context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
+ context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 60), text);
text.Text = $"Current: {screen.Equals(w.Screens.ScreenFromBounds(new PixelRect(w.Position, PixelSize.FromSize(w.Bounds.Size, scaling))))}";
- context.DrawText(Brushes.Black, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
+ context.DrawText(drawBrush, boundsRect.Position.WithY(boundsRect.Size.Height + 80), text);
}
context.DrawRectangle(p, new Rect(w.Position.X / 10f + Math.Abs(_leftMost), w.Position.Y / 10, w.Bounds.Width / 10, w.Bounds.Height / 10));
diff --git a/samples/ControlCatalog/Pages/TextBlockPage.xaml b/samples/ControlCatalog/Pages/TextBlockPage.xaml
index 4b8edcf98c..4a1c196917 100644
--- a/samples/ControlCatalog/Pages/TextBlockPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBlockPage.xaml
@@ -12,7 +12,7 @@
@@ -49,7 +49,7 @@
diff --git a/samples/ControlCatalog/Pages/TextBoxPage.xaml b/samples/ControlCatalog/Pages/TextBoxPage.xaml
index 64118a00b4..481a459159 100644
--- a/samples/ControlCatalog/Pages/TextBoxPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBoxPage.xaml
@@ -20,6 +20,7 @@
@@ -37,6 +38,8 @@
Text="Multiline TextBox with TextWrapping.
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
+
+
resm fonts
diff --git a/samples/ControlCatalog/Pages/TreeViewPage.xaml b/samples/ControlCatalog/Pages/TreeViewPage.xaml
index 789b45e62c..6d99132680 100644
--- a/samples/ControlCatalog/Pages/TreeViewPage.xaml
+++ b/samples/ControlCatalog/Pages/TreeViewPage.xaml
@@ -10,7 +10,7 @@
HorizontalAlignment="Center"
Spacing="16">
-
+
diff --git a/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
new file mode 100644
index 0000000000..d088576998
--- /dev/null
+++ b/samples/ControlCatalog/ViewModels/ListBoxPageViewModel.cs
@@ -0,0 +1,66 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Reactive;
+using Avalonia.Controls;
+using Avalonia.Controls.Selection;
+using ReactiveUI;
+
+namespace ControlCatalog.ViewModels
+{
+ public class ListBoxPageViewModel : ReactiveObject
+ {
+ private int _counter;
+ private SelectionMode _selectionMode;
+
+ public ListBoxPageViewModel()
+ {
+ Items = new ObservableCollection(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
+ Selection = new SelectionModel();
+ Selection.Select(1);
+
+ AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
+
+ RemoveItemCommand = ReactiveCommand.Create(() =>
+ {
+ while (Selection.Count > 0)
+ {
+ Items.Remove(Selection.SelectedItems.First());
+ }
+ });
+
+ SelectRandomItemCommand = ReactiveCommand.Create(() =>
+ {
+ var random = new Random();
+
+ using (Selection.BatchUpdate())
+ {
+ Selection.Clear();
+ Selection.Select(random.Next(Items.Count - 1));
+ }
+ });
+ }
+
+ public ObservableCollection Items { get; }
+
+ public SelectionModel Selection { get; }
+
+ public ReactiveCommand AddItemCommand { get; }
+
+ public ReactiveCommand RemoveItemCommand { get; }
+
+ public ReactiveCommand SelectRandomItemCommand { get; }
+
+ public SelectionMode SelectionMode
+ {
+ get => _selectionMode;
+ set
+ {
+ Selection.Clear();
+ this.RaiseAndSetIfChanged(ref _selectionMode, value);
+ }
+ }
+
+ private string GenerateItem() => $"Item {_counter++.ToString()}";
+ }
+}
diff --git a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
index dc9c4a8f49..9e7ae8b716 100644
--- a/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/MenuPageViewModel.cs
@@ -17,6 +17,23 @@ namespace ControlCatalog.ViewModels
SaveCommand = ReactiveCommand.Create(Save, Observable.Return(false));
OpenRecentCommand = ReactiveCommand.Create(OpenRecent);
+ var recentItems = new[]
+ {
+ new MenuItemViewModel
+ {
+ Header = "File1.txt",
+ Command = OpenRecentCommand,
+ CommandParameter = @"c:\foo\File1.txt"
+ },
+ new MenuItemViewModel
+ {
+ Header = "File2.txt",
+ Command = OpenRecentCommand,
+ CommandParameter = @"c:\foo\File2.txt"
+ },
+ };
+
+ RecentItems = recentItems;
MenuItems = new[]
{
new MenuItemViewModel
@@ -24,27 +41,13 @@ namespace ControlCatalog.ViewModels
Header = "_File",
Items = new[]
{
- new MenuItemViewModel { Header = "_Open...", Command = OpenCommand },
+ new MenuItemViewModel { Header = "O_pen...", Command = OpenCommand },
new MenuItemViewModel { Header = "Save", Command = SaveCommand },
new MenuItemViewModel { Header = "-" },
new MenuItemViewModel
{
Header = "Recent",
- Items = new[]
- {
- new MenuItemViewModel
- {
- Header = "File1.txt",
- Command = OpenRecentCommand,
- CommandParameter = @"c:\foo\File1.txt"
- },
- new MenuItemViewModel
- {
- Header = "File2.txt",
- Command = OpenRecentCommand,
- CommandParameter = @"c:\foo\File2.txt"
- },
- }
+ Items = recentItems
},
}
},
@@ -61,6 +64,7 @@ namespace ControlCatalog.ViewModels
}
public IReadOnlyList MenuItems { get; set; }
+ public IReadOnlyList RecentItems { get; set; }
public ReactiveCommand OpenCommand { get; }
public ReactiveCommand SaveCommand { get; }
public ReactiveCommand OpenRecentCommand { get; }
diff --git a/samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs b/samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
index 5bc23e2fe5..210e281ed6 100644
--- a/samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
+++ b/samples/ControlCatalog/ViewModels/TreeViewPageViewModel.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
@@ -18,8 +17,7 @@ namespace ControlCatalog.ViewModels
_root = new Node();
Items = _root.Children;
- Selection = new SelectionModel();
- Selection.SelectionChanged += SelectionChanged;
+ SelectedItems = new ObservableCollection();
AddItemCommand = ReactiveCommand.Create(AddItem);
RemoveItemCommand = ReactiveCommand.Create(RemoveItem);
@@ -27,7 +25,7 @@ namespace ControlCatalog.ViewModels
}
public ObservableCollection Items { get; }
- public SelectionModel Selection { get; }
+ public ObservableCollection SelectedItems { get; }
public ReactiveCommand AddItemCommand { get; }
public ReactiveCommand RemoveItemCommand { get; }
public ReactiveCommand SelectRandomItemCommand { get; }
@@ -37,24 +35,24 @@ namespace ControlCatalog.ViewModels
get => _selectionMode;
set
{
- Selection.ClearSelection();
+ SelectedItems.Clear();
this.RaiseAndSetIfChanged(ref _selectionMode, value);
}
}
private void AddItem()
{
- var parentItem = Selection.SelectedItems.Count > 0 ? (Node)Selection.SelectedItems[0] : _root;
+ var parentItem = SelectedItems.Count > 0 ? (Node)SelectedItems[0] : _root;
parentItem.AddItem();
}
private void RemoveItem()
{
- while (Selection.SelectedItems.Count > 0)
+ while (SelectedItems.Count > 0)
{
- Node lastItem = (Node)Selection.SelectedItems[0];
+ Node lastItem = (Node)SelectedItems[0];
RecursiveRemove(Items, lastItem);
- Selection.DeselectAt(Selection.SelectedIndices[0]);
+ SelectedItems.RemoveAt(0);
}
bool RecursiveRemove(ObservableCollection items, Node selectedItem)
@@ -80,16 +78,16 @@ namespace ControlCatalog.ViewModels
{
var random = new Random();
var depth = random.Next(4);
- var indexes = Enumerable.Range(0, 4).Select(x => random.Next(10));
- var path = new IndexPath(indexes);
- Selection.SelectedIndex = path;
- }
+ var indexes = Enumerable.Range(0, depth).Select(x => random.Next(10));
+ var node = _root;
- private void SelectionChanged(object sender, SelectionModelSelectionChangedEventArgs e)
- {
- var selected = string.Join(",", e.SelectedIndices);
- var deselected = string.Join(",", e.DeselectedIndices);
- System.Diagnostics.Debug.WriteLine($"Selected '{selected}', Deselected '{deselected}'");
+ foreach (var i in indexes)
+ {
+ node = node.Children[i];
+ }
+
+ SelectedItems.Clear();
+ SelectedItems.Add(node);
}
public class Node
diff --git a/samples/RenderDemo/MainWindow.xaml b/samples/RenderDemo/MainWindow.xaml
index 14ccc82043..770960d7c4 100644
--- a/samples/RenderDemo/MainWindow.xaml
+++ b/samples/RenderDemo/MainWindow.xaml
@@ -44,6 +44,9 @@
+
+
+
diff --git a/samples/RenderDemo/Pages/WriteableBitmapPage.cs b/samples/RenderDemo/Pages/WriteableBitmapPage.cs
new file mode 100644
index 0000000000..850e398a93
--- /dev/null
+++ b/samples/RenderDemo/Pages/WriteableBitmapPage.cs
@@ -0,0 +1,92 @@
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.LogicalTree;
+using Avalonia.Media;
+using Avalonia.Media.Imaging;
+using Avalonia.Media.Immutable;
+using Avalonia.Platform;
+using Avalonia.Threading;
+
+namespace RenderDemo.Pages
+{
+ public class WriteableBitmapPage : Control
+ {
+ private WriteableBitmap _unpremulBitmap;
+ private WriteableBitmap _premulBitmap;
+ private readonly Stopwatch _st = Stopwatch.StartNew();
+
+ protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ _unpremulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Unpremul);
+ _premulBitmap = new WriteableBitmap(new PixelSize(256, 256), new Vector(96, 96), PixelFormat.Bgra8888, AlphaFormat.Premul);
+
+ base.OnAttachedToLogicalTree(e);
+ }
+
+ protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
+ {
+ base.OnDetachedFromLogicalTree(e);
+
+ _unpremulBitmap?.Dispose();
+ _unpremulBitmap = null;
+
+ _premulBitmap?.Dispose();
+ _unpremulBitmap = null;
+ }
+
+ public override void Render(DrawingContext context)
+ {
+ void FillPixels(WriteableBitmap bitmap, byte fillAlpha, bool premul)
+ {
+ using (var fb = bitmap.Lock())
+ {
+ var data = new int[fb.Size.Width * fb.Size.Height];
+
+ for (int y = 0; y < fb.Size.Height; y++)
+ {
+ for (int x = 0; x < fb.Size.Width; x++)
+ {
+ var color = new Color(fillAlpha, 0, 255, 0);
+
+ if (premul)
+ {
+ byte r = (byte) (color.R * color.A / 255);
+ byte g = (byte) (color.G * color.A / 255);
+ byte b = (byte) (color.B * color.A / 255);
+
+ color = new Color(fillAlpha, r, g, b);
+ }
+
+ data[y * fb.Size.Width + x] = (int) color.ToUint32();
+ }
+ }
+
+ Marshal.Copy(data, 0, fb.Address, fb.Size.Width * fb.Size.Height);
+ }
+ }
+
+ base.Render(context);
+
+ byte alpha = (byte)((_st.ElapsedMilliseconds / 10) % 256);
+
+ FillPixels(_unpremulBitmap, alpha, false);
+ FillPixels(_premulBitmap, alpha, true);
+
+ context.FillRectangle(Brushes.Red, new Rect(0, 0, 256 * 3, 256));
+
+ context.DrawImage(_unpremulBitmap,
+ new Rect(0, 0, 256, 256),
+ new Rect(0, 0, 256, 256));
+
+ context.DrawImage(_premulBitmap,
+ new Rect(0, 0, 256, 256),
+ new Rect(256, 0, 256, 256));
+
+ context.FillRectangle(new ImmutableSolidColorBrush(Colors.Lime, alpha / 255d), new Rect(512, 0, 256, 256));
+
+ Dispatcher.UIThread.Post(InvalidateVisual, DispatcherPriority.Background);
+ }
+ }
+}
diff --git a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
index 3a6ed88fcd..852c01399f 100644
--- a/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
+++ b/samples/VirtualizationDemo/ViewModels/MainWindowViewModel.cs
@@ -7,6 +7,7 @@ using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using ReactiveUI;
using Avalonia.Layout;
+using Avalonia.Controls.Selection;
namespace VirtualizationDemo.ViewModels
{
@@ -48,7 +49,7 @@ namespace VirtualizationDemo.ViewModels
set { this.RaiseAndSetIfChanged(ref _itemCount, value); }
}
- public SelectionModel Selection { get; } = new SelectionModel();
+ public SelectionModel Selection { get; } = new SelectionModel();
public AvaloniaList Items
{
@@ -137,9 +138,9 @@ namespace VirtualizationDemo.ViewModels
{
var index = Items.Count;
- if (Selection.SelectedIndices.Count > 0)
+ if (Selection.SelectedItems.Count > 0)
{
- index = Selection.SelectedIndex.GetAt(0);
+ index = Selection.SelectedIndex;
}
Items.Insert(index, new ItemViewModel(_newItemIndex++, NewItemString));
@@ -149,7 +150,7 @@ namespace VirtualizationDemo.ViewModels
{
if (Selection.SelectedItems.Count > 0)
{
- Items.RemoveAll(Selection.SelectedItems.Cast().ToList());
+ Items.RemoveAll(Selection.SelectedItems.ToList());
}
}
@@ -163,7 +164,7 @@ namespace VirtualizationDemo.ViewModels
private void SelectItem(int index)
{
- Selection.SelectedIndex = new IndexPath(index);
+ Selection.SelectedIndex = index;
}
}
}
diff --git a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
index 69fd2a9f13..71dce93ce7 100644
--- a/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
+++ b/src/Android/Avalonia.Android/Platform/SkiaPlatform/TopLevelImpl.cs
@@ -126,7 +126,7 @@ namespace Avalonia.Android.Platform.SkiaPlatform
_view.Visibility = ViewStates.Visible;
}
- public double Scaling => 1;
+ public double RenderScaling => 1;
void Draw()
{
diff --git a/src/Avalonia.Animation/Avalonia.Animation.csproj b/src/Avalonia.Animation/Avalonia.Animation.csproj
index 73c619942e..ee91acf45e 100644
--- a/src/Avalonia.Animation/Avalonia.Animation.csproj
+++ b/src/Avalonia.Animation/Avalonia.Animation.csproj
@@ -1,9 +1,10 @@
- netstandard2.0
+ netstandard2.0
+
diff --git a/src/Avalonia.Base/Avalonia.Base.csproj b/src/Avalonia.Base/Avalonia.Base.csproj
index cbcf7a7386..9bfd387ca9 100644
--- a/src/Avalonia.Base/Avalonia.Base.csproj
+++ b/src/Avalonia.Base/Avalonia.Base.csproj
@@ -3,7 +3,7 @@
netstandard2.0
Avalonia.Base
Avalonia
- True
+ True
@@ -13,4 +13,5 @@
+
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index d18f0b3f94..65233f9230 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -806,7 +806,9 @@ namespace Avalonia
break;
}
- if (p.IsDataValidationEnabled)
+ var metadata = p.GetMetadata(GetType());
+
+ if (metadata.EnableDataValidation == true)
{
UpdateDataValidation(property, value);
}
diff --git a/src/Avalonia.Base/AvaloniaProperty.cs b/src/Avalonia.Base/AvaloniaProperty.cs
index a873d5fd42..39391490b0 100644
--- a/src/Avalonia.Base/AvaloniaProperty.cs
+++ b/src/Avalonia.Base/AvaloniaProperty.cs
@@ -369,14 +369,14 @@ namespace Avalonia
var metadata = new DirectPropertyMetadata(
unsetValue: unsetValue,
- defaultBindingMode: defaultBindingMode);
+ defaultBindingMode: defaultBindingMode,
+ enableDataValidation: enableDataValidation);
var result = new DirectProperty(
name,
getter,
setter,
- metadata,
- enableDataValidation);
+ metadata);
AvaloniaPropertyRegistry.Instance.Register(typeof(TOwner), result);
return result;
}
diff --git a/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs b/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs
deleted file mode 100644
index 7f4c83772d..0000000000
--- a/src/Avalonia.Base/Data/Converters/AlwaysEnabledDelegateCommand.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using System;
-using System.Globalization;
-using System.Reflection;
-using System.Windows.Input;
-using Avalonia.Utilities;
-
-namespace Avalonia.Data.Converters
-{
- class AlwaysEnabledDelegateCommand : ICommand
- {
- private readonly Delegate action;
-
- private ParameterInfo parameterInfo;
-
- public AlwaysEnabledDelegateCommand(Delegate action)
- {
- this.action = action;
- var parameters = action.Method.GetParameters();
- parameterInfo = parameters.Length == 0 ? null : parameters[0];
- }
-
-#pragma warning disable 0067
- public event EventHandler CanExecuteChanged;
-#pragma warning restore 0067
-
- public bool CanExecute(object parameter) => true;
-
- public void Execute(object parameter)
- {
- if (parameterInfo == null)
- {
- action.DynamicInvoke();
- }
- else
- {
- TypeUtilities.TryConvert(parameterInfo.ParameterType, parameter, CultureInfo.CurrentCulture, out object convertedParameter);
- action.DynamicInvoke(convertedParameter);
- }
- }
- }
-}
diff --git a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
index 5e80a15059..83f7e02c16 100644
--- a/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
+++ b/src/Avalonia.Base/Data/Converters/DefaultValueConverter.cs
@@ -33,7 +33,7 @@ namespace Avalonia.Data.Converters
if (typeof(ICommand).IsAssignableFrom(targetType) && value is Delegate d && d.Method.GetParameters().Length <= 1)
{
- return new AlwaysEnabledDelegateCommand(d);
+ return new MethodToCommandConverter(d);
}
if (TypeUtilities.TryConvert(targetType, value, culture, out object result))
diff --git a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs
new file mode 100644
index 0000000000..7e7417d2f5
--- /dev/null
+++ b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs
@@ -0,0 +1,230 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Linq;
+using System.Linq.Expressions;
+using System.Reflection;
+using System.Windows.Input;
+using Avalonia.Utilities;
+
+namespace Avalonia.Data.Converters
+{
+ class MethodToCommandConverter : ICommand
+ {
+ readonly static Func