Browse Source

Merge branch 'master' into fixes/macCaretPosition

pull/11021/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
a17aa5253f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      .ncrunch/SafeAreaDemo.Android.v3.ncrunchproject
  2. 5
      .ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject
  3. 5
      .ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject
  4. 5
      .ncrunch/SafeAreaDemo.v3.ncrunchproject
  5. 4
      samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs
  6. 2
      samples/ControlCatalog/Pages/ContextFlyoutPage.xaml
  7. 2
      samples/ControlCatalog/Pages/DataGridPage.xaml
  8. 4
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  9. 4
      samples/ControlCatalog/Pages/DialogsPage.xaml
  10. 2
      samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml
  11. 27
      src/Avalonia.Controls.DataGrid/DataGrid.cs
  12. 2
      src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
  13. 4
      src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs
  14. 4
      src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs
  15. 22
      src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs
  16. 36
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs
  17. 26
      src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs
  18. 3
      src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs
  19. 34
      src/Avalonia.Controls/Flyouts/MenuFlyout.cs
  20. 67
      src/Avalonia.Controls/ItemsControl.cs
  21. 2
      src/Avalonia.Controls/ItemsSourceView.cs
  22. 4
      src/Avalonia.Controls/RadioButton.cs
  23. 4
      src/Avalonia.Controls/Templates/FuncControlTemplate.cs
  24. 18
      src/Avalonia.Controls/Templates/IControlTemplate.cs
  25. 2
      src/Avalonia.Controls/Utils/ISelectionAdapter.cs
  26. 2
      src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs
  27. 2
      src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml
  28. 8
      src/Avalonia.Themes.Fluent/Controls/TextBox.xaml
  29. 9
      src/Avalonia.Themes.Simple/Controls/TextBox.xaml
  30. 3
      src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs
  31. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs
  32. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs
  33. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs
  34. 5
      src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs
  35. 2
      src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs
  36. 2
      src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs
  37. 8
      tests/Avalonia.Controls.ItemsRepeater.UnitTests/ItemsRepeaterTests.cs
  38. 10
      tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs
  39. 32
      tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
  40. 2
      tests/Avalonia.Controls.UnitTests/MaskedTextBoxTests.cs
  41. 97
      tests/Avalonia.Controls.UnitTests/MenuItemTests.cs
  42. 2
      tests/Avalonia.Controls.UnitTests/TextBoxTests.cs
  43. 18
      tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs
  44. 2
      tests/Avalonia.LeakTests/ControlTests.cs
  45. 2
      tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs
  46. 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs
  47. 6
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs
  48. 2
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

5
.ncrunch/SafeAreaDemo.Android.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

5
.ncrunch/SafeAreaDemo.Desktop.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

5
.ncrunch/SafeAreaDemo.iOS.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

5
.ncrunch/SafeAreaDemo.v3.ncrunchproject

@ -0,0 +1,5 @@
<ProjectConfiguration>
<Settings>
<IgnoreThisComponentCompletely>True</IgnoreThisComponentCompletely>
</Settings>
</ProjectConfiguration>

4
samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs

@ -114,7 +114,7 @@ namespace ControlCatalog.Pages
foreach (AutoCompleteBox box in GetAllAutoCompleteBox().Where(x => x.Name != "CustomAutocompleteBox"))
{
box.Items = States;
box.ItemsSource = States;
}
var converter = new FuncMultiValueConverter<string, string>(parts =>
@ -132,7 +132,7 @@ namespace ControlCatalog.Pages
asyncBox.AsyncPopulator = PopulateAsync;
var customAutocompleteBox = this.Get<AutoCompleteBox>("CustomAutocompleteBox");
customAutocompleteBox.Items = Sentences.SelectMany(x => x);
customAutocompleteBox.ItemsSource = Sentences.SelectMany(x => x);
customAutocompleteBox.TextFilter = LastWordContains;
customAutocompleteBox.TextSelector = AppendWord;
}

2
samples/ControlCatalog/Pages/ContextFlyoutPage.xaml

@ -67,7 +67,7 @@
</Style>
</Border.Styles>
<Border.ContextFlyout>
<MenuFlyout Items="{Binding MenuItems}" />
<MenuFlyout ItemsSource="{Binding MenuItems}" />
</Border.ContextFlyout>
<TextBlock Text="Dynamically Generated"/>
</Border>

2
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -94,7 +94,7 @@
<Grid RowDefinitions="*,Auto">
<!-- Example of columns inheriting the data type from the Items source -->
<DataGrid Name="dataGridEdit" Margin="12" Grid.Row="0"
Items="{Binding DataGrid3Source}">
ItemsSource="{Binding DataGrid3Source}">
<DataGrid.Columns>
<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}" />

4
samples/ControlCatalog/Pages/DataGridPage.xaml.cs

@ -36,7 +36,7 @@ namespace ControlCatalog.Pages
collectionView1.SortDescriptions.Add(dataGridSortDescription);
}
};
dg1.Items = collectionView1;
dg1.ItemsSource = collectionView1;
var dg2 = this.Get<DataGrid>("dataGridGrouping");
dg2.IsReadOnly = true;
@ -44,7 +44,7 @@ namespace ControlCatalog.Pages
var collectionView2 = new DataGridCollectionView(Countries.All);
collectionView2.GroupDescriptions.Add(new DataGridPathGroupDescription("Region"));
dg2.Items = collectionView2;
dg2.ItemsSource = collectionView2;
var dg3 = this.Get<DataGrid>("dataGridEdit");
dg3.IsReadOnly = false;

4
samples/ControlCatalog/Pages/DialogsPage.xaml

@ -45,7 +45,7 @@
</Expander>
<AutoCompleteBox x:Name="CurrentFolderBox" Watermark="Write full path/uri or well known folder name">
<AutoCompleteBox.Items>
<AutoCompleteBox.ItemsSource>
<generic:List x:TypeArguments="storage:WellKnownFolder">
<storage:WellKnownFolder>Desktop</storage:WellKnownFolder>
<storage:WellKnownFolder>Documents</storage:WellKnownFolder>
@ -54,7 +54,7 @@
<storage:WellKnownFolder>Videos</storage:WellKnownFolder>
<storage:WellKnownFolder>Music</storage:WellKnownFolder>
</generic:List>
</AutoCompleteBox.Items>
</AutoCompleteBox.ItemsSource>
</AutoCompleteBox>
<TextBlock x:Name="PickerLastResultsVisible"

