Browse Source

Merge branch 'master' into fixes/1286-panel-logicalchildren

pull/1301/head
Steven Kirk 9 years ago
committed by GitHub
parent
commit
74e805466b
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/Avalonia.Controls/Calendar/Calendar.cs
  2. 1
      src/Avalonia.Controls/Control.cs
  3. 33
      src/Avalonia.Controls/DropDown.cs
  4. 11
      src/Avalonia.Controls/ItemsControl.cs
  5. 2
      src/Avalonia.Controls/Primitives/SelectingItemsControl.cs
  6. 5
      src/Avalonia.Controls/TreeView.cs
  7. 8
      src/Avalonia.Controls/VirtualizingStackPanel.cs
  8. 2
      src/Avalonia.Visuals/Media/PathMarkupParser.cs
  9. 2
      src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs
  10. 32
      src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs
  11. 2
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs
  12. 10
      src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs
  13. 1
      src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs
  14. 23
      tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs
  15. 32
      tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs

2
src/Avalonia.Controls/Calendar/Calendar.cs

@ -549,7 +549,7 @@ namespace Avalonia.Controls
} }
else else
{ {
if (addedDate.HasValue && !(SelectedDates.Count > 0 && SelectedDates[0] == addedDate.Value)) if (!(SelectedDates.Count > 0 && SelectedDates[0] == addedDate.Value))
{ {
foreach (DateTime item in SelectedDates) foreach (DateTime item in SelectedDates)
{ {

1
src/Avalonia.Controls/Control.cs

@ -621,7 +621,6 @@ namespace Avalonia.Controls
Contract.Requires<ArgumentNullException>(property != null); Contract.Requires<ArgumentNullException>(property != null);
Contract.Requires<ArgumentNullException>(selector != null); Contract.Requires<ArgumentNullException>(selector != null);
Contract.Requires<ArgumentNullException>(className != null); Contract.Requires<ArgumentNullException>(className != null);
Contract.Requires<ArgumentNullException>(property != null);
if (string.IsNullOrWhiteSpace(className)) if (string.IsNullOrWhiteSpace(className))
{ {

33
src/Avalonia.Controls/DropDown.cs

@ -96,6 +96,16 @@ namespace Avalonia.Controls
this.UpdateSelectionBoxItem(this.SelectedItem); this.UpdateSelectionBoxItem(this.SelectedItem);
} }
protected override void OnGotFocus(GotFocusEventArgs e)
{
base.OnGotFocus(e);
if (!e.Handled && e.NavigationMethod == NavigationMethod.Directional)
{
e.Handled = UpdateSelectionFromEventSource(e.Source);
}
}
/// <inheritdoc/> /// <inheritdoc/>
protected override void OnKeyDown(KeyEventArgs e) protected override void OnKeyDown(KeyEventArgs e)
{ {
@ -104,7 +114,7 @@ namespace Avalonia.Controls
if (!e.Handled) if (!e.Handled)
{ {
if (e.Key == Key.F4 || if (e.Key == Key.F4 ||
(e.Key == Key.Down && ((e.Modifiers & InputModifiers.Alt) != 0))) ((e.Key == Key.Down || e.Key == Key.Up) && ((e.Modifiers & InputModifiers.Alt) != 0)))
{ {
IsDropDownOpen = !IsDropDownOpen; IsDropDownOpen = !IsDropDownOpen;
e.Handled = true; e.Handled = true;
@ -114,6 +124,27 @@ namespace Avalonia.Controls
IsDropDownOpen = false; IsDropDownOpen = false;
e.Handled = true; e.Handled = true;
} }
if (!IsDropDownOpen)
{
if (e.Key == Key.Down)
{
if (SelectedIndex == -1)
SelectedIndex = 0;
if (++SelectedIndex >= ItemCount)
SelectedIndex = 0;
e.Handled = true;
}
else if (e.Key == Key.Up)
{
if (--SelectedIndex < 0)
SelectedIndex = ItemCount - 1;
e.Handled = true;
}
}
} }
} }

11
src/Avalonia.Controls/ItemsControl.cs

@ -11,6 +11,7 @@ using Avalonia.Controls.Presenters;
using Avalonia.Controls.Primitives; using Avalonia.Controls.Primitives;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Input;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Metadata; using Avalonia.Metadata;
@ -106,6 +107,12 @@ namespace Avalonia.Controls
set { SetAndRaise(ItemsProperty, ref _items, value); } set { SetAndRaise(ItemsProperty, ref _items, value); }
} }
public int ItemCount
{
get;
private set;
}
/// <summary> /// <summary>
/// Gets or sets the panel used to display the items. /// Gets or sets the panel used to display the items.
/// </summary> /// </summary>
@ -352,6 +359,10 @@ namespace Avalonia.Controls
RemoveControlItemsFromLogicalChildren(e.OldItems); RemoveControlItemsFromLogicalChildren(e.OldItems);
break; break;
} }
int? count = (Items as IList)?.Count;
if (count != null)
ItemCount = (int)count;
var collection = sender as ICollection; var collection = sender as ICollection;
PseudoClasses.Set(":empty", collection == null || collection.Count == 0); PseudoClasses.Set(":empty", collection == null || collection.Count == 0);

2
src/Avalonia.Controls/Primitives/SelectingItemsControl.cs

@ -297,7 +297,7 @@ namespace Avalonia.Controls.Primitives
.OfType<IControl>() .OfType<IControl>()
.FirstOrDefault(x => x.LogicalParent == this && ItemContainerGenerator?.IndexFromContainer(x) != -1); .FirstOrDefault(x => x.LogicalParent == this && ItemContainerGenerator?.IndexFromContainer(x) != -1);
return item as IControl; return item;
} }
/// <inheritdoc/> /// <inheritdoc/>

