committed by
GitHub
35 changed files with 516 additions and 179 deletions
@ -0,0 +1,7 @@ |
|||
Compat issues with assembly Avalonia.Controls: |
|||
MembersMustExist : Member 'protected void Avalonia.Controls.ComboBox.PopupClosedOverride(Avalonia.Controls.Primitives.PopupClosedEventArgs)' does not exist in the implementation but it does exist in the contract. |
|||
MembersMustExist : Member 'public Avalonia.StyledProperty<System.Boolean> Avalonia.StyledProperty<System.Boolean> Avalonia.Controls.Primitives.Popup.StaysOpenProperty' does not exist in the implementation but it does exist in the contract. |
|||
MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.add_Closed(System.EventHandler<Avalonia.Controls.Primitives.PopupClosedEventArgs>)' does not exist in the implementation but it does exist in the contract. |
|||
MembersMustExist : Member 'public void Avalonia.Controls.Primitives.Popup.remove_Closed(System.EventHandler<Avalonia.Controls.Primitives.PopupClosedEventArgs>)' does not exist in the implementation but it does exist in the contract. |
|||
TypesMustExist : Type 'Avalonia.Controls.Primitives.PopupClosedEventArgs' does not exist in the implementation but it does exist in the contract. |
|||
Total Issues: 5 |
|||
@ -0,0 +1,61 @@ |
|||
using System; |
|||
using System.Linq; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Input; |
|||
using Avalonia.Rendering; |
|||
using Avalonia.Styling; |
|||
using Avalonia.VisualTree; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
/// <summary>
|
|||
/// A layer that is used to dismiss a <see cref="Popup"/> when the user clicks outside.
|
|||
/// </summary>
|
|||
public class LightDismissOverlayLayer : Border, ICustomHitTest |
|||
{ |
|||
public IInputElement? InputPassThroughElement { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Returns the light dismiss overlay for a specified visual.
|
|||
/// </summary>
|
|||
/// <param name="visual">The visual.</param>
|
|||
/// <returns>The light dismiss overlay, or null if none found.</returns>
|
|||
public static LightDismissOverlayLayer? GetLightDismissOverlayLayer(IVisual visual) |
|||
{ |
|||
visual = visual ?? throw new ArgumentNullException(nameof(visual)); |
|||
|
|||
VisualLayerManager? manager; |
|||
|
|||
if (visual is TopLevel topLevel) |
|||
{ |
|||
manager = topLevel.GetTemplateChildren() |
|||
.OfType<VisualLayerManager>() |
|||
.FirstOrDefault(); |
|||
} |
|||
else |
|||
{ |
|||
manager = visual.FindAncestorOfType<VisualLayerManager>(); |
|||
} |
|||
|
|||
return manager?.LightDismissOverlayLayer; |
|||
} |
|||
|
|||
public bool HitTest(Point point) |
|||
{ |
|||
if (InputPassThroughElement is object) |
|||
{ |
|||
var p = point.Transform(this.TransformToVisual(VisualRoot)!.Value); |
|||
var hit = VisualRoot.GetVisualAt(p, x => x != this); |
|||
|
|||
if (hit is object) |
|||
{ |
|||
return !InputPassThroughElement.IsVisualAncestorOf(hit); |
|||
} |
|||
} |
|||
|
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
@ -1,33 +0,0 @@ |
|||
using System; |
|||
using Avalonia.Interactivity; |
|||
|
|||
#nullable enable |
|||
|
|||
namespace Avalonia.Controls.Primitives |
|||
{ |
|||
/// <summary>
|
|||
/// Holds data for the <see cref="Popup.Closed"/> event.
|
|||
/// </summary>
|
|||
public class PopupClosedEventArgs : EventArgs |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PopupClosedEventArgs"/> class.
|
|||
/// </summary>
|
|||
/// <param name="closeEvent"></param>
|
|||
public PopupClosedEventArgs(EventArgs? closeEvent) |
|||
{ |
|||
CloseEvent = closeEvent; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the event that closed the popup, if any.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// If <see cref="Popup.StaysOpen"/> is false, then this property will hold details of the
|
|||
/// interaction that caused the popup to close if the close was caused by e.g. a pointer press
|
|||
/// outside the popup. It can be used to mark the event as handled if the event should not
|
|||
/// be propagated.
|
|||
/// </remarks>
|
|||
public EventArgs? CloseEvent { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,126 @@ |
|||
using System.Linq; |
|||
using Avalonia.Controls.Presenters; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Input; |
|||
using Avalonia.Styling; |
|||
using Avalonia.UnitTests; |
|||
using Avalonia.VisualTree; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Controls.UnitTests |
|||
{ |
|||
public class ListBoxTests_Multiple |
|||
{ |
|||
[Fact] |
|||
public void Focusing_Item_With_Shift_And_Arrow_Key_Should_Add_To_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItem = "Foo"; |
|||
|
|||
target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Shift |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Focusing_Item_With_Ctrl_And_Arrow_Key_Should_Add_To_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItem = "Foo"; |
|||
|
|||
target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Control |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Focusing_Selected_Item_With_Ctrl_And_Arrow_Key_Should_Remove_From_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItems.Add("Foo"); |
|||
target.SelectedItems.Add("Bar"); |
|||
|
|||
target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Control |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
private Control CreateListBoxTemplate(ITemplatedControl parent, INameScope scope) |
|||
{ |
|||
return new ScrollViewer |
|||
{ |
|||
Template = new FuncControlTemplate(CreateScrollViewerTemplate), |
|||
Content = new ItemsPresenter |
|||
{ |
|||
Name = "PART_ItemsPresenter", |
|||
[~ItemsPresenter.ItemsProperty] = parent.GetObservable(ItemsControl.ItemsProperty).ToBinding(), |
|||
}.RegisterInNameScope(scope) |
|||
}; |
|||
} |
|||
|
|||
private Control CreateScrollViewerTemplate(ITemplatedControl parent, INameScope scope) |
|||
{ |
|||
return new ScrollContentPresenter |
|||
{ |
|||
Name = "PART_ContentPresenter", |
|||
[~ContentPresenter.ContentProperty] = |
|||
parent.GetObservable(ContentControl.ContentProperty).ToBinding(), |
|||
}.RegisterInNameScope(scope); |
|||
} |
|||
|
|||
private void ApplyTemplate(ListBox target) |
|||
{ |
|||
// Apply the template to the ListBox itself.
|
|||
target.ApplyTemplate(); |
|||
|
|||
// Then to its inner ScrollViewer.
|
|||
var scrollViewer = (ScrollViewer)target.GetVisualChildren().Single(); |
|||
scrollViewer.ApplyTemplate(); |
|||
|
|||
// Then make the ScrollViewer create its child.
|
|||
((ContentPresenter)scrollViewer.Presenter).UpdateChild(); |
|||
|
|||
// Now the ItemsPresenter should be reigstered, so apply its template.
|
|||
target.Presenter.ApplyTemplate(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue