Browse Source

Merge branch 'master' into render-inside-win-ui-comp-tree

win-ui-comp-with-manual-fbo
danwalmsley 5 years ago
committed by GitHub
parent
commit
10dac50a52
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 17
      samples/ControlCatalog/Pages/DataGridPage.xaml
  2. 2
      src/Avalonia.Animation/KeySplineTypeConverter.cs
  3. 4
      src/Avalonia.Base/Data/Core/Plugins/DataAnnotationsValidationPlugin.cs
  4. 5
      src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt
  5. 24
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  6. 34
      src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs
  7. 39
      src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
  8. 231
      src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs
  9. 21
      src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml
  10. 22
      src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs
  11. 9
      src/Avalonia.Controls/Calendar/CalendarDatePicker.cs
  12. 4
      src/Avalonia.Controls/ComboBox.cs
  13. 6
      src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs
  14. 21
      src/Avalonia.Controls/Primitives/Popup.cs
  15. 4
      src/Avalonia.Themes.Default/ComboBox.xaml
  16. 2
      src/Avalonia.Themes.Default/MenuItem.xaml
  17. 33
      src/Avalonia.Themes.Fluent/CheckBox.xaml
  18. 3
      src/Avalonia.Themes.Fluent/ComboBox.xaml
  19. 2
      src/Avalonia.Themes.Fluent/ContextMenu.xaml
  20. 85
      src/Avalonia.Themes.Fluent/ListBoxItem.xaml
  21. 4
      src/Avalonia.Themes.Fluent/MenuItem.xaml
  22. 92
      src/Avalonia.Themes.Fluent/ScrollViewer.xaml
  23. 4
      tests/Avalonia.Base.UnitTests/Data/Core/Plugins/DataAnnotationsValidationPluginTests.cs
  24. 2
      tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs
  25. 10
      tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs
  26. 45
      tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs
  27. 50
      tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs

17
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -11,12 +11,17 @@
<Setter Property="Background" Value="{Binding Path=GDP, Mode=OneWay, Converter={StaticResource GDPConverter}}" />
</Style>
</UserControl.Styles>
<Grid RowDefinitions="Auto,*">
<Grid RowDefinitions="Auto,Auto,*">
<StackPanel Orientation="Vertical" Spacing="4" Grid.Row="0">
<TextBlock Classes="h1">DataGrid</TextBlock>
<TextBlock Classes="h2">A control for displaying and interacting with a data source.</TextBlock>
</StackPanel>
<TabControl Grid.Row="1">
<StackPanel Grid.Row="1" Spacing="4" Orientation="Horizontal" IsVisible="{Binding #EditableTab.IsSelected}">
<TextBlock Text="FontSize:" VerticalAlignment="Center"/>
<Slider x:Name="FontSizeSlider" Minimum="5" Maximum="30" Value="14" Width="100" VerticalAlignment="Center" />
<CheckBox x:Name="IsThreeStateCheckBox" IsChecked="False" Content="IsThreeState"/>
</StackPanel>
<TabControl Grid.Row="2">
<TabItem Header="DataGrid">
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
<DataGrid.Columns>
@ -39,13 +44,13 @@
</DataGrid.Columns>
</DataGrid>
</TabItem>
<TabItem Header="Editable">
<TabItem x:Name="EditableTab" Header="Editable">
<Grid RowDefinitions="*,Auto">
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0">
<DataGrid.Columns>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" />
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridTextColumn Header="Last" Binding="{Binding LastName}" Width="2*" FontSize="{Binding #FontSizeSlider.Value, Mode=OneWay}" />
<DataGridCheckBoxColumn Header="Is Banned" Binding="{Binding IsBanned}" Width="*" IsThreeState="{Binding #IsThreeStateCheckBox.IsChecked, Mode=OneWay}" />
</DataGrid.Columns>
</DataGrid>
<Button Grid.Row="1" Name="btnAdd" Margin="12,0,12,12" Content="Add" HorizontalAlignment="Right" />

2
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);
}
}
}

4
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)));
}
}
}

5
src/Avalonia.Controls.DataGrid/ApiCompatBaseline.txt

@ -0,0 +1,5 @@
Compat issues with assembly Avalonia.Controls.DataGrid:
MembersMustExist : Member 'public Avalonia.StyledProperty<System.String> Avalonia.StyledProperty<System.String> 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

24
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -31,7 +31,7 @@ namespace Avalonia.Controls
/// <summary>
/// Displays data in a customizable grid.
/// </summary>
[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<T>(AvaloniaProperty<T> 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

34
src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs

@ -17,9 +17,7 @@ namespace Avalonia.Controls
/// </summary>
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;
}
/// <summary>
/// Defines the <see cref="IsThreeState"/> property.
/// </summary>
public static StyledProperty<bool> IsThreeStateProperty =
CheckBox.IsThreeStateProperty.AddOwner<DataGridCheckBoxColumn>();
/// <summary>
/// Gets or sets a value that indicates whether the hosted <see cref="T:System.Windows.Controls.CheckBox" /> controls allow three states or two.
/// </summary>
@ -39,17 +43,17 @@ namespace Avalonia.Controls
/// </returns>
public bool IsThreeState
{
get
{
return _isThreeState;
}
set
get => GetValue(IsThreeStateProperty);
set => SetValue(IsThreeStateProperty, value);
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> 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()

39
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<object>().Count() ?? 0;
}
}
public int Count => GetCount(true);
public bool DataIsPrimitive
{
@ -210,6 +193,24 @@ namespace Avalonia.Controls
}
}
internal bool Any()
{
return GetCount(false) > 0;
}
/// <param name="allowSlow">When "allowSlow" is false, method will not use Linq.Count() method and will return 0 or 1 instead.</param>
private int GetCount(bool allowSlow)
{
return DataSource switch
{
ICollection collection => collection.Count,
DataGridCollectionView cv => cv.Count,
IEnumerable enumerable when allowSlow => enumerable.Cast<object>().Count(),
IEnumerable enumerable when !allowSlow => enumerable.Cast<object>().Any() ? 1 : 0,
_ => 0
};
}
/// <summary>
/// Puts the entity into editing mode if possible
/// </summary>
@ -675,6 +676,8 @@ namespace Avalonia.Controls
}
break;
}
_owner.UpdatePseudoClasses();
}
private void UpdateDataProperties()

231
src/Avalonia.Controls.DataGrid/DataGridTextColumn.cs