5
src/Avalonia.Controls/TreeView.cs

@ -176,10 +176,7 @@ namespace Avalonia.Controls
SelectedItem = item; SelectedItem = item;
if (SelectedItem != null) MarkContainerSelected(container, true);
{
MarkContainerSelected(container, true);
}
} }
} }

8
src/Avalonia.Controls/VirtualizingStackPanel.cs

@ -134,12 +134,14 @@ namespace Avalonia.Controls
protected override IInputElement GetControlInDirection(NavigationDirection direction, IControl from) protected override IInputElement GetControlInDirection(NavigationDirection direction, IControl from)
{ {
if (from == null)
return null;
var logicalScrollable = Parent as ILogicalScrollable; var logicalScrollable = Parent as ILogicalScrollable;
var fromControl = from as IControl;
if (logicalScrollable?.IsLogicalScrollEnabled == true && fromControl != null) if (logicalScrollable?.IsLogicalScrollEnabled == true)
{ {
return logicalScrollable.GetControlInDirection(direction, fromControl); return logicalScrollable.GetControlInDirection(direction, from);
} }
else else
{ {

2
src/Avalonia.Visuals/Media/PathMarkupParser.cs

@ -320,7 +320,7 @@ namespace Avalonia.Media
if (c == 'E') if (c == 'E')
{ {
readSign = false; readSign = false;
readExponent = c == 'E'; readExponent = true;
} }
} }
else else

2
src/Avalonia.Visuals/Rendering/SceneGraph/SceneBuilder.cs

@ -192,7 +192,7 @@ namespace Avalonia.Rendering.SceneGraph
UpdateLayer(node, scene.Layers[node.LayerRoot]); UpdateLayer(node, scene.Layers[node.LayerRoot]);
} }
} }
else if (!startLayer && node.LayerRoot == node.Visual && node.Parent != null) else if (node.LayerRoot == node.Visual && node.Parent != null)
{ {
ClearLayer(scene, node); ClearLayer(scene, node);
} }

32
src/Markup/Avalonia.Markup.Xaml/Data/Binding.cs