2
samples/ControlCatalog/Pages/ItemsRepeaterPage.xaml

@ -66,7 +66,7 @@
<ScrollViewer Name="scroller"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<ItemsRepeater Name="repeater" Background="Transparent" Items="{Binding Items}"
<ItemsRepeater Name="repeater" Background="Transparent" ItemsSource="{Binding Items}"
ItemTemplate="{StaticResource elementFactory}"/>
</ScrollViewer>
</Border>

27
src/Avalonia.Controls.DataGrid/DataGrid.cs

@ -152,8 +152,6 @@ namespace Avalonia.Controls
private double _verticalOffset;
private byte _verticalScrollChangesIgnored;
private IEnumerable _items;
public event EventHandler<ScrollEventArgs> HorizontalScroll;
public event EventHandler<ScrollEventArgs> VerticalScroll;
@ -652,21 +650,18 @@ namespace Avalonia.Controls
}
/// <summary>
/// Identifies the ItemsSource dependency property.
/// Identifies the ItemsSource property.
/// </summary>
public static readonly DirectProperty<DataGrid, IEnumerable> ItemsProperty =
AvaloniaProperty.RegisterDirect<DataGrid, IEnumerable>(
nameof(Items),
o => o.Items,
(o, v) => o.Items = v);
public static readonly StyledProperty<IEnumerable> ItemsSourceProperty =
AvaloniaProperty.Register<DataGrid, IEnumerable>(nameof(ItemsSource));
/// <summary>
/// Gets or sets a collection that is used to generate the content of the control.
/// </summary>
public IEnumerable Items
public IEnumerable ItemsSource
{
get { return _items; }
set { SetAndRaise(ItemsProperty, ref _items, value); }
get => GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
public static readonly StyledProperty<bool> AreRowDetailsFrozenProperty =
@ -713,7 +708,7 @@ namespace Avalonia.Controls
HorizontalScrollBarVisibilityProperty,
VerticalScrollBarVisibilityProperty);
ItemsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnItemsPropertyChanged(e));
ItemsSourceProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnItemsSourcePropertyChanged(e));
CanUserResizeColumnsProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnCanUserResizeColumnsChanged(e));
ColumnWidthProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnColumnWidthChanged(e));
FrozenColumnCountProperty.Changed.AddClassHandler<DataGrid>((x, e) => x.OnFrozenColumnCountChanged(e));
@ -816,10 +811,10 @@ namespace Avalonia.Controls
}
/// <summary>
/// ItemsProperty property changed handler.
/// ItemsSourceProperty property changed handler.
/// </summary>
/// <param name="e">The event arguments.</param>
private void OnItemsPropertyChanged(AvaloniaPropertyChangedEventArgs e)
private void OnItemsSourcePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
if (!_areHandlersSuspended)
{
@ -830,7 +825,7 @@ namespace Avalonia.Controls
if (LoadingOrUnloadingRow)
{
SetValueNoCallback(ItemsProperty, oldValue);
SetValueNoCallback(ItemsSourceProperty, oldValue);
throw DataGridError.DataGrid.CannotChangeItemsWhenLoadingRows();
}
@ -1855,7 +1850,7 @@ namespace Avalonia.Controls
{
get
{
if (CurrentSlot == -1 || Items == null || RowGroupHeadersTable.Contains(CurrentSlot))
if (CurrentSlot == -1 || ItemsSource == null || RowGroupHeadersTable.Contains(CurrentSlot))
{
return null;
}

2
src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs

@ -25,7 +25,7 @@ namespace Avalonia.Controls
/// </summary>
//TODO Binding
[AssignBinding]
[InheritDataTypeFromItems(nameof(DataGrid.Items), AncestorType = typeof(DataGrid))]
[InheritDataTypeFromItems(nameof(DataGrid.ItemsSource), AncestorType = typeof(DataGrid))]
public virtual IBinding Binding
{
get

4
src/Avalonia.Controls.DataGrid/DataGridDataConnection.cs

@ -122,9 +122,9 @@ namespace Avalonia.Controls
// We need to use the raw ItemsSource as opposed to DataSource because DataSource
// may be the ItemsSource wrapped in a collection view, in which case we wouldn't
// be able to take T to be the type if we're given IEnumerable<T>
if (_dataType == null && _owner.Items != null)
if (_dataType == null && _owner.ItemsSource != null)
{
_dataType = _owner.Items.GetItemType();
_dataType = _owner.ItemsSource.GetItemType();
}
return _dataType;
}

4
src/Avalonia.Controls.DataGrid/DataGridTemplateColumn.cs

@ -24,7 +24,7 @@ namespace Avalonia.Controls
(o, v) => o.CellTemplate = v);
[Content]
[InheritDataTypeFromItems(nameof(DataGrid.Items), AncestorType = typeof(DataGrid))]
[InheritDataTypeFromItems(nameof(DataGrid.ItemsSource), AncestorType = typeof(DataGrid))]
public IDataTemplate CellTemplate
{
get { return _cellTemplate; }
@ -51,7 +51,7 @@ namespace Avalonia.Controls
/// <remarks>
/// If this property is <see langword="null"/> the column is read-only.
/// </remarks>
[InheritDataTypeFromItems(nameof(DataGrid.Items), AncestorType = typeof(DataGrid))]
[InheritDataTypeFromItems(nameof(DataGrid.ItemsSource), AncestorType = typeof(DataGrid))]
public IDataTemplate CellEditingTemplate
{
get => _cellEditingCellTemplate;

22
src/Avalonia.Controls.ItemsRepeater/Controls/ItemsRepeater.cs

@ -36,13 +36,13 @@ namespace Avalonia.Controls
ItemsControl.ItemTemplateProperty.AddOwner<ItemsRepeater>();
/// <summary>
/// Defines the <see cref="Items"/> property.
/// Defines the <see cref="ItemsSource"/> property.
/// </summary>
public static readonly DirectProperty<ItemsRepeater, IEnumerable?> ItemsProperty =
public static readonly DirectProperty<ItemsRepeater, IEnumerable?> ItemsSourceProperty =
AvaloniaProperty.RegisterDirect<ItemsRepeater, IEnumerable?>(
nameof(Items),
o => o.Items,
(o, v) => o.Items = v);
nameof(ItemsSource),
o => o.ItemsSource,
(o, v) => o.ItemsSource = v);
/// <summary>
/// Defines the <see cref="Layout"/> property.
@ -65,7 +65,7 @@ namespace Avalonia.Controls
private readonly ViewManager _viewManager;
private readonly ViewportManager _viewportManager;
private readonly TargetWeakEventSubscriber<ItemsRepeater, EventArgs> _layoutWeakSubscriber;
private IEnumerable? _items;
private IEnumerable? _itemsSource;
private RepeaterLayoutContext? _layoutContext;
private EventHandler<ChildIndexChangedEventArgs>? _childIndexChanged;
private bool _isLayoutInProgress;
@ -116,16 +116,16 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets an object source used to generate the content of the ItemsRepeater.
/// </summary>
public IEnumerable? Items
public IEnumerable? ItemsSource
{
get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value);
get => _itemsSource;
set => SetAndRaise(ItemsSourceProperty, ref _itemsSource, value);
}
/// <summary>
/// Gets or sets the template used to display each item.
/// </summary>
[InheritDataTypeFromItems(nameof(Items))]
[InheritDataTypeFromItems(nameof(ItemsSource))]
public IDataTemplate? ItemTemplate
{
get => GetValue(ItemTemplateProperty);
@ -415,7 +415,7 @@ namespace Avalonia.Controls
/// <inheritdoc />
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
if (change.Property == ItemsProperty)
if (change.Property == ItemsSourceProperty)
{
var (oldEnumerable, newEnumerable) = change.GetOldAndNewValue<IEnumerable?>();

36
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.Properties.cs

@ -143,12 +143,12 @@ namespace Avalonia.Controls
nameof(TextSelector));
/// <summary>
/// Identifies the <see cref="Items" /> property.
/// Identifies the <see cref="ItemsSource" /> property.
/// </summary>
/// <value>The identifier for the <see cref="Items" /> property.</value>
public static readonly StyledProperty<IEnumerable?> ItemsProperty =
/// <value>The identifier for the <see cref="ItemsSource" /> property.</value>
public static readonly StyledProperty<IEnumerable?> ItemsSourceProperty =
AvaloniaProperty.Register<AutoCompleteBox, IEnumerable?>(
nameof(Items));
nameof(ItemsSource));
/// <summary>
/// Identifies the <see cref="AsyncPopulator" /> property.
@ -311,10 +311,10 @@ namespace Avalonia.Controls
/// <summary>
/// Gets the text that is used to filter items in the
/// <see cref="Items" /> item collection.
/// <see cref="ItemsSource" /> item collection.
/// </summary>
/// <value>The text that is used to filter items in the
/// <see cref="Items" /> item collection.</value>
/// <see cref="ItemsSource" /> item collection.</value>
/// <remarks>
/// The SearchText value is typically the same as the
/// Text property, but is set after the TextChanged event occurs
@ -339,7 +339,7 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets how the text in the text box is used to filter items
/// specified by the <see cref="Items" />
/// specified by the <see cref="ItemsSource" />
/// property for display in the drop-down.
/// </summary>
/// <value>One of the <see cref="AutoCompleteFilterMode" />
@ -366,11 +366,11 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the custom method that uses user-entered text to filter
/// the items specified by the <see cref="Items" />
/// the items specified by the <see cref="ItemsSource" />
/// property for display in the drop-down.
/// </summary>
/// <value>The custom method that uses the user-entered text to filter
/// the items specified by the <see cref="Items" />
/// the items specified by the <see cref="ItemsSource" />
/// property. The default is null.</value>
/// <remarks>
/// The filter mode is automatically set to Custom if you set the
@ -384,11 +384,11 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the custom method that uses the user-entered text to
/// filter items specified by the <see cref="Items" />
/// filter items specified by the <see cref="ItemsSource" />
/// property in a text-based way for display in the drop-down.
/// </summary>
/// <value>The custom method that uses the user-entered text to filter
/// items specified by the <see cref="Items" />
/// items specified by the <see cref="ItemsSource" />
/// property in a text-based way for display in the drop-down.</value>
/// <remarks>
/// The search mode is automatically set to Custom if you set the
@ -402,11 +402,11 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the <see cref="Items" />.
/// text and one of the items specified by the <see cref="ItemsSource" />.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the <see cref="Items" />.
/// text and one of the items specified by the <see cref="ItemsSource" />.
/// </value>
public AutoCompleteSelector<object>? ItemSelector
{
@ -417,11 +417,11 @@ namespace Avalonia.Controls
/// <summary>
/// Gets or sets the custom method that combines the user-entered
/// text and one of the items specified by the
/// <see cref="Items" /> in a text-based way.
/// <see cref="ItemsSource" /> in a text-based way.
/// </summary>
/// <value>
/// The custom method that combines the user-entered
/// text and one of the items specified by the <see cref="Items" />
/// text and one of the items specified by the <see cref="ItemsSource" />
/// in a text-based way.
/// </value>
public AutoCompleteSelector<string?>? TextSelector
@ -442,10 +442,10 @@ namespace Avalonia.Controls
/// </summary>
/// <value>The collection that is used to generate the items of the
/// drop-down portion of the <see cref="AutoCompleteBox" /> control.</value>
public IEnumerable? Items
public IEnumerable? ItemsSource
{
get => GetValue(ItemsProperty);
set => SetValue(ItemsProperty, value);
get => GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
}
}

26
src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs

@ -419,9 +419,9 @@ namespace Avalonia.Controls
/// ItemsSourceProperty property changed handler.
/// </summary>
/// <param name="e">Event arguments.</param>
private void OnItemsPropertyChanged(AvaloniaPropertyChangedEventArgs e)
private void OnItemsSourcePropertyChanged(AvaloniaPropertyChangedEventArgs e)
{
OnItemsChanged((IEnumerable?)e.NewValue);
OnItemsSourceChanged((IEnumerable?)e.NewValue);
}
private void OnItemTemplatePropertyChanged(AvaloniaPropertyChangedEventArgs e)
@ -461,7 +461,7 @@ namespace Avalonia.Controls
SearchTextProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnSearchTextPropertyChanged(e));
FilterModeProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnFilterModePropertyChanged(e));
ItemFilterProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemFilterPropertyChanged(e));
ItemsProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemsPropertyChanged(e));
ItemsSourceProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemsSourcePropertyChanged(e));
ItemTemplateProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnItemTemplatePropertyChanged(e));
IsEnabledProperty.Changed.AddClassHandler<AutoCompleteBox>((x,e) => x.OnControlIsEnabledChanged(e));
}
@ -559,7 +559,7 @@ namespace Avalonia.Controls
_adapter.Commit -= OnAdapterSelectionComplete;
_adapter.Cancel -= OnAdapterSelectionCanceled;
_adapter.Cancel -= OnAdapterSelectionComplete;
_adapter.Items = null;
_adapter.ItemsSource = null;
}
_adapter = value;
@ -570,7 +570,7 @@ namespace Avalonia.Controls
_adapter.Commit += OnAdapterSelectionComplete;
_adapter.Cancel += OnAdapterSelectionCanceled;
_adapter.Cancel += OnAdapterSelectionComplete;
_adapter.Items = _view;
_adapter.ItemsSource = _view;
}
}
}
@ -1128,7 +1128,7 @@ namespace Avalonia.Controls
{
if (!cancellationToken.IsCancellationRequested)
{
SetCurrentValue(ItemsProperty, resultList);
SetCurrentValue(ItemsSourceProperty, resultList);
PopulateComplete();
}
});
@ -1475,7 +1475,7 @@ namespace Avalonia.Controls
/// adapter's ItemsSource to the view if appropriate.
/// </summary>
/// <param name="newValue">The new enumerable reference.</param>
private void OnItemsChanged(IEnumerable? newValue)
private void OnItemsSourceChanged(IEnumerable? newValue)
{
// Remove handler for oldValue.CollectionChanged (if present)
_collectionChangeSubscription?.Dispose();
@ -1492,9 +1492,9 @@ namespace Avalonia.Controls
// Clear and set the view on the selection adapter
ClearView();
if (SelectionAdapter != null && SelectionAdapter.Items != _view)
if (SelectionAdapter != null && SelectionAdapter.ItemsSource != _view)
{
SelectionAdapter.Items = _view;
SelectionAdapter.ItemsSource = _view;
}
if (IsDropDownOpen)
{
@ -1545,9 +1545,9 @@ namespace Avalonia.Controls
{
// Significant changes to the underlying data.
ClearView();
if (Items != null)
if (ItemsSource != null)
{
_items = new List<object>(Items.Cast<object>());
_items = new List<object>(ItemsSource.Cast<object>());
}
}
@ -1582,9 +1582,9 @@ namespace Avalonia.Controls
PopulatedEventArgs populated = new PopulatedEventArgs(new ReadOnlyCollection<object>(_view!));
OnPopulated(populated);
if (SelectionAdapter != null && SelectionAdapter.Items != _view)
if (SelectionAdapter != null && SelectionAdapter.ItemsSource != _view)
{
SelectionAdapter.Items = _view;
SelectionAdapter.ItemsSource = _view;
}
bool isDropDownOpen = _userCalledPopulate && (_view!.Count > 0);

3
src/Avalonia.Controls/CalendarDatePicker/CalendarDatePicker.cs

@ -875,10 +875,11 @@ namespace Avalonia.Controls
{
if (_textBox != null)
{
SetCurrentValue(TextProperty, String.Empty);
if (string.IsNullOrEmpty(Watermark) && !UseFloatingWatermark)
{
DateTimeFormatInfo dtfi = DateTimeHelper.GetCurrentDateFormat();
SetCurrentValue(TextProperty, string.Empty);
_defaultText = string.Empty;
var watermarkFormat = "<{0}>";
string watermarkText;

34
src/Avalonia.Controls/Flyouts/MenuFlyout.cs

@ -1,6 +1,5 @@
using System.Collections;
using System.ComponentModel;
using Avalonia.Collections;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Metadata;
@ -12,17 +11,15 @@ namespace Avalonia.Controls
{
public MenuFlyout()
{
_items = new AvaloniaList<object>();
Items = new ItemCollection();
}
/// <summary>
/// Defines the <see cref="Items"/> property
/// Defines the <see cref="ItemsSource"/> property
/// </summary>
public static readonly DirectProperty<MenuFlyout, IEnumerable?> ItemsProperty =
AvaloniaProperty.RegisterDirect<MenuFlyout, IEnumerable?>(
nameof(Items),
x => x.Items,
(x, v) => x.Items = v);
public static readonly StyledProperty<IEnumerable?> ItemsSourceProperty =
AvaloniaProperty.Register<MenuFlyout, IEnumerable?>(
nameof(ItemsSource));
/// <summary>
/// Defines the <see cref="ItemTemplate"/> property
@ -45,14 +42,16 @@ namespace Avalonia.Controls
public Classes FlyoutPresenterClasses => _classes ??= new Classes();
[Content]
public ItemCollection Items { get; }
/// <summary>
/// Gets or sets the items of the MenuFlyout
/// </summary>
[Content]
public IEnumerable? Items
public IEnumerable? ItemsSource
{
get => _items;
set => SetAndRaise(ItemsProperty, ref _items, value);
get => GetValue(ItemsSourceProperty);
set => SetValue(ItemsSourceProperty, value);
}
/// <summary>
@ -83,14 +82,13 @@ namespace Avalonia.Controls
}
private Classes? _classes;
private IEnumerable? _items;
private IDataTemplate? _itemTemplate;
protected override Control CreatePresenter()
{
return new MenuFlyoutPresenter
{
[!ItemsControl.ItemsSourceProperty] = this[!ItemsProperty],
ItemsSource = Items,
[!ItemsControl.ItemTemplateProperty] = this[!ItemTemplateProperty],
[!ItemsControl.ItemContainerThemeProperty] = this[!ItemContainerThemeProperty],
};
@ -113,5 +111,13 @@ namespace Avalonia.Controls
base.OnOpening(args);
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (change.Property == ItemsSourceProperty)
Items.SetItemsSource(change.GetNewValue<IEnumerable?>());
}
}
}

67
src/Avalonia.Controls/ItemsControl.cs

@ -378,48 +378,48 @@ namespace Avalonia.Controls
if (container is HeaderedContentControl hcc)
{
hcc.Content = item;
SetIfUnset(hcc, HeaderedContentControl.ContentProperty, item);
if (item is IHeadered headered)
hcc.Header = headered.Header;
SetIfUnset(hcc, HeaderedContentControl.HeaderProperty, headered.Header);
else if (item is not Visual)
hcc.Header = item;
SetIfUnset(hcc, HeaderedContentControl.HeaderProperty, item);
if (itemTemplate is not null)
hcc.HeaderTemplate = itemTemplate;
SetIfUnset(hcc, HeaderedContentControl.HeaderTemplateProperty, itemTemplate);
}
else if (container is ContentControl cc)
{
cc.Content = item;
SetIfUnset(cc, ContentControl.ContentProperty, item);
if (itemTemplate is not null)
cc.ContentTemplate = itemTemplate;
SetIfUnset(cc, ContentControl.ContentTemplateProperty, itemTemplate);
}
else if (container is ContentPresenter p)
{
p.Content = item;
SetIfUnset(p, ContentPresenter.ContentProperty, item);
if (itemTemplate is not null)
p.ContentTemplate = itemTemplate;
SetIfUnset(p, ContentPresenter.ContentTemplateProperty, itemTemplate);
}
else if (container is ItemsControl ic)
{
if (itemTemplate is not null)
ic.ItemTemplate = itemTemplate;
if (ItemContainerTheme is { } ict && !ict.IsSet(ItemContainerThemeProperty))
ic.ItemContainerTheme = ict;
SetIfUnset(ic, ItemTemplateProperty, itemTemplate);
if (ItemContainerTheme is { } ict)
SetIfUnset(ic, ItemContainerThemeProperty, ict);
}
// These conditions are separate because HeaderedItemsControl and
// HeaderedSelectingItemsControl also need to run the ItemsControl preparation.
if (container is HeaderedItemsControl hic)
{
hic.Header = item;
hic.HeaderTemplate = itemTemplate;
SetIfUnset(hic, HeaderedItemsControl.HeaderProperty, item);
SetIfUnset(hic, HeaderedItemsControl.HeaderTemplateProperty, itemTemplate);
hic.PrepareItemContainer(this);
}
else if (container is HeaderedSelectingItemsControl hsic)
{
hsic.Header = item;
hsic.HeaderTemplate = itemTemplate;
SetIfUnset(hsic, HeaderedSelectingItemsControl.HeaderProperty, item);
SetIfUnset(hsic, HeaderedSelectingItemsControl.HeaderTemplateProperty, itemTemplate);
hsic.PrepareItemContainer(this);
}
}
@ -458,30 +458,35 @@ namespace Avalonia.Controls
{
if (container is HeaderedContentControl hcc)
{
if (hcc.Content is Control)
hcc.Content = null;
if (hcc.Header is Control)
hcc.Header = null;
hcc.ClearValue(HeaderedContentControl.ContentProperty);
hcc.ClearValue(HeaderedContentControl.HeaderProperty);
hcc.ClearValue(HeaderedContentControl.HeaderTemplateProperty);
}
else if (container is ContentControl cc)
{
if (cc.Content is Control)
cc.Content = null;
cc.ClearValue(ContentControl.ContentProperty);
cc.ClearValue(ContentControl.ContentTemplateProperty);
}
else if (container is ContentPresenter p)
{
if (p.Content is Control)
p.Content = null;
p.ClearValue(ContentPresenter.ContentProperty);
p.ClearValue(ContentPresenter.ContentTemplateProperty);
}
else if (container is HeaderedItemsControl hic)
else if (container is ItemsControl ic)
{
ic.ClearValue(ItemTemplateProperty);
ic.ClearValue(ItemContainerThemeProperty);
}
if (container is HeaderedItemsControl hic)
{
if (hic.Header is Control)
hic.Header = null;
hic.ClearValue(HeaderedItemsControl.HeaderProperty);
hic.ClearValue(HeaderedItemsControl.HeaderTemplateProperty);
}
else if (container is HeaderedSelectingItemsControl hsic)
{
if (hsic.Header is Control)
hsic.Header = null;
hsic.ClearValue(HeaderedSelectingItemsControl.HeaderProperty);
hsic.ClearValue(HeaderedSelectingItemsControl.HeaderTemplateProperty);
}
// Feels like we should be clearing the HeaderedItemsControl.Items binding here, but looking at
@ -707,6 +712,12 @@ namespace Avalonia.Controls
LogicalChildren.AddRange(toAdd);
}
private void SetIfUnset<T>(AvaloniaObject target, StyledProperty<T> property, T value)
{
if (!target.IsSet(property))
target.SetCurrentValue(property, value);
}
private void RemoveControlItemsFromLogicalChildren(IEnumerable? items)
{
if (items is null)

2
src/Avalonia.Controls/ItemsSourceView.cs

@ -262,7 +262,7 @@ namespace Avalonia.Controls
_source = source switch
{
ItemsSourceView => throw new ArgumentException("Cannot wrap an existing ItemsSourceView.", nameof(source)),
ItemsSourceView isv => isv.Source,
IList list => list,
INotifyCollectionChanged => throw new ArgumentException(
"Collection implements INotifyCollectionChanged but not IList.",

4
src/Avalonia.Controls/RadioButton.cs

@ -86,7 +86,7 @@ namespace Avalonia.Controls
continue;
}
if (current != radioButton && current.IsChecked.GetValueOrDefault())
current.IsChecked = false;
current.SetCurrentValue(IsCheckedProperty, false);
i++;
}
if (group.Count == 0)
@ -193,7 +193,7 @@ namespace Avalonia.Controls
foreach (var sibling in siblings)
{
if (sibling.IsChecked.GetValueOrDefault())
sibling.IsChecked = false;
sibling.SetCurrentValue(IsCheckedProperty, false);
}
}
}

4
src/Avalonia.Controls/Templates/FuncControlTemplate.cs

@ -18,10 +18,10 @@ namespace Avalonia.Controls.Templates
{
}
public new ControlTemplateResult Build(TemplatedControl param)
public new TemplateResult<Control> Build(TemplatedControl param)
{
var (control, scope) = BuildWithNameScope(param);
return new ControlTemplateResult(control, scope);
return new(control, scope);
}
}
}

18
src/Avalonia.Controls/Templates/IControlTemplate.cs

@ -5,23 +5,7 @@ namespace Avalonia.Controls.Templates
/// <summary>
/// Interface representing a template used to build a <see cref="TemplatedControl"/>.
/// </summary>
public interface IControlTemplate : ITemplate<TemplatedControl, ControlTemplateResult?>
public interface IControlTemplate : ITemplate<TemplatedControl, TemplateResult<Control>?>
{
}
public class ControlTemplateResult : TemplateResult<Control>
{
public Control Control { get; }
public ControlTemplateResult(Control control, INameScope nameScope) : base(control, nameScope)
{
Control = control;
}
public new void Deconstruct(out Control control, out INameScope scope)
{
control = Control;
scope = NameScope;
}
}
}

2
src/Avalonia.Controls/Utils/ISelectionAdapter.cs

@ -36,7 +36,7 @@ namespace Avalonia.Controls.Utils
/// </summary>
/// <value>The collection that is used to generate content for the
/// selection adapter.</value>
IEnumerable? Items { get; set; }
IEnumerable? ItemsSource { get; set; }
/// <summary>
/// Occurs when a selected item is not cancelled and is committed as the

2
src/Avalonia.Controls/Utils/SelectingItemsControlSelectionAdapter.cs