@ -20,11 +20,6 @@ namespace Avalonia.Controls
{
private const string DATAGRID_TextColumnCellTextBlockMarginKey = "DataGridTextColumnCellTextBlockMargin";
private double? _fontSize;
private FontStyle? _fontStyle;
private FontWeight? _fontWeight;
private IBrush _foreground;
/// <summary>
/// Initializes a new instance of the <see cref="T:Avalonia.Controls.DataGridTextColumn" /> class.
/// </summary>
@ -36,18 +31,24 @@ namespace Avalonia.Controls
/// <summary>
/// Identifies the FontFamily dependency property.
/// </summary>
public static readonly StyledProperty<string> FontFamilyProperty =
AvaloniaProperty.Register<DataGridTextColumn, string>(nameof(FontFamily));
public static readonly AttachedProperty<FontFamily> FontFamilyProperty =
TextBlock.FontFamilyProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font name.
/// </summary>
public string FontFamily
public FontFamily FontFamily
{
get { return GetValue(FontFamilyProperty); }
set { SetValue(FontFamilyProperty, value); }
get => GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
/// <summary>
/// Identifies the FontSize dependency property.
/// </summary>
public static readonly AttachedProperty<double> FontSizeProperty =
TextBlock.FontSizeProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font size.
/// </summary>
@ -55,74 +56,66 @@ namespace Avalonia.Controls
[DefaultValue(double.NaN)]
public double FontSize
{
get
{
return _fontSize ?? Double.NaN;
}
set
{
if (_fontSize != value)
{
_fontSize = value;
NotifyPropertyChanged(nameof(FontSize));
}
}
get => GetValue(FontSizeProperty);
set => SetValue(FontSizeProperty, value);
}
/// <summary>
/// Identifies the FontStyle dependency property.
/// </summary>
public static readonly AttachedProperty<FontStyle> FontStyleProperty =
TextBlock.FontStyleProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font style.
/// </summary>
public FontStyle FontStyle
{
get
{
return _fontStyle ?? FontStyle.Normal;
}
set
{
if (_fontStyle != value)
{
_fontStyle = value;
NotifyPropertyChanged(nameof(FontStyle));
}
}
get => GetValue(FontStyleProperty);
set => SetValue(FontStyleProperty, value);
}
/// <summary>
/// Identifies the FontWeight dependency property.
/// </summary>
public static readonly AttachedProperty<FontWeight> FontWeightProperty =
TextBlock.FontWeightProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets the font weight or thickness.
/// </summary>
public FontWeight FontWeight
{
get
{
return _fontWeight ?? FontWeight.Normal;
}
set
{
if (_fontWeight != value)
{
_fontWeight = value;
NotifyPropertyChanged(nameof(FontWeight));
}
}
get => GetValue(FontWeightProperty);
set => SetValue(FontWeightProperty, value);
}
/// <summary>
/// Identifies the Foreground dependency property.
/// </summary>
public static readonly AttachedProperty<IBrush> ForegroundProperty =
TextBlock.ForegroundProperty.AddOwner<DataGridTextColumn>();
/// <summary>
/// Gets or sets a brush that describes the foreground of the column cells.
/// </summary>
public IBrush Foreground
{
get
{
return _foreground;
}
set
get => GetValue(ForegroundProperty);
set => SetValue(ForegroundProperty, value);
}
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == FontFamilyProperty
|| change.Property == FontSizeProperty
|| change.Property == FontStyleProperty
|| change.Property == FontWeightProperty
|| change.Property == ForegroundProperty)
{
if (_foreground != value)
{
_foreground = value;
NotifyPropertyChanged(nameof(Foreground));
}
NotifyPropertyChanged(change.Property.Name);
}
}
@ -154,26 +147,7 @@ namespace Avalonia.Controls
Background = new SolidColorBrush(Colors.Transparent)
};
if (IsSet(FontFamilyProperty))
{
textBox.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBox.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBox.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBox.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBox.Foreground = _foreground;
}
SyncProperties(textBox);
return textBox;
}
@ -192,26 +166,8 @@ namespace Avalonia.Controls
VerticalAlignment = VerticalAlignment.Center
};
if (IsSet(FontFamilyProperty))
{
textBlockElement.FontFamily = FontFamily;
}
if (_fontSize.HasValue)
{
textBlockElement.FontSize = _fontSize.Value;
}
if (_fontStyle.HasValue)
{
textBlockElement.FontStyle = _fontStyle.Value;
}
if (_fontWeight.HasValue)
{
textBlockElement.FontWeight = _fontWeight.Value;
}
if (_foreground != null)
{
textBlockElement.Foreground = _foreground;
}
SyncProperties(textBlockElement);
if (Binding != null)
{
textBlockElement.Bind(TextBlock.TextProperty, Binding);
@ -261,99 +217,42 @@ namespace Avalonia.Controls
throw new ArgumentNullException("element");
}
if(element is TextBox textBox)
if (element is AvaloniaObject content)
{
if (propertyName == nameof(FontFamily))
{
textBox.FontFamily = FontFamily;
DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
}
else if (propertyName == nameof(FontSize))
{
SetTextFontSize(textBox, TextBox.FontSizeProperty);
DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
textBox.FontStyle = FontStyle;
DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
}
else if (propertyName == nameof(FontWeight))
{
textBox.FontWeight = FontWeight;
DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
}
else if (propertyName == nameof(Foreground))
{
textBox.Foreground = Foreground;
}
else
{
if (FontFamily != null)
{
textBox.FontFamily = FontFamily;
}
SetTextFontSize(textBox, TextBox.FontSizeProperty);
textBox.FontStyle = FontStyle;
textBox.FontWeight = FontWeight;
if (Foreground != null)
{
textBox.Foreground = Foreground;
}
}
}
else if (element is TextBlock textBlock)
{
if (propertyName == nameof(FontFamily))
{
textBlock.FontFamily = FontFamily;
}
else if (propertyName == nameof(FontSize))
{
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
}
else if (propertyName == nameof(FontStyle))
{
textBlock.FontStyle = FontStyle;
}
else if (propertyName == nameof(FontWeight))
{
textBlock.FontWeight = FontWeight;
}
else if (propertyName == nameof(Foreground))
{
textBlock.Foreground = Foreground;
}
else
{
if (FontFamily != null)
{
textBlock.FontFamily = FontFamily;
}
SetTextFontSize(textBlock, TextBlock.FontSizeProperty);
textBlock.FontStyle = FontStyle;
textBlock.FontWeight = FontWeight;
if (Foreground != null)
{
textBlock.Foreground = Foreground;
}
DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
}
else
{
throw DataGridError.DataGrid.ValueIsNotAnInstanceOfEitherOr("element", typeof(TextBox), typeof(TextBlock));
throw DataGridError.DataGrid.ValueIsNotAnInstanceOf("element", typeof(AvaloniaObject));
}
}
private void SetTextFontSize(AvaloniaObject textElement, AvaloniaProperty fontSizeProperty)
private void SyncProperties(AvaloniaObject content)
{
double newFontSize = FontSize;
if (double.IsNaN(newFontSize))
{
textElement.ClearValue(fontSizeProperty);
}
else
{
textElement.SetValue(fontSizeProperty, newFontSize);
}
DataGridHelper.SyncColumnProperty(this, content, FontFamilyProperty);
DataGridHelper.SyncColumnProperty(this, content, FontSizeProperty);
DataGridHelper.SyncColumnProperty(this, content, FontStyleProperty);
DataGridHelper.SyncColumnProperty(this, content, FontWeightProperty);
DataGridHelper.SyncColumnProperty(this, content, ForegroundProperty);
}
}
}

21
src/Avalonia.Controls.DataGrid/Themes/Fluent.xaml

@ -588,18 +588,11 @@
<!--<DataGridColumnHeader Name="PART_TopRightCornerHeader"
Grid.Column="2"
Template="{StaticResource TopRightHeaderTemplate}" />-->
<!--<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
<Rectangle Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3"
VerticalAlignment="Bottom"
StrokeThickness="1"
Height="1"
Fill="{DynamicResource DataGridGridLinesBrush}" />-->
<Border Name="PART_ColumnHeadersAndRowsSeparator"
Grid.ColumnSpan="3"
Height="2"
VerticalAlignment="Bottom"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource DataGridGridLinesBrush}" />
Fill="{DynamicResource DataGridGridLinesBrush}" />
<DataGridRowsPresenter Name="PART_RowsPresenter"
Grid.Row="1"
@ -642,4 +635,14 @@
</ControlTemplate>
</Setter>
</Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeader#PART_TopLeftCornerHeader">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ DataGridColumnHeadersPresenter#PART_ColumnHeadersPresenter">
<Setter Property="IsVisible" Value="False" />
</Style>
<Style Selector="DataGrid:empty-columns /template/ Rectangle#PART_ColumnHeadersAndRowsSeparator">
<Setter Property="IsVisible" Value="False" />
</Style>
</Styles>

22
src/Avalonia.Controls.DataGrid/Utils/DataGridHelper.cs

@ -0,0 +1,22 @@
namespace Avalonia.Controls
{
internal static class DataGridHelper
{
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> property)
{
SyncColumnProperty(column, content, property, property);
}
internal static void SyncColumnProperty<T>(AvaloniaObject column, AvaloniaObject content, AvaloniaProperty<T> contentProperty, AvaloniaProperty<T> columnProperty)
{
if (!column.IsSet(columnProperty))
{
content.ClearValue(contentProperty);
}
else
{
content.SetValue(contentProperty, column.GetValue(columnProperty));
}
}
}
}

9
src/Avalonia.Controls/Calendar/CalendarDatePicker.cs

@ -420,7 +420,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp -= Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged -= Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged -= Calendar_SelectedDatesChanged;
_calendar.PointerPressed -= Calendar_PointerPressed;
_calendar.PointerReleased -= Calendar_PointerReleased;
_calendar.KeyDown -= Calendar_KeyDown;
}
_calendar = e.NameScope.Find<Calendar>(ElementCalendar);
@ -435,7 +435,7 @@ namespace Avalonia.Controls
_calendar.DayButtonMouseUp += Calendar_DayButtonMouseUp;
_calendar.DisplayDateChanged += Calendar_DisplayDateChanged;
_calendar.SelectedDatesChanged += Calendar_SelectedDatesChanged;
_calendar.PointerPressed += Calendar_PointerPressed;
_calendar.PointerReleased += Calendar_PointerReleased;
_calendar.KeyDown += Calendar_KeyDown;
//_calendar.SizeChanged += new SizeChangedEventHandler(Calendar_SizeChanged);
//_calendar.IsTabStop = true;
@ -831,9 +831,10 @@ namespace Avalonia.Controls
}
}
}
private void Calendar_PointerPressed(object sender, PointerPressedEventArgs e)
private void Calendar_PointerReleased(object sender, PointerReleasedEventArgs e)
{
if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed)
if (e.InitialPressMouseButton == MouseButton.Left)
{
e.Handled = true;
}

4
src/Avalonia.Controls/ComboBox.cs

@ -257,7 +257,7 @@ namespace Avalonia.Controls
}
/// <inheritdoc/>
protected override void OnPointerPressed(PointerPressedEventArgs e)
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
if (!e.Handled)
{
@ -276,7 +276,7 @@ namespace Avalonia.Controls
}
}
base.OnPointerPressed(e);
base.OnPointerReleased(e);
}
/// <inheritdoc/>