@ -104,7 +104,8 @@ namespace Avalonia.Markup.Xaml.Data
observer = CreateElementObserver( observer = CreateElementObserver(
(target as IControl) ?? (anchor as IControl), (target as IControl) ?? (anchor as IControl),
ElementName, ElementName,
Path); Path,
enableDataValidation);
} }
else if (Source != null) else if (Source != null)
{ {
@ -125,7 +126,7 @@ namespace Avalonia.Markup.Xaml.Data
} }
else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent) else if (RelativeSource.Mode == RelativeSourceMode.TemplatedParent)
{ {
observer = CreateTemplatedParentObserver(target, Path); observer = CreateTemplatedParentObserver(target, Path, enableDataValidation);
} }
else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor) else if (RelativeSource.Mode == RelativeSourceMode.FindAncestor)
{ {
@ -137,7 +138,8 @@ namespace Avalonia.Markup.Xaml.Data
observer = CreateFindAncestorObserver( observer = CreateFindAncestorObserver(
(target as IControl) ?? (anchor as IControl), (target as IControl) ?? (anchor as IControl),
RelativeSource, RelativeSource,
Path); Path,
enableDataValidation);
} }
else else
{ {
@ -207,7 +209,11 @@ namespace Avalonia.Markup.Xaml.Data
} }
} }
private ExpressionObserver CreateElementObserver(IControl target, string elementName, string path) private ExpressionObserver CreateElementObserver(
IControl target,
string elementName,
string path,
bool enableDataValidation)
{ {
Contract.Requires<ArgumentNullException>(target != null); Contract.Requires<ArgumentNullException>(target != null);
@ -215,7 +221,7 @@ namespace Avalonia.Markup.Xaml.Data
var result = new ExpressionObserver( var result = new ExpressionObserver(
ControlLocator.Track(target, elementName), ControlLocator.Track(target, elementName),
path, path,
false, enableDataValidation,
description); description);
return result; return result;
} }
@ -223,28 +229,31 @@ namespace Avalonia.Markup.Xaml.Data
private ExpressionObserver CreateFindAncestorObserver( private ExpressionObserver CreateFindAncestorObserver(
IControl target, IControl target,
RelativeSource relativeSource, RelativeSource relativeSource,
string path) string path,
bool enableDataValidation)
{ {
Contract.Requires<ArgumentNullException>(target != null); Contract.Requires<ArgumentNullException>(target != null);
return new ExpressionObserver( return new ExpressionObserver(
ControlLocator.Track(target, relativeSource.Tree, relativeSource.AncestorLevel - 1, relativeSource.AncestorType), ControlLocator.Track(target, relativeSource.Tree, relativeSource.AncestorLevel - 1, relativeSource.AncestorType),
path); path,
enableDataValidation);
} }
private ExpressionObserver CreateSourceObserver( private ExpressionObserver CreateSourceObserver(
object source, object source,
string path, string path,
bool enabledDataValidation) bool enableDataValidation)
{ {
Contract.Requires<ArgumentNullException>(source != null); Contract.Requires<ArgumentNullException>(source != null);
return new ExpressionObserver(source, path, enabledDataValidation); return new ExpressionObserver(source, path, enableDataValidation);
} }
private ExpressionObserver CreateTemplatedParentObserver( private ExpressionObserver CreateTemplatedParentObserver(
IAvaloniaObject target, IAvaloniaObject target,
string path) string path,
bool enableDataValidation)
{ {
Contract.Requires<ArgumentNullException>(target != null); Contract.Requires<ArgumentNullException>(target != null);
@ -255,7 +264,8 @@ namespace Avalonia.Markup.Xaml.Data
var result = new ExpressionObserver( var result = new ExpressionObserver(
() => target.GetValue(Control.TemplatedParentProperty), () => target.GetValue(Control.TemplatedParentProperty),
path, path,
update); update,
enableDataValidation);
return result; return result;
} }

2
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/TemplateBindingExtension.cs