@ -140,7 +140,7 @@ namespace Avalonia.Controls.Utils
/// </summary>
/// <value>The collection used to generate content for the selection
/// adapter.</value>
public IEnumerable? Items
public IEnumerable? ItemsSource
{
get
{

2
src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml

@ -51,7 +51,7 @@
<DataGrid
x:Name="DataGrid"
Items="{Binding PropertiesView}"
ItemsSource="{Binding PropertiesView}"
Grid.Row="2"
BorderThickness="0"
RowBackground="Transparent"

8
src/Avalonia.Themes.Fluent/Controls/TextBox.xaml

@ -1,4 +1,4 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui"
<ResourceDictionary xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
@ -26,12 +26,6 @@
<MenuItem x:Name="TextBoxContextFlyoutPasteItem" Header="Paste" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}"/>
</MenuFlyout>
<ContextMenu x:Key="DefaultTextBoxContextMenu" x:Name="TextBoxContextMenu">
<MenuItem x:Name="TextBoxContextMenuCutItem" Header="Cut" Command="{Binding $parent[TextBox].Cut}" IsEnabled="{Binding $parent[TextBox].CanCut}" InputGesture="{x:Static TextBox.CutGesture}" />
<MenuItem x:Name="TextBoxContextMenuCopyItem" Header="Copy" Command="{Binding $parent[TextBox].Copy}" IsEnabled="{Binding $parent[TextBox].CanCopy}" InputGesture="{x:Static TextBox.CopyGesture}"/>
<MenuItem x:Name="TextBoxContextMenuPasteItem" Header="Paste" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}"/>
</ContextMenu>
<ControlTheme x:Key="FluentTextBoxButton" TargetType="Button">
<Setter Property="Background" Value="{DynamicResource TextControlButtonBackground}" />
<Setter Property="BorderBrush" Value="{DynamicResource TextControlButtonBorderBrush}" />