6
src/Avalonia.Controls/Generators/ItemContainerGenerator`1.cs

@ -47,11 +47,7 @@ namespace Avalonia.Controls.Generators
{
var container = item as T;
if (item == null)
{
return null;
}
else if (container != null)
if (container != null)
{
return container;
}

21
src/Avalonia.Controls/Primitives/Popup.cs

@ -128,6 +128,7 @@ namespace Avalonia.Controls.Primitives
public static readonly StyledProperty<bool> TopmostProperty =
AvaloniaProperty.Register<Popup, bool>(nameof(Topmost));
private bool _isOpenRequested = false;
private bool _isOpen;
private bool _ignoreIsOpenChanged;
private PopupOpenState? _openState;
@ -361,17 +362,19 @@ namespace Avalonia.Controls.Primitives
if (placementTarget == null)
{
throw new InvalidOperationException("Popup has no logical parent and PlacementTarget is null");
_isOpenRequested = true;
return;
}
var topLevel = placementTarget.VisualRoot as TopLevel;
if (topLevel == null)
{
throw new InvalidOperationException(
"Attempted to open a popup not attached to a TopLevel");
_isOpenRequested = true;
return;
}
_isOpenRequested = false;
var popupHost = OverlayPopupHost.CreatePopupHost(placementTarget, DependencyResolver);
var handlerCleanup = new CompositeDisposable(5);
@ -492,6 +495,17 @@ namespace Avalonia.Controls.Primitives
return new Size();
}
/// <inheritdoc/>
protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e)
{
base.OnAttachedToVisualTree(e);
if (_isOpenRequested)
{
Open();
}
}
/// <inheritdoc/>
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
@ -552,6 +566,7 @@ namespace Avalonia.Controls.Primitives
private void CloseCore()
{
_isOpenRequested = false;
if (_openState is null)
{
using (BeginIgnoringIsOpen())

4
src/Avalonia.Themes.Default/ComboBox.xaml

@ -26,6 +26,7 @@
<Setter Property="Padding" Value="4" />
<Setter Property="MinHeight" Value="20" />
<Setter Property="PlaceholderForeground" Value="{DynamicResource ThemeForegroundBrush}" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled" />
<Setter Property="Template">
<ControlTemplate>
<Border Name="border"
@ -69,7 +70,8 @@
IsLightDismissEnabled="True">
<Border BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="1">
<ScrollViewer>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

2
src/Avalonia.Themes.Default/MenuItem.xaml

@ -64,7 +64,7 @@
<Border Background="{TemplateBinding Background}"
BorderBrush="{DynamicResource ThemeBorderMidBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

33
src/Avalonia.Themes.Fluent/CheckBox.xaml

@ -1,13 +1,10 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<CheckBox IsThreeState="True" IsChecked="True" />
<CheckBox IsThreeState="True" IsChecked="True" Content="Content" Foreground="Gold" />
</Border>
</Design.PreviewWith>
<Style Selector="CheckBox">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" />
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" />
<Setter Property="Padding" Value="8,0,0,0" />
<Setter Property="HorizontalAlignment" Value="Left" />
<Setter Property="VerticalAlignment" Value="Center" />
@ -21,10 +18,12 @@
<Setter Property="Template">
<ControlTemplate>
<Grid x:Name="RootGrid" ColumnDefinitions="20,*">
<Border x:Name="PART_Border" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}" />
<Border x:Name="PART_Border"
Grid.ColumnSpan="2"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{DynamicResource ControlCornerRadius}" />
<Grid VerticalAlignment="Top" Height="32">
<Border x:Name="NormalRectangle"
@ -55,11 +54,11 @@
</Style>
<!-- Unchecked Normal State -->
<Style Selector="CheckBox /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
<Style Selector="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundUnchecked}" />
</Style>
<Style Selector="CheckBox /template/ Border#PART_Border">
<Style Selector="CheckBox">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundUnchecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushUnchecked}" />
</Style>
@ -133,11 +132,11 @@
<!-- Checked Normal State -->
<Style Selector="CheckBox:checked /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
<Style Selector="CheckBox:checked">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundChecked}" />
</Style>
<Style Selector="CheckBox:checked /template/ Border#PART_Border">
<Style Selector="CheckBox:checked">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundChecked}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushChecked}" />
</Style>
@ -213,11 +212,11 @@
<!-- Indeterminate Normal State -->
<Style Selector="CheckBox:indeterminate /template/ ContentPresenter#ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
<Style Selector="CheckBox:indeterminate">
<Setter Property="Foreground" Value="{DynamicResource CheckBoxForegroundIndeterminate}" />
</Style>
<Style Selector="CheckBox:indeterminate /template/ Border#PART_Border">
<Style Selector="CheckBox:indeterminate">
<Setter Property="Background" Value="{DynamicResource CheckBoxBackgroundIndeterminate}" />
<Setter Property="BorderBrush" Value="{DynamicResource CheckBoxBorderBrushIndeterminate}" />
</Style>

3
src/Avalonia.Themes.Fluent/ComboBox.xaml

@ -133,7 +133,8 @@
Padding="{DynamicResource ComboBoxDropdownBorderPadding}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer HorizontalScrollBarVisibility="{TemplateBinding ScrollViewer.HorizontalScrollBarVisibility}"
VerticalScrollBarVisibility="{TemplateBinding ScrollViewer.VerticalScrollBarVisibility}">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
Margin="{DynamicResource ComboBoxDropdownContentMargin}"

2
src/Avalonia.Themes.Fluent/ContextMenu.xaml

@ -49,7 +49,7 @@
MinHeight="{TemplateBinding MinHeight}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

85
src/Avalonia.Themes.Fluent/ListBoxItem.xaml

@ -1,9 +1,13 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="0">
<ListBox>
<ListBoxItem IsEnabled="False">Disabled</ListBoxItem>
<ListBoxItem>Test</ListBoxItem>
<ListBoxItem Background="#66000000"
Padding="20">
Test
</ListBoxItem>
<ListBoxItem>Test</ListBoxItem>
</ListBox>
</Border>
@ -17,11 +21,7 @@
<Setter Property="HorizontalContentAlignment" Value="Left" />
<Setter Property="Template">
<ControlTemplate>
<Border x:Name="LayoutRoot" Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<Panel>
<Rectangle x:Name="PressedBackground" IsHitTestVisible="False" />
<ContentPresenter Name="PART_ContentPresenter"
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
@ -29,69 +29,66 @@
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Panel>
</Border>
HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" />
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ListBoxItem /template/ ContentPresenter">
<Style Selector="ListBoxItem /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.FontWeight" Value="Normal" />
<Setter Property="TextBlock.FontSize" Value="{DynamicResource ControlContentThemeFontSize}" />
</Style>
<!-- Disabled State -->
<Style Selector="ListBoxItem:disabled /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}"/>
<!-- Disabled State -->
<Style Selector="ListBoxItem:disabled /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlDisabledBaseMediumLowBrush}" />
</Style>
<!-- PointerOver State -->
<Style Selector="ListBoxItem:pointerover /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListLowBrush}"/>
<!-- PointerOver State -->
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListLowBrush}" />
</Style>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Pressed State -->
<Style Selector="ListBoxItem:pressed /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListMediumBrush}"/>
<!-- Pressed State -->
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListMediumBrush}" />
</Style>
<Style Selector="ListBoxItem:pressed /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected State -->
<Style Selector="ListBoxItem:selected /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}"/>
<!-- Selected State -->
<Style Selector="ListBoxItem:selected /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}" />
</Style>
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected Unfocused State -->
<Style Selector="ListBoxItem:selected:not(:focus) /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}"/>
<!-- Selected Unfocused State -->
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentLowBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:selected:not(:focus) /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected PointerOver State -->
<Style Selector="ListBoxItem:selected:pointerover /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentMediumBrush}"/>
<!-- Selected PointerOver State -->
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentMediumBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
<!-- Selected Pressed State -->
<Style Selector="ListBoxItem:selected:pressed /template/ Rectangle#PressedBackground">
<Setter Property="Fill" Value="{DynamicResource SystemControlHighlightListAccentHighBrush}"/>
<!-- Selected Pressed State -->
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="Background" Value="{DynamicResource SystemControlHighlightListAccentHighBrush}" />
</Style>
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}"/>
<Style Selector="ListBoxItem:selected:pressed /template/ ContentPresenter#PART_ContentPresenter">
<Setter Property="TextBlock.Foreground" Value="{DynamicResource SystemControlHighlightAltBaseHighBrush}" />
</Style>
</Styles>

4
src/Avalonia.Themes.Fluent/MenuItem.xaml

@ -123,7 +123,7 @@
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"
@ -171,7 +171,7 @@
MinHeight="{DynamicResource MenuFlyoutThemeMinHeight}"
HorizontalAlignment="Stretch"
CornerRadius="{DynamicResource OverlayCornerRadius}">
<ScrollViewer>
<ScrollViewer Classes="menuscroller">
<ItemsPresenter Name="PART_ItemsPresenter"
Items="{TemplateBinding Items}"
ItemsPanel="{TemplateBinding ItemsPanel}"

92
src/Avalonia.Themes.Fluent/ScrollViewer.xaml

@ -1,5 +1,21 @@
<Styles xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:converters="clr-namespace:Avalonia.Controls.Converters;assembly=Avalonia.Controls">
<Design.PreviewWith>
<Grid ColumnDefinitions="*,20,*"
Height="300"
Width="200"
Margin="20">
<ScrollViewer>
<Border Height="1000" Background="#ccc"/>
</ScrollViewer>
<ScrollViewer Grid.Column="2" Classes="menuscroller">
<Border Height="1000" Background="#ccc"/>
</ScrollViewer>
</Grid>
</Design.PreviewWith>
<Style Selector="ScrollViewer">
<Setter Property="Background"
Value="Transparent" />
@ -66,4 +82,78 @@
<Setter Property="Opacity" Value="1" />
</Style>
<Style Selector="ScrollViewer.menuscroller">
<Setter Property="Template">
<ControlTemplate>
<DockPanel>
<RepeatButton DockPanel.Dock="Top"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
RenderTransform="{x:Null}"
Command="{Binding LineUp, RelativeSource={RelativeSource TemplatedParent}}">
<RepeatButton.IsVisible>
<MultiBinding Converter="{x:Static converters:MenuScrollingVisibilityConverter.Instance}"
ConverterParameter="0">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="VerticalScrollBarVisibility"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Offset.Y"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Extent.Height"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Viewport.Height"/>
</MultiBinding>
</RepeatButton.IsVisible>
<Viewbox Width="{DynamicResource ScrollBarButtonArrowIconFontSize}"
Height="{DynamicResource ScrollBarButtonArrowIconFontSize}">
<Path VerticalAlignment="Center"
HorizontalAlignment="Center"
Data="M 19.091797 14.970703 L 10 5.888672 L 0.908203 14.970703 L 0.029297 14.091797 L 10 4.111328 L 19.970703 14.091797 Z"
Width="20"
Height="20" />
</Viewbox>
</RepeatButton>
<RepeatButton DockPanel.Dock="Bottom"
BorderThickness="0"
Background="Transparent"
HorizontalAlignment="Stretch"
HorizontalContentAlignment="Center"
RenderTransform="{x:Null}"
Command="{Binding LineDown, RelativeSource={RelativeSource TemplatedParent}}">
<RepeatButton.IsVisible>
<MultiBinding Converter="{x:Static converters:MenuScrollingVisibilityConverter.Instance}"
ConverterParameter="100">
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="VerticalScrollBarVisibility"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Offset.Y"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Extent.Height"/>
<Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Viewport.Height"/>
</MultiBinding>
</RepeatButton.IsVisible>
<Viewbox Width="{DynamicResource ScrollBarButtonArrowIconFontSize}"
Height="{DynamicResource ScrollBarButtonArrowIconFontSize}">
<Path VerticalAlignment="Center"
HorizontalAlignment="Center"
Data="M 18.935547 4.560547 L 19.814453 5.439453 L 10 15.253906 L 0.185547 5.439453 L 1.064453 4.560547 L 10 13.496094 Z"
Width="20"
Height="20" />
</Viewbox>
</RepeatButton>
<ScrollContentPresenter Name="PART_ContentPresenter"
CanHorizontallyScroll="{TemplateBinding CanHorizontallyScroll}"
CanVerticallyScroll="{TemplateBinding CanVerticallyScroll}"
Content="{TemplateBinding Content}"
Extent="{TemplateBinding Extent, Mode=TwoWay}"
Margin="{TemplateBinding Padding}"
Offset="{TemplateBinding Offset, Mode=TwoWay}"
Viewport="{TemplateBinding Viewport, Mode=TwoWay}"/>
</DockPanel>
</ControlTemplate>
</Setter>
</Style>
<Style Selector="ScrollViewer.menuscroller /template/ RepeatButton > Viewbox > Path">
<Setter Property="Fill" Value="{DynamicResource ScrollBarButtonArrowForeground}" />
</Style>
<Style Selector="ScrollViewer.menuscroller /template/ RepeatButton:pointerover > Viewbox > Path">
<Setter Property="Fill" Value="{DynamicResource ScrollBarButtonArrowForegroundPointerOver}" />
</Style>
</Styles>

4
tests/Avalonia.Base.UnitTests/Data/Core/Plugins/DataAnnotationsValidationPluginTests.cs

@ -59,12 +59,12 @@ namespace Avalonia.Markup.UnitTests.Data.Plugins
{
new BindingNotification(5),
new BindingNotification(
new ValidationException(errmsg),
new DataValidationException(errmsg),
BindingErrorType.DataValidationError,
3),
new BindingNotification(7),
new BindingNotification(
new ValidationException(errmsg),
new DataValidationException(errmsg),
BindingErrorType.DataValidationError,
11),
}, result);

2
tests/Avalonia.Controls.UnitTests/ComboBoxTests.cs

@ -2,7 +2,6 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Shapes;
using Avalonia.Controls.Templates;
using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.UnitTests;
@ -27,6 +26,7 @@ namespace Avalonia.Controls.UnitTests
Assert.True(target.IsDropDownOpen);
_helper.Down(target);
_helper.Up(target);
Assert.False(target.IsDropDownOpen);
}

10
tests/Avalonia.Controls.UnitTests/Generators/ItemContainerGeneratorTests.cs

@ -144,6 +144,16 @@ namespace Avalonia.Controls.UnitTests.Generators
Assert.Equal("bar", container.Content);
}
[Fact]
public void Materialize_Should_Create_Containers_When_Item_Is_Null()
{
var owner = new Decorator();
var target = new ItemContainerGenerator<ListBoxItem>(owner, ListBoxItem.ContentProperty, null);
var container = (ListBoxItem)target.Materialize(0, null).ContainerControl;
Assert.True(container != null, "The containers is not materialized.");
}
private IList<ItemContainerInfo> Materialize(
IItemContainerGenerator generator,
int index,

45
tests/Avalonia.Controls.UnitTests/Primitives/PopupTests.cs

@ -21,7 +21,50 @@ namespace Avalonia.Controls.UnitTests.Primitives
public class PopupTests
{
protected bool UsePopupHost;
[Fact]
public void Popup_Open_Without_Target_Should_Attach_Itself_Later()
{
using (CreateServices())
{
int openedEvent = 0;
var target = new Popup();
target.Opened += (s, a) => openedEvent++;
target.IsOpen = true;
var window = PreparedWindow(target);
window.Show();
Assert.Equal(1, openedEvent);
}
}
[Fact]
public void Popup_Without_TopLevel_Shouldnt_Call_Open()
{
int openedEvent = 0;
var target = new Popup();
target.Opened += (s, a) => openedEvent++;
target.IsOpen = true;
Assert.Equal(0, openedEvent);
}
[Fact]
public void Opening_Popup_Shouldnt_Throw_When_Not_In_Visual_Tree()
{
var target = new Popup();
target.IsOpen = true;
}
[Fact]
public void Opening_Popup_Shouldnt_Throw_When_In_Tree_Without_TopLevel()
{
Control c = new Control();
var target = new Popup();
((ISetLogicalParent)target).SetParent(c);
target.IsOpen = true;
}
[Fact]
public void Setting_Child_Should_Set_Child_Controls_LogicalParent()
{

50
tests/Avalonia.Visuals.UnitTests/Media/GlyphRunTests.cs

@ -119,6 +119,56 @@ namespace Avalonia.Visuals.UnitTests.Media
}
}
[InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 0)]
[InlineData(new double[] { 10, 10, 10 }, new ushort[] { 0, 0, 0 }, 1)]
[InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 0, 0, 0, 3 }, 0)]
[InlineData(new double[] { 10, 10, 10, 10 }, new ushort[] { 3, 0, 0, 0 }, 1)]
[InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 0, 1, 1, 1, 4 }, 0)]
[InlineData(new double[] { 10, 10, 10, 10, 10 }, new ushort[] { 4, 1, 1, 1, 0 }, 1)]
[Theory]
public void Should_Find_Glyph_Index(double[] advances, ushort[] clusters, int bidiLevel)
{
using (var glyphRun = CreateGlyphRun(advances, clusters, bidiLevel))
{
if (glyphRun.IsLeftToRight)
{
for (var i = 0; i < clusters.Length; i++)
{
var cluster = clusters[i];
var found = glyphRun.FindGlyphIndex(cluster);
var expected = i;
while (expected - 1 >= 0 && clusters[expected - 1] == cluster)
{
expected--;
}
Assert.Equal(expected, found);
}
}
else
{
for (var i = clusters.Length - 1; i > 0; i--)
{
var cluster = clusters[i];
var found = glyphRun.FindGlyphIndex(cluster);
var expected = i;
while (expected + 1 < clusters.Length && clusters[expected + 1] == cluster)
{
expected++;
}
Assert.Equal(expected, found);
}
}
}
}
private static GlyphRun CreateGlyphRun(double[] glyphAdvances, ushort[] glyphClusters, int bidiLevel = 0)
{
var count = glyphAdvances.Length;

Loading…
Cancel
Save