diff --git a/samples/ControlCatalog/App.xaml.cs b/samples/ControlCatalog/App.xaml.cs
index cb50cba540..22f4e9be1f 100644
--- a/samples/ControlCatalog/App.xaml.cs
+++ b/samples/ControlCatalog/App.xaml.cs
@@ -81,7 +81,7 @@ namespace ControlCatalog
public override void Initialize()
{
- Styles.Insert(0, FluentDark);
+ Styles.Insert(0, FluentLight);
AvaloniaXamlLoader.Load(this);
}
diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml
index 790813fda0..bd5beafe29 100644
--- a/samples/ControlCatalog/MainView.xaml
+++ b/samples/ControlCatalog/MainView.xaml
@@ -77,8 +77,8 @@
Full Decorations
- Fluent - Dark
Fluent - Light
+ Fluent - Dark
Simple - Light
Simple - Dark
diff --git a/samples/ControlCatalog/MainView.xaml.cs b/samples/ControlCatalog/MainView.xaml.cs
index b0c205246e..c84f2f06b6 100644
--- a/samples/ControlCatalog/MainView.xaml.cs
+++ b/samples/ControlCatalog/MainView.xaml.cs
@@ -38,10 +38,10 @@ namespace ControlCatalog
switch (themes.SelectedIndex)
{
case 0:
- Application.Current.Styles[0] = App.FluentDark;
+ Application.Current.Styles[0] = App.FluentLight;
break;
case 1:
- Application.Current.Styles[0] = App.FluentLight;
+ Application.Current.Styles[0] = App.FluentDark;
break;
case 2:
Application.Current.Styles[0] = App.DefaultLight;
diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml
index d045626c2c..cacc2204bd 100644
--- a/samples/ControlCatalog/Pages/DataGridPage.xaml
+++ b/samples/ControlCatalog/Pages/DataGridPage.xaml
@@ -11,12 +11,17 @@
-
+
DataGrid
A control for displaying and interacting with a data source.
-
+
+
+
+
+
+
@@ -39,13 +44,13 @@
-
+
-
-
-
+
+
+
diff --git a/samples/ControlCatalog/Pages/TextBlockPage.xaml b/samples/ControlCatalog/Pages/TextBlockPage.xaml
index 4a1c196917..d4f72f161a 100644
--- a/samples/ControlCatalog/Pages/TextBlockPage.xaml
+++ b/samples/ControlCatalog/Pages/TextBlockPage.xaml
@@ -18,8 +18,8 @@
-
-
+
+
diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs
index 233160b025..340ccdae19 100644
--- a/samples/RenderDemo/App.xaml.cs
+++ b/samples/RenderDemo/App.xaml.cs
@@ -18,6 +18,10 @@ namespace RenderDemo
// App configuration, used by the entry point and previewer
static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure()
+ .With(new Win32PlatformOptions
+ {
+ OverlayPopups = true,
+ })
.UsePlatformDetect()
.UseReactiveUI()
.LogToDebug();
diff --git a/src/Avalonia.Animation/KeySplineTypeConverter.cs b/src/Avalonia.Animation/KeySplineTypeConverter.cs
index cd7427a37d..b026206e5f 100644
--- a/src/Avalonia.Animation/KeySplineTypeConverter.cs
+++ b/src/Avalonia.Animation/KeySplineTypeConverter.cs
@@ -19,7 +19,7 @@ namespace Avalonia.Animation
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
- return KeySpline.Parse((string)value, culture);
+ return KeySpline.Parse((string)value, CultureInfo.InvariantCulture);
}
}
}
diff --git a/src/Avalonia.Base/AvaloniaLocator.cs b/src/Avalonia.Base/AvaloniaLocator.cs
index f9bbe38bec..3163d15c1b 100644
--- a/src/Avalonia.Base/AvaloniaLocator.cs
+++ b/src/Avalonia.Base/AvaloniaLocator.cs
@@ -54,6 +54,23 @@ namespace Avalonia
return _locator;
}
+ public AvaloniaLocator ToLazy(Func func) where TImlp : TService
+ {
+ var constructed = false;
+ TImlp instance = default;
+ _locator._registry[typeof (TService)] = () =>
+ {
+ if (!constructed)
+ {
+ instance = func();
+ constructed = true;
+ }
+
+ return instance;
+ };
+ return _locator;
+ }
+
public AvaloniaLocator ToSingleton() where TImpl : class, TService, new()
{
TImpl instance = null;
diff --git a/src/Avalonia.Base/AvaloniaObject.cs b/src/Avalonia.Base/AvaloniaObject.cs
index 65233f9230..6645d25b5d 100644
--- a/src/Avalonia.Base/AvaloniaObject.cs
+++ b/src/Avalonia.Base/AvaloniaObject.cs
@@ -113,16 +113,8 @@ namespace Avalonia
/// The binding information.
public IBinding this[IndexerDescriptor binding]
{
- get
- {
- return new IndexerBinding(this, binding.Property, binding.Mode);
- }
-
- set
- {
- var sourceBinding = value as IBinding;
- this.Bind(binding.Property, sourceBinding);
- }
+ get { return new IndexerBinding(this, binding.Property, binding.Mode); }
+ set { this.Bind(binding.Property, value); }
}
public bool CheckAccess() => Dispatcher.UIThread.CheckAccess();
diff --git a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
index 3b61f6d898..f052283b22 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
@@ -63,12 +63,12 @@ namespace Avalonia.Data.Core.Plugins
{
if (errors.Count == 1)
{
- return new ValidationException(errors[0].ErrorMessage);
+ return new DataValidationException(errors[0].ErrorMessage);
}
else
{
return new AggregateException(
- errors.Select(x => new ValidationException(x.ErrorMessage)));
+ errors.Select(x => new DataValidationException(x.ErrorMessage)));
}
}
}
diff --git a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
index 8fc2a7b77c..3bf6842cd6 100644
--- a/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
+++ b/src/Avalonia.Base/Data/Core/Plugins/InpcPropertyAccessorPlugin.cs
@@ -1,4 +1,5 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using Avalonia.Utilities;
@@ -11,8 +12,11 @@ namespace Avalonia.Data.Core.Plugins
///
public class InpcPropertyAccessorPlugin : IPropertyAccessorPlugin
{
+ private readonly Dictionary<(Type, string), PropertyInfo> _propertyLookup =
+ new Dictionary<(Type, string), PropertyInfo>();
+
///
- public bool Match(object obj, string propertyName) => GetPropertyWithName(obj.GetType(), propertyName) != null;
+ public bool Match(object obj, string propertyName) => GetFirstPropertyWithName(obj.GetType(), propertyName) != null;
///
/// Starts monitoring the value of a property on an object.
@@ -30,7 +34,7 @@ namespace Avalonia.Data.Core.Plugins
reference.TryGetTarget(out object instance);
- var p = GetPropertyWithName(instance.GetType(), propertyName);
+ var p = GetFirstPropertyWithName(instance.GetType(), propertyName);
if (p != null)
{
@@ -44,12 +48,40 @@ namespace Avalonia.Data.Core.Plugins
}
}
- private static PropertyInfo GetPropertyWithName(Type type, string propertyName)
+ private PropertyInfo GetFirstPropertyWithName(Type type, string propertyName)
{
- const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public |
- BindingFlags.Static | BindingFlags.Instance;
+ var key = (type, propertyName);
+
+ if (!_propertyLookup.TryGetValue(key, out PropertyInfo propertyInfo))
+ {
+ propertyInfo = TryFindAndCacheProperty(type, propertyName);
+ }
+
+ return propertyInfo;
+ }
+
+ private PropertyInfo TryFindAndCacheProperty(Type type, string propertyName)
+ {
+ PropertyInfo found = null;
+
+ const BindingFlags bindingFlags =
+ BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance;
+
+ var properties = type.GetProperties(bindingFlags);
+
+ foreach (PropertyInfo propertyInfo in properties)
+ {
+ if (propertyInfo.Name == propertyName)
+ {
+ found = propertyInfo;
+
+ break;
+ }
+ }
+
+ _propertyLookup.Add((type, propertyName), found);
- return type.GetProperty(propertyName, bindingFlags);
+ return found;
}
private class Accessor : PropertyAccessorBase, IWeakSubscriber
diff --git a/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
new file mode 100644
index 0000000000..82472c505a
--- /dev/null
+++ b/src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
@@ -0,0 +1,5 @@
+Compat issues with assembly Avalonia.Controls.DataGrid:
+MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.DataGridTextColumn.FontFamilyProperty' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public System.String Avalonia.Controls.DataGridTextColumn.FontFamily.get()' does not exist in the implementation but it does exist in the contract.
+MembersMustExist : Member 'public void Avalonia.Controls.DataGridTextColumn.FontFamily.set(System.String)' does not exist in the implementation but it does exist in the contract.
+Total Issues: 3
diff --git a/src/Avalonia.Controls.DataGrid/DataGrid.cs b/src/Avalonia.Controls.DataGrid/DataGrid.cs
index 7c57ea3db9..5bb2763566 100644
--- a/src/Avalonia.Controls.DataGrid/DataGrid.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGrid.cs
@@ -31,7 +31,7 @@ namespace Avalonia.Controls
///
/// Displays data in a customizable grid.
///
- [PseudoClasses(":invalid")]
+ [PseudoClasses(":invalid", ":empty-rows", ":empty-columns")]
public partial class DataGrid : TemplatedControl
{
private const string DATAGRID_elementRowsPresenterName = "PART_RowsPresenter";
@@ -711,6 +711,7 @@ namespace Avalonia.Controls
DisplayData = new DataGridDisplayData(this);
ColumnsInternal = CreateColumnsInstance();
+ ColumnsInternal.CollectionChanged += ColumnsInternal_CollectionChanged;
RowHeightEstimate = DATAGRID_defaultRowHeight;
RowDetailsHeightEstimate = 0;
@@ -727,6 +728,8 @@ namespace Avalonia.Controls
CurrentCellCoordinates = new DataGridCellCoordinates(-1, -1);
RowGroupHeaderHeightEstimate = DATAGRID_defaultRowHeight;
+
+ UpdatePseudoClasses();
}
private void SetValueNoCallback(AvaloniaProperty property, T value, BindingPriority priority = BindingPriority.LocalValue)
@@ -851,9 +854,27 @@ namespace Avalonia.Controls
// can be set when the DataGrid is not part of the visual tree
_measured = false;
InvalidateMeasure();
+
+ UpdatePseudoClasses();
}
}
+ private void ColumnsInternal_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
+ {
+ if (e.Action == NotifyCollectionChangedAction.Add
+ || e.Action == NotifyCollectionChangedAction.Remove
+ || e.Action == NotifyCollectionChangedAction.Reset)
+ {
+ UpdatePseudoClasses();
+ }
+ }
+
+ internal void UpdatePseudoClasses()
+ {
+ PseudoClasses.Set(":empty-columns", !ColumnsInternal.GetVisibleColumns().Any());
+ PseudoClasses.Set(":empty-rows", !DataConnection.Any());
+ }
+
private void OnSelectedIndexChanged(AvaloniaPropertyChangedEventArgs e)
{
if (!_areHandlersSuspended)
@@ -1348,7 +1369,6 @@ namespace Avalonia.Controls
internal DataGridColumnCollection ColumnsInternal
{
get;
- private set;
}
internal int AnchorSlot
diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
index f1bbea9949..e2a067ac61 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
@@ -17,9 +17,7 @@ namespace Avalonia.Controls
///
public class DataGridCheckBoxColumn : DataGridBoundColumn
{
-
private bool _beganEditWithKeyboard;
- private bool _isThreeState;
private CheckBox _currentCheckBox;
private DataGrid _owningGrid;
@@ -31,6 +29,12 @@ namespace Avalonia.Controls
BindingTarget = CheckBox.IsCheckedProperty;
}
+ ///
+ /// Defines the property.
+ ///
+ public static StyledProperty IsThreeStateProperty =
+ CheckBox.IsThreeStateProperty.AddOwner();
+
///
/// Gets or sets a value that indicates whether the hosted controls allow three states or two.
///
@@ -39,17 +43,17 @@ namespace Avalonia.Controls
///
public bool IsThreeState
{
- get
- {
- return _isThreeState;
- }
- set
+ get => GetValue(IsThreeStateProperty);
+ set => SetValue(IsThreeStateProperty, value);
+ }
+
+ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
+ {
+ base.OnPropertyChanged(change);
+
+ if (change.Property == IsThreeStateProperty)
{
- if (_isThreeState != value)
- {
- _isThreeState = value;
- NotifyPropertyChanged(nameof(IsThreeState));
- }
+ NotifyPropertyChanged(change.Property.Name);
}
}
@@ -203,9 +207,9 @@ namespace Avalonia.Controls
{
throw new ArgumentNullException("element");
}
- if(element is CheckBox checkBox)
+ if (element is CheckBox checkBox)
{
- checkBox.IsThreeState = IsThreeState;
+ DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
else
{
@@ -229,7 +233,7 @@ namespace Avalonia.Controls
{
checkBox.HorizontalAlignment = HorizontalAlignment.Center;
checkBox.VerticalAlignment = VerticalAlignment.Center;
- checkBox.IsThreeState = IsThreeState;
+ DataGridHelper.SyncColumnProperty(this, checkBox, IsThreeStateProperty);
}
private bool EnsureOwningGrid()
diff --git a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
index 19539bf032..a94acdec57 100644
--- a/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
+++ b/src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
@@ -77,24 +77,7 @@ namespace Avalonia.Controls
private set;
}
- public int Count
- {
- get
- {
- IList list = List;
- if (list != null)
- {
- return list.Count;
- }
-
- if(DataSource is DataGridCollectionView cv)
- {
- return cv.Count;
- }
-
- return DataSource?.Cast
@@ -53,7 +53,6 @@
Grid.Row="0"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}"
- Margin="{DynamicResource ToggleSwitchTopHeaderMargin}"
VerticalAlignment="Top"/>
+
+
+