9
src/Avalonia.Themes.Simple/Controls/TextBox.xaml

@ -13,15 +13,6 @@
IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}" />
</MenuFlyout>
<ContextMenu x:Key="SimpleTextBoxContextMenu" x:Name="TextBoxContextMenu">
<MenuItem x:Name="TextBoxContextMenuCutItem" Header="Cut" Command="{Binding $parent[TextBox].Cut}"
IsEnabled="{Binding $parent[TextBox].CanCut}" InputGesture="{x:Static TextBox.CutGesture}" />
<MenuItem x:Name="TextBoxContextMenuCopyItem" Header="Copy" Command="{Binding $parent[TextBox].Copy}"
IsEnabled="{Binding $parent[TextBox].CanCopy}" InputGesture="{x:Static TextBox.CopyGesture}" />
<MenuItem x:Name="TextBoxContextMenuPasteItem" Header="Paste" Command="{Binding $parent[TextBox].Paste}"
IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}" />
</ContextMenu>
<ControlTheme x:Key="SimpleTextBoxClearButtonTheme"
BasedOn="{StaticResource {x:Type Button}}"
TargetType="Button">

3
src/Markup/Avalonia.Markup.Xaml/Templates/ControlTemplate.cs

@ -1,4 +1,5 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Metadata;
@ -13,6 +14,6 @@ namespace Avalonia.Markup.Xaml.Templates
public Type? TargetType { get; set; }
public ControlTemplateResult? Build(TemplatedControl control) => TemplateContent.Load(Content);
public TemplateResult<Control>? Build(TemplatedControl control) => TemplateContent.Load(Content);
}
}

