Skip to content

Commit

Permalink
Merge branch 'master' into release/0.10.2
Browse files Browse the repository at this point in the history
  • Loading branch information
grokys committed Apr 21, 2021
2 parents 9c3537a + 9794354 commit 24510f9
Show file tree
Hide file tree
Showing 5 changed files with 56 additions and 10 deletions.
2 changes: 0 additions & 2 deletions src/Avalonia.Controls/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ public class Control : InputElement, IControl, INamed, IVisualBrushInitialize, I
/// <summary>
/// Defines the <see cref="ContextMenu"/> property.
/// </summary>
[Obsolete("Prefer ContextFlyout")]
public static readonly StyledProperty<ContextMenu?> ContextMenuProperty =
AvaloniaProperty.Register<Control, ContextMenu?>(nameof(ContextMenu));

Expand Down Expand Up @@ -77,7 +76,6 @@ public class Control : InputElement, IControl, INamed, IVisualBrushInitialize, I
/// <summary>
/// Gets or sets a context menu to the control.
/// </summary>
[Obsolete("Prefer ContextFlyout")]
public ContextMenu? ContextMenu
{
get => GetValue(ContextMenuProperty);
Expand Down
34 changes: 28 additions & 6 deletions src/Avalonia.Controls/Selection/InternalSelectionModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -80,10 +80,12 @@ private protected override void SetSource(IEnumerable? value)
try
{
_ignoreSelectedItemsChanges = true;
++_ignoreModelChanges;
base.SetSource(value);
}
finally
{
--_ignoreModelChanges;
_ignoreSelectedItemsChanges = false;
}

Expand All @@ -93,17 +95,14 @@ private protected override void SetSource(IEnumerable? value)
}
else
{
foreach (var i in oldSelection)
{
var index = ItemsView!.IndexOf(i);
Select(index);
}
SyncFromSelectedItems();
}
}

private void SyncToSelectedItems()
{
if (_writableSelectedItems is object)
if (_writableSelectedItems is object &&
!SequenceEqual(_writableSelectedItems, base.SelectedItems))
{
try
{
Expand Down Expand Up @@ -224,6 +223,7 @@ protected override void OnSourceCollectionChangeFinished()
if (_isResetting)
{
--_ignoreModelChanges;
_isResetting = false;
}
}

Expand Down Expand Up @@ -310,5 +310,27 @@ private static int IndexOf(object? source, object? item)

return -1;
}

private static bool SequenceEqual(IList first, IReadOnlyList<object?> second)
{
if (first is IEnumerable<object?> e)
{
return e.SequenceEqual(second);
}

var comparer = EqualityComparer<object?>.Default;
var e1 = first.GetEnumerator();
using var e2 = second.GetEnumerator();

while (e1.MoveNext())
{
if (!(e2.MoveNext() && comparer.Equals(e1.Current, e2.Current)))
{
return false;
}
}

return !e2.MoveNext();
}
}
}
1 change: 0 additions & 1 deletion src/Avalonia.Themes.Default/TextBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
<MenuItem x:Name="TextBoxContextFlyoutPasteItem" Header="Paste" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}"/>
</MenuFlyout>

<!-- ContextMenu obsolete, prefer ContextFlyout -->
<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}"/>
Expand Down
1 change: 0 additions & 1 deletion src/Avalonia.Themes.Fluent/Controls/TextBox.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
<MenuItem x:Name="TextBoxContextFlyoutPasteItem" Header="Paste" Command="{Binding $parent[TextBox].Paste}" IsEnabled="{Binding $parent[TextBox].CanPaste}" InputGesture="{x:Static TextBox.PasteGesture}"/>
</MenuFlyout>

<!-- ContextMenu obsolete, prefer ContextFlyout -->
<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}"/>
Expand Down
28 changes: 28 additions & 0 deletions tests/Avalonia.Controls.UnitTests/ListBoxTests.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Subjects;
using Avalonia.Collections;
Expand Down Expand Up @@ -457,6 +458,33 @@ public void Adding_And_Selecting_Item_With_AutoScrollToSelectedItem_Should_NotHi
}
}

[Fact]
public void Initial_Binding_Of_SelectedItems_Should_Not_Cause_Write_To_SelectedItems()
{
var target = new ListBox
{
[!ListBox.ItemsProperty] = new Binding("Items"),
[!ListBox.SelectedItemsProperty] = new Binding("SelectedItems"),
};

var viewModel = new
{
Items = new[] { "Foo", "Bar", "Baz " },
SelectedItems = new ObservableCollection<string> { "Bar" },
};

var raised = 0;

viewModel.SelectedItems.CollectionChanged += (s, e) => ++raised;

target.DataContext = viewModel;

Assert.Equal(0, raised);
Assert.Equal(new[] { "Bar" }, viewModel.SelectedItems);
Assert.Equal(new[] { "Bar" }, target.SelectedItems);
Assert.Equal(new[] { "Bar" }, target.Selection.SelectedItems);
}

private FuncControlTemplate ListBoxTemplate()
{
return new FuncControlTemplate<ListBox>((parent, scope) =>
Expand Down

0 comments on commit 24510f9

Please sign in to comment.