Browse Source

Merge branch 'master' into fixes/2821-remove-contentcontrolmixin

danwalmsley 6 years ago
parent
commit
365cde4cc0

+ 3 - 1
samples/ControlCatalog/Pages/ListBoxPage.xaml

@@ -10,12 +10,14 @@
               HorizontalAlignment="Center"
               Spacing="16">
       <StackPanel Orientation="Vertical" Spacing="8">
-        <ListBox Items="{Binding Items}" SelectedItems="{Binding SelectedItems}" SelectionMode="{Binding SelectionMode}" Width="250" Height="350"></ListBox>
+        <ListBox Items="{Binding Items}" SelectedItem="{Binding SelectedItem}" AutoScrollToSelectedItem="True"  SelectedItems="{Binding SelectedItems}" SelectionMode="{Binding SelectionMode}" Width="250" Height="350"></ListBox>
 
         <Button Command="{Binding AddItemCommand}">Add</Button>
 
         <Button Command="{Binding RemoveItemCommand}">Remove</Button>
 
+        <Button Command="{Binding SelectRandomItemCommand}">Select Random Item</Button>
+
         <ComboBox SelectedIndex="{Binding SelectionMode, Mode=TwoWay}">
           <ComboBoxItem>Single</ComboBoxItem>
           <ComboBoxItem>Multiple</ComboBoxItem>

+ 20 - 1
samples/ControlCatalog/Pages/ListBoxPage.xaml.cs

@@ -1,3 +1,4 @@
+using System;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Reactive;
@@ -27,7 +28,7 @@ namespace ControlCatalog.Pages
 
             public PageViewModel()
             {
-                Items = new ObservableCollection<string>(Enumerable.Range(1, 10).Select(i => GenerateItem()));
+                Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem()));
                 SelectedItems = new ObservableCollection<string>();
 
                 AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem()));
@@ -39,16 +40,34 @@ namespace ControlCatalog.Pages
                         Items.Remove(SelectedItems[0]);
                     }
                 });
+
+                SelectRandomItemCommand = ReactiveCommand.Create(() =>
+                {
+                    var random = new Random();
+
+                    SelectedItem = Items[random.Next(Items.Count - 1)];
+                });
             }
 
             public ObservableCollection<string> Items { get; }
 
+            private string _selectedItem;
+
+            public string SelectedItem
+            {
+                get { return _selectedItem; }
+                set { this.RaiseAndSetIfChanged(ref _selectedItem, value); }
+            }
+
+
             public ObservableCollection<string> SelectedItems { get; }
 
             public ReactiveCommand<Unit, Unit> AddItemCommand { get; }
 
             public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; }
 
+            public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; }
+
             public SelectionMode SelectionMode
             {
                 get => _selectionMode;

+ 5 - 5
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@@ -855,11 +855,6 @@ namespace Avalonia.Controls.Primitives
                     _selectedItem = ElementAt(Items, _selectedIndex);
                     RaisePropertyChanged(SelectedIndexProperty, -1, _selectedIndex, BindingPriority.LocalValue);
                     RaisePropertyChanged(SelectedItemProperty, null, _selectedItem, BindingPriority.LocalValue);
-
-                    if (AutoScrollToSelectedItem)
-                    {
-                        ScrollIntoView(_selectedIndex);
-                    }
                 }
             }
 
@@ -1046,6 +1041,11 @@ namespace Avalonia.Controls.Primitives
                     removed?.Select(x => ElementAt(Items, x)).ToArray() ?? Array.Empty<object>());
                 RaiseEvent(e);
             }
+
+            if (AutoScrollToSelectedItem)
+            {
+                ScrollIntoView(_selectedItem);
+            }
         }
 
         private void UpdateSelectedItems(Action action)

+ 10 - 2
src/Avalonia.Input/InputElement.cs

@@ -565,9 +565,17 @@ namespace Avalonia.Input
         {
             IsEffectivelyEnabled = IsEnabledCore && (parent?.IsEffectivelyEnabled ?? true);
 
-            foreach (var child in this.GetVisualChildren().OfType<InputElement>())
+            // PERF-SENSITIVE: This is called on entire hierarchy and using foreach or LINQ
+            // will cause extra allocations and overhead.
+            
+            var children = VisualChildren;
+
+            // ReSharper disable once ForCanBeConvertedToForeach
+            for (int i = 0; i < children.Count; ++i)
             {
-                child.UpdateIsEffectivelyEnabled(this);
+                var child = children[i] as InputElement;
+
+                child?.UpdateIsEffectivelyEnabled(this);
             }
         }
     }

+ 27 - 0
tests/Avalonia.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs

@@ -894,6 +894,33 @@ namespace Avalonia.Controls.UnitTests.Primitives
             Assert.Equal("Qux", target.SelectedItem);
         }
 
+        [Fact]
+        public void AutoScrollToSelectedItem_Causes_Scroll_To_SelectedItem()
+        {
+            var items = new ObservableCollection<string>
+            {
+               "Foo",
+               "Bar",
+               "Baz"
+            };
+
+            var target = new ListBox
+            {
+                Template = Template(),
+                Items = items,
+            };
+
+            target.ApplyTemplate();
+            target.Presenter.ApplyTemplate();
+
+            var raised = false;
+            target.AddHandler(Control.RequestBringIntoViewEvent, (s, e) => raised = true);
+
+            target.SelectedIndex = 2;
+
+            Assert.True(raised);
+        }
+
         private FuncControlTemplate Template()
         {
             return new FuncControlTemplate<SelectingItemsControl>((control, scope) =>