2
src/Markup/Avalonia.Markup.Xaml/Templates/DataTemplate.cs

@ -30,7 +30,7 @@ namespace Avalonia.Markup.Xaml.Templates
public Control? Build(object? data, Control? existing)
{
return existing ?? TemplateContent.Load(Content)?.Control;
return existing ?? TemplateContent.Load(Content)?.Result;
}
}
}

2
src/Markup/Avalonia.Markup.Xaml/Templates/ItemsPanelTemplate.cs

@ -10,7 +10,7 @@ namespace Avalonia.Markup.Xaml.Templates
[TemplateContent]
public object? Content { get; set; }
public Panel? Build() => (Panel?)TemplateContent.Load(Content)?.Control;
public Panel? Build() => (Panel?)TemplateContent.Load(Content)?.Result;
object? ITemplate.Build() => Build();
}

2
src/Markup/Avalonia.Markup.Xaml/Templates/Template.cs

@ -10,7 +10,7 @@ namespace Avalonia.Markup.Xaml.Templates
[TemplateContent]
public object? Content { get; set; }
public Control? Build() => TemplateContent.Load(Content)?.Control;
public Control? Build() => TemplateContent.Load(Content)?.Result;
object? ITemplate.Build() => Build();
}

5
src/Markup/Avalonia.Markup.Xaml/Templates/TemplateContent.cs

@ -1,15 +1,16 @@
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
namespace Avalonia.Markup.Xaml.Templates
{
public static class TemplateContent
{
public static ControlTemplateResult? Load(object? templateContent)
public static TemplateResult<Control>? Load(object? templateContent)
{
if (templateContent is Func<IServiceProvider?, object?> direct)
{
return (ControlTemplateResult?)direct(null);
return (TemplateResult<Control>?)direct(null);
}
if (templateContent is null)

2
src/Markup/Avalonia.Markup.Xaml/Templates/TreeDataTemplate.cs

@ -54,7 +54,7 @@ namespace Avalonia.Markup.Xaml.Templates
public Control? Build(object? data)
{
var visualTreeForItem = TemplateContent.Load(Content)?.Control;
var visualTreeForItem = TemplateContent.Load(Content)?.Result;
if (visualTreeForItem != null)
{
visualTreeForItem.DataContext = data;

2
src/Markup/Avalonia.Markup.Xaml/XamlIl/Runtime/XamlIlRuntimeHelpers.cs

@ -35,7 +35,7 @@ namespace Avalonia.Markup.Xaml.XamlIl.Runtime
scope.Complete();
if(typeof(T) == typeof(Control))
return new ControlTemplateResult((Control)obj, scope);
return new TemplateResult<Control>((Control)obj, scope);
return new TemplateResult<T>((T)obj, scope);
};

8
tests/Avalonia.Controls.ItemsRepeater.UnitTests/ItemsRepeaterTests.cs

@ -9,16 +9,16 @@ namespace Avalonia.Controls.UnitTests
public void Can_Reassign_Items()
{
var target = new ItemsRepeater();
target.Items = new ObservableCollection<string>();
target.Items = new ObservableCollection<string>();
target.ItemsSource = new ObservableCollection<string>();
target.ItemsSource = new ObservableCollection<string>();
}
[Fact]
public void Can_Reassign_Items_To_Null()
{
var target = new ItemsRepeater();
target.Items = new ObservableCollection<string>();
target.Items = null;
target.ItemsSource = new ObservableCollection<string>();
target.ItemsSource = null;
}
}
}

10
tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs

@ -89,7 +89,7 @@ namespace Avalonia.Controls.UnitTests
bool closeEvent = false;
control.DropDownOpened += (s, e) => openEvent = true;
control.DropDownClosed += (s, e) => closeEvent = true;
control.Items = CreateSimpleStringArray();
control.ItemsSource = CreateSimpleStringArray();
textbox.Text = "a";
Dispatcher.UIThread.RunJobs();
@ -258,7 +258,7 @@ namespace Avalonia.Controls.UnitTests
control.FilterMode = AutoCompleteFilterMode.None;
control.Populating += (s, e) =>
{
control.Items = new string[] { custom };
control.ItemsSource = new string[] { custom };
Assert.Equal(search, e.Parameter);
};
control.Populated += (s, e) =>
@ -380,7 +380,7 @@ namespace Avalonia.Controls.UnitTests
{
RunTest((control, textbox) =>
{
object selectedItem = control.Items.Cast<object>().First();
object selectedItem = control.ItemsSource.Cast<object>().First();
string input = "42";
control.TextSelector = (text, item) => text + item;
@ -397,7 +397,7 @@ namespace Avalonia.Controls.UnitTests
{
RunTest((control, textbox) =>
{
object selectedItem = control.Items.Cast<object>().First();
object selectedItem = control.ItemsSource.Cast<object>().First();
string input = "42";
control.ItemSelector = (text, item) => text + item;
@ -1053,7 +1053,7 @@ namespace Avalonia.Controls.UnitTests
using (UnitTestApplication.Start(Services))
{
AutoCompleteBox control = CreateControl();
control.Items = CreateSimpleStringArray();
control.ItemsSource = CreateSimpleStringArray();
TextBox textBox = GetTextBox(control);
var window = new Window {Content = control};
window.ApplyStyling();

32
tests/Avalonia.Controls.UnitTests/ListBoxTests.cs

@ -554,6 +554,36 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(new[] { "Bar" }, target.Selection.SelectedItems);
}
[Fact]
public void Content_Can_Be_Bound_In_ItemContainerTheme()
{
using (UnitTestApplication.Start(TestServices.MockPlatformRenderInterface))
{
var items = new[] { new ItemViewModel("Foo"), new ItemViewModel("Bar") };
var theme = new ControlTheme(typeof(ListBoxItem))
{
Setters =
{
new Setter(ListBoxItem.ContentProperty, new Binding("Caption")),
}
};
var target = new ListBox
{
Template = ListBoxTemplate(),
ItemsSource = items,
ItemContainerTheme = theme,
};
Prepare(target);
var containers = target.GetRealizedContainers().Cast<ListBoxItem>().ToList();
Assert.Equal(2, containers.Count);
Assert.Equal("Foo", containers[0].Content);
Assert.Equal("Bar", containers[1].Content);
}
}
private static FuncControlTemplate ListBoxTemplate()
{
return new FuncControlTemplate<ListBox>((parent, scope) =>
@ -918,6 +948,8 @@ namespace Avalonia.Controls.UnitTests
Assert.Equal(1, raised);
}
private record ItemViewModel(string Caption);
private class ResettingCollection : List<string>, INotifyCollectionChanged
{
public ResettingCollection(int itemCount)

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

@ -72,7 +72,7 @@ namespace Avalonia.Controls.UnitTests
Text = "1234",
ContextFlyout = new MenuFlyout
{
Items = new List<MenuItem>
Items =
{
new MenuItem { Header = "Item 1" },
new MenuItem {Header = "Item 2" },

97
tests/Avalonia.Controls.UnitTests/MenuItemTests.cs

@ -1,16 +1,16 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Windows.Input;
using Avalonia.Collections;
using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils;
using Avalonia.Data;
using Avalonia.Input;
using Avalonia.Platform;
using Avalonia.Styling;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using Moq;
using Xunit;
@ -36,7 +36,6 @@ namespace Avalonia.Controls.UnitTests
Assert.False(target.Focusable);
}
[Fact]
public void MenuItem_Is_Disabled_When_Command_Is_Enabled_But_IsEnabled_Is_False()
{
@ -232,7 +231,7 @@ namespace Avalonia.Controls.UnitTests
return true;
});
var target = new MenuItem();
var flyout = new MenuFlyout { Items = new AvaloniaList<MenuItem> { target } };
var flyout = new MenuFlyout { Items = { target } };
var button = new Button { Flyout = flyout };
var window = new Window { Content = button };
window.ApplyStyling();
@ -393,6 +392,87 @@ namespace Avalonia.Controls.UnitTests
}
}
[Fact]
public void Header_And_ItemsSource_Can_Be_Bound_In_Style()
{
using var app = Application();
var items = new[]
{
new MenuViewModel("Foo")
{
Children = new[]
{
new MenuViewModel("FooChild"),
},
},
new MenuViewModel("Bar"),
};
var target = new Menu
{
ItemsSource = items,
Styles =
{
new Style(x => x.OfType<MenuItem>())
{
Setters =
{
new Setter(MenuItem.HeaderProperty, new Binding("Header")),
new Setter(MenuItem.ItemsSourceProperty, new Binding("Children")),
}
}
}
};
var root = new TestRoot(true, target);
root.LayoutManager.ExecuteInitialLayoutPass();
var children = target.GetRealizedContainers().Cast<MenuItem>().ToList();
Assert.Equal(2, children.Count);
Assert.Equal("Foo", children[0].Header);
Assert.Equal("Bar", children[1].Header);
Assert.Same(items[0].Children, children[0].ItemsSource);
}
[Fact]
public void Header_And_ItemsSource_Can_Be_Bound_In_ItemContainerTheme()
{
using var app = Application();
var items = new[]
{
new MenuViewModel("Foo")
{
Children = new[]
{
new MenuViewModel("FooChild"),
},
},
new MenuViewModel("Bar"),
};
var target = new Menu
{
ItemsSource = items,
ItemContainerTheme = new ControlTheme(typeof(MenuItem))
{
Setters =
{
new Setter(MenuItem.HeaderProperty, new Binding("Header")),
new Setter(MenuItem.ItemsSourceProperty, new Binding("Children")),
}
}
};
var root = new TestRoot(true, target);
root.LayoutManager.ExecuteInitialLayoutPass();
var children = target.GetRealizedContainers().Cast<MenuItem>().ToList();
Assert.Equal(2, children.Count);
Assert.Equal("Foo", children[0].Header);
Assert.Equal("Bar", children[1].Header);
Assert.Same(items[0].Children, children[0].ItemsSource);
}
private IDisposable Application()
{
var screen = new PixelRect(new PixelPoint(), new PixelSize(100, 100));
@ -447,6 +527,9 @@ namespace Avalonia.Controls.UnitTests
public void RaiseCanExecuteChanged() => _canExecuteChanged?.Invoke(this, EventArgs.Empty);
}
private record MenuViewModel(string Header);
private record MenuViewModel(string Header)
{
public IList<MenuViewModel> Children { get; set;}
}
}
}

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

@ -93,7 +93,7 @@ namespace Avalonia.Controls.UnitTests
Text = "1234",
ContextFlyout = new MenuFlyout
{
Items = new List<MenuItem>
Items =
{
new MenuItem { Header = "Item 1" },
new MenuItem {Header = "Item 2" },

18
tests/Avalonia.IntegrationTests.Appium/NativeMenuTests.cs

@ -18,7 +18,7 @@ namespace Avalonia.IntegrationTests.Appium
}
[PlatformFact(TestPlatforms.MacOS)]
public void View_Menu_Select_Button_Tab()
public void MacOS_View_Menu_Select_Button_Tab()
{
var tabs = _session.FindElementByAccessibilityId("MainTabs");
var buttonTab = tabs.FindElementByName("Button");
@ -33,5 +33,21 @@ namespace Avalonia.IntegrationTests.Appium
Assert.True(buttonTab.Selected);
}
[PlatformFact(TestPlatforms.Windows)]
public void Win32_View_Menu_Select_Button_Tab()
{
var tabs = _session.FindElementByAccessibilityId("MainTabs");
var buttonTab = tabs.FindElementByName("Button");
var viewMenu = _session.FindElementByXPath("//MenuItem[@Name='View']");
Assert.False(buttonTab.Selected);
viewMenu.Click();
var buttonMenu = viewMenu.FindElementByName("Button");
buttonMenu.Click();
Assert.True(buttonTab.Selected);
}
}
}

2
tests/Avalonia.LeakTests/ControlTests.cs

@ -51,7 +51,7 @@ namespace Avalonia.LeakTests
{
Content = new DataGrid
{
Items = _observableCollection
ItemsSource = _observableCollection
}
};

2
tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/CompiledBindingExtensionTests.cs

@ -1978,7 +1978,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions
public bool Match(object data) => FancyDataType?.IsInstanceOfType(data) ?? true;
public Control Build(object data) => TemplateContent.Load(Content)?.Control;
public Control Build(object data) => TemplateContent.Load(Content)?.Result;
}
public class CustomDataTemplateInherit : CustomDataTemplate { }

2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/BasicTests.cs

@ -605,7 +605,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
var control = new ContentControl();
var result = (ContentPresenter)template.Build(control).Control;
var result = (ContentPresenter)template.Build(control).Result;
Assert.NotNull(result);
}

6
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ControlTemplateTests.cs

@ -258,7 +258,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
";
var template = AvaloniaRuntimeXamlLoader.Parse<ControlTemplate>(xaml);
var parent = (ContentControl)template.Build(new ContentControl()).Control;
var parent = (ContentControl)template.Build(new ContentControl()).Result;
Assert.Equal("parent", parent.Name);
@ -283,7 +283,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
Assert.Equal(typeof(ContentControl), template.TargetType);
Assert.IsType(typeof(ContentPresenter), template.Build(new ContentControl()).Control);
Assert.IsType(typeof(ContentPresenter), template.Build(new ContentControl()).Result);
}
[Fact]
@ -299,7 +299,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
";
var template = AvaloniaRuntimeXamlLoader.Parse<ControlTemplate>(xaml);
var panel = (Panel)template.Build(new ContentControl()).Control;
var panel = (Panel)template.Build(new ContentControl()).Result;
Assert.Equal(2, panel.Children.Count);

2
tests/Avalonia.Markup.Xaml.UnitTests/Xaml/StyleTests.cs

@ -424,7 +424,7 @@ namespace Avalonia.Markup.Xaml.UnitTests.Xaml
};
var list = window.FindControl<ItemsRepeater>("list");
list.Items = collection;
list.ItemsSource = collection;
window.Show();

Loading…
Cancel
Save