@ -29,7 +29,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions
ElementName = ElementName, ElementName = ElementName,
Mode = Mode, Mode = Mode,
RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent), RelativeSource = new RelativeSource(RelativeSourceMode.TemplatedParent),
Path = Path, Path = Path ?? string.Empty,
Priority = Priority, Priority = Priority,
}; };
} }

10
src/Markup/Avalonia.Markup/Data/Parsers/ArgumentListParser.cs

@ -51,15 +51,7 @@ namespace Avalonia.Markup.Data.Parsers
} }
} }
if (!r.End) throw new ExpressionParseException(r.Position, "Expected ']'.");
{
r.Take();
return result;
}
else
{
throw new ExpressionParseException(r.Position, "Expected ']'.");
}
} }
return null; return null;

1
src/Windows/Avalonia.Direct2D1/Media/DrawingContextImpl.cs

@ -54,7 +54,6 @@ namespace Avalonia.Direct2D1.Media
_finishedCallback = finishedCallback; _finishedCallback = finishedCallback;
_directWriteFactory = directWriteFactory; _directWriteFactory = directWriteFactory;
_imagingFactory = imagingFactory; _imagingFactory = imagingFactory;
_swapChain = swapChain;
_renderTarget.BeginDraw(); _renderTarget.BeginDraw();
} }

23
tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests.cs

@ -13,6 +13,7 @@ using Moq;
using Xunit; using Xunit;
using System.ComponentModel; using System.ComponentModel;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Avalonia.UnitTests;
namespace Avalonia.Markup.Xaml.UnitTests.Data namespace Avalonia.Markup.Xaml.UnitTests.Data
{ {
@ -337,6 +338,28 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
Assert.Equal("foo", target.Content); Assert.Equal("foo", target.Content);
} }
[Fact]
public void Binding_With_Null_Path_Works()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
<TextBlock Name='textBlock' Text='{Binding}'/>
</Window>";
var loader = new AvaloniaXamlLoader();
var window = (Window)loader.Load(xaml);
var textBlock = window.FindControl<TextBlock>("textBlock");
window.DataContext = "foo";
window.ApplyTemplate();
Assert.Equal("foo", textBlock.Text);
}
}
private class TwoWayBindingTest : Control private class TwoWayBindingTest : Control
{ {
public static readonly StyledProperty<string> TwoWayProperty = public static readonly StyledProperty<string> TwoWayProperty =

32
tests/Avalonia.Markup.Xaml.UnitTests/Data/BindingTests_TemplatedParent.cs

@ -11,6 +11,9 @@ using Avalonia.Markup.Xaml.Data;
using Avalonia.Styling; using Avalonia.Styling;
using Xunit; using Xunit;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Avalonia.UnitTests;
using Avalonia.VisualTree;
using System.Linq;
namespace Avalonia.Markup.Xaml.UnitTests.Data namespace Avalonia.Markup.Xaml.UnitTests.Data
{ {
@ -56,6 +59,35 @@ namespace Avalonia.Markup.Xaml.UnitTests.Data
BindingPriority.TemplatedParent)); BindingPriority.TemplatedParent));
} }
[Fact]
public void TemplateBinding_With_Null_Path_Works()
{
using (UnitTestApplication.Start(TestServices.StyledWindow))
{
var xaml = @"
<Window xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'>
<Button Name='button'>
<Button.Template>
<ControlTemplate>
<TextBlock Text='{TemplateBinding}'/>
</ControlTemplate>
</Button.Template>
</Button>
</Window>";
var loader = new AvaloniaXamlLoader();
var window = (Window)loader.Load(xaml);
var button = window.FindControl<Button>("button");
window.ApplyTemplate();
button.ApplyTemplate();
var textBlock = (TextBlock)button.GetVisualChildren().Single();
Assert.Equal("Avalonia.Controls.Button", textBlock.Text);
}
}
private Mock<IControl> CreateTarget( private Mock<IControl> CreateTarget(
ITemplatedControl templatedParent = null, ITemplatedControl templatedParent = null,
string text = null) string text = null)

Loading…
Cancel
Save