Browse Source

Merge branch 'master' into parse-class

pull/5495/head
Dariusz Komosiński 5 years ago
committed by GitHub
parent
commit
b45e8050df
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 5
      samples/ControlCatalog/Pages/DataGridPage.xaml
  2. 6
      samples/ControlCatalog/Pages/DataGridPage.xaml.cs
  3. 21
      src/Avalonia.Controls.DataGrid/DataGridBoundColumn.cs
  4. 16
      src/Avalonia.Controls.DataGrid/DataGridColumn.cs
  5. 5
      src/Avalonia.Controls.DataGrid/DataGridColumns.cs
  6. 77
      src/Avalonia.Controls/ContextMenu.cs
  7. 4
      src/Avalonia.Input/FocusManager.cs
  8. 11
      src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs
  9. 19
      tests/Avalonia.Input.UnitTests/InputElement_Focus.cs

5
samples/ControlCatalog/Pages/DataGridPage.xaml

@ -1,5 +1,5 @@
<UserControl xmlns="https://github.com/avaloniaui" <UserControl xmlns="https://github.com/avaloniaui"
xmlns:local="clr-namespace:ControlCatalog.Models;assembly=ControlCatalog" xmlns:local="using:ControlCatalog.Models"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="ControlCatalog.Pages.DataGridPage"> x:Class="ControlCatalog.Pages.DataGridPage">
<UserControl.Resources> <UserControl.Resources>
@ -26,7 +26,8 @@
<DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All"> <DataGrid Name="dataGrid1" Margin="12" CanUserResizeColumns="True" CanUserReorderColumns="True" CanUserSortColumns="True" HeadersVisibility="All">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Header="Country" Binding="{Binding Name}" Width="6*" /> <DataGridTextColumn Header="Country" Binding="{Binding Name}" Width="6*" />
<DataGridTextColumn Header="Region" Binding="{Binding Region}" Width="4*" /> <!-- CompiledBinding example of usage. -->
<DataGridTextColumn Header="Region" Binding="{CompiledBinding Region}" Width="4*" x:DataType="local:Country" />
<DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" /> <DataGridTextColumn Header="Population" Binding="{Binding Population}" Width="3*" />
<DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" /> <DataGridTextColumn Header="Area" Binding="{Binding Area}" Width="3*" />
<DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" CellStyleClasses="gdp" /> <DataGridTextColumn Header="GDP" Binding="{Binding GDP}" Width="3*" CellStyleClasses="gdp" />

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

@ -24,8 +24,10 @@ namespace ControlCatalog.Pages
dg1.LoadingRow += Dg1_LoadingRow; dg1.LoadingRow += Dg1_LoadingRow;
dg1.Sorting += (s, a) => dg1.Sorting += (s, a) =>
{ {
var property = ((a.Column as DataGridBoundColumn)?.Binding as Binding).Path; var binding = (a.Column as DataGridBoundColumn)?.Binding as Binding;
if (property == dataGridSortDescription.PropertyPath
if (binding?.Path is string property
&& property == dataGridSortDescription.PropertyPath
&& !collectionView1.SortDescriptions.Contains(dataGridSortDescription)) && !collectionView1.SortDescriptions.Contains(dataGridSortDescription))
{ {
collectionView1.SortDescriptions.Add(dataGridSortDescription); collectionView1.SortDescriptions.Add(dataGridSortDescription);

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

@ -10,7 +10,8 @@ using System.Reactive.Disposables;
using System.Reactive.Subjects; using System.Reactive.Subjects;
using Avalonia.Reactive; using Avalonia.Reactive;
using System.Diagnostics; using System.Diagnostics;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Markup.Xaml.MarkupExtensions;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -47,14 +48,15 @@ namespace Avalonia.Controls
if (_binding != null) if (_binding != null)
{ {
if(_binding is Avalonia.Data.Binding binding) if(_binding is BindingBase binding)
{ {
if (binding.Mode == BindingMode.OneWayToSource) if (binding.Mode == BindingMode.OneWayToSource)
{ {
throw new InvalidOperationException("DataGridColumn doesn't support BindingMode.OneWayToSource. Use BindingMode.TwoWay instead."); throw new InvalidOperationException("DataGridColumn doesn't support BindingMode.OneWayToSource. Use BindingMode.TwoWay instead.");
} }
if (!String.IsNullOrEmpty(binding.Path) && binding.Mode == BindingMode.Default) var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (!string.IsNullOrEmpty(path) && binding.Mode == BindingMode.Default)
{ {
binding.Mode = BindingMode.TwoWay; binding.Mode = BindingMode.TwoWay;
} }
@ -136,13 +138,16 @@ namespace Avalonia.Controls
internal void SetHeaderFromBinding() internal void SetHeaderFromBinding()
{ {
if (OwningGrid != null && OwningGrid.DataConnection.DataType != null if (OwningGrid != null && OwningGrid.DataConnection.DataType != null
&& Header == null && Binding != null && Binding is Binding binding && Header == null && Binding != null && Binding is BindingBase binding)
&& !String.IsNullOrWhiteSpace(binding.Path))
{ {
string header = OwningGrid.DataConnection.DataType.GetDisplayName(binding.Path); var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (header != null) if (!string.IsNullOrWhiteSpace(path))
{ {
Header = header; var header = OwningGrid.DataConnection.DataType.GetDisplayName(path);
if (header != null)
{
Header = header;
}
} }
} }
} }

16
src/Avalonia.Controls.DataGrid/DataGridColumn.cs

@ -12,6 +12,7 @@ using System;
using System.Linq; using System.Linq;
using System.Diagnostics; using System.Diagnostics;
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Markup.Xaml.MarkupExtensions;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -1033,13 +1034,16 @@ namespace Avalonia.Controls
if (String.IsNullOrEmpty(result)) if (String.IsNullOrEmpty(result))
{ {
if (this is DataGridBoundColumn boundColumn)
if(this is DataGridBoundColumn boundColumn &&
boundColumn.Binding != null &&
boundColumn.Binding is Binding binding &&
binding.Path != null)
{ {
result = binding.Path; if (boundColumn.Binding is Binding binding)
{
result = binding.Path;
}
else if (boundColumn.Binding is CompiledBindingExtension compiledBinding)
{
result = compiledBinding.Path.ToString();
}
} }
} }

5
src/Avalonia.Controls.DataGrid/DataGridColumns.cs

@ -5,6 +5,7 @@
using Avalonia.Controls.Utils; using Avalonia.Controls.Utils;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Markup.Xaml.MarkupExtensions;
using Avalonia.Utilities; using Avalonia.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@ -141,9 +142,9 @@ namespace Avalonia.Controls
Debug.Assert(dataGridColumn != null); Debug.Assert(dataGridColumn != null);
if (dataGridColumn is DataGridBoundColumn dataGridBoundColumn && if (dataGridColumn is DataGridBoundColumn dataGridBoundColumn &&
dataGridBoundColumn.Binding is Binding binding) dataGridBoundColumn.Binding is BindingBase binding)
{ {
string path = binding.Path; var path = (binding as Binding)?.Path ?? (binding as CompiledBindingExtension)?.Path.ToString();
if (string.IsNullOrWhiteSpace(path)) if (string.IsNullOrWhiteSpace(path))
{ {

77
src/Avalonia.Controls/ContextMenu.cs

@ -269,7 +269,43 @@ namespace Avalonia.Controls
} }
control ??= _attachedControls![0]; control ??= _attachedControls![0];
Open(control, PlacementTarget ?? control);
}
/// <summary>
/// Closes the menu.
/// </summary>
public override void Close()
{
if (!IsOpen)
{
return;
}
if (_popup != null && _popup.IsVisible)
{
_popup.IsOpen = false;
}
}
void ISetterValue.Initialize(ISetter setter)
{
// ContextMenu can be assigned to the ContextMenu property in a setter. This overrides
// the behavior defined in Control which requires controls to be wrapped in a <template>.
if (!(setter is Setter s && s.Property == ContextMenuProperty))
{
throw new InvalidOperationException(
"Cannot use a control as a Setter value. Wrap the control in a <Template>.");
}
}
protected override IItemContainerGenerator CreateItemContainerGenerator()
{
return new MenuItemContainerGenerator(this);
}
private void Open(Control control, Control placementTarget)
{
if (IsOpen) if (IsOpen)
{ {
return; return;
@ -286,7 +322,6 @@ namespace Avalonia.Controls
PlacementGravity = PlacementGravity, PlacementGravity = PlacementGravity,
PlacementMode = PlacementMode, PlacementMode = PlacementMode,
PlacementRect = PlacementRect, PlacementRect = PlacementRect,
PlacementTarget = PlacementTarget ?? control,
IsLightDismissEnabled = true, IsLightDismissEnabled = true,
OverlayDismissEventPassThrough = true, OverlayDismissEventPassThrough = true,
WindowManagerAddShadowHint = WindowManagerAddShadowHint, WindowManagerAddShadowHint = WindowManagerAddShadowHint,
@ -302,11 +337,7 @@ namespace Avalonia.Controls
((ISetLogicalParent)_popup).SetParent(control); ((ISetLogicalParent)_popup).SetParent(control);
} }
if (PlacementTarget is null && _popup.PlacementTarget != control) _popup.PlacementTarget = placementTarget;
{
_popup.PlacementTarget = control;
}
_popup.Child = this; _popup.Child = this;
IsOpen = true; IsOpen = true;
_popup.IsOpen = true; _popup.IsOpen = true;
@ -318,38 +349,6 @@ namespace Avalonia.Controls
}); });
} }
/// <summary>
/// Closes the menu.
/// </summary>
public override void Close()
{
if (!IsOpen)
{
return;
}
if (_popup != null && _popup.IsVisible)
{
_popup.IsOpen = false;
}
}
void ISetterValue.Initialize(ISetter setter)
{
// ContextMenu can be assigned to the ContextMenu property in a setter. This overrides
// the behavior defined in Control which requires controls to be wrapped in a <template>.
if (!(setter is Setter s && s.Property == ContextMenuProperty))
{
throw new InvalidOperationException(
"Cannot use a control as a Setter value. Wrap the control in a <Template>.");
}
}
protected override IItemContainerGenerator CreateItemContainerGenerator()
{
return new MenuItemContainerGenerator(this);
}
private void PopupOpened(object sender, EventArgs e) private void PopupOpened(object sender, EventArgs e)
{ {
_previousFocus = FocusManager.Instance?.Current; _previousFocus = FocusManager.Instance?.Current;
@ -403,7 +402,7 @@ namespace Avalonia.Controls
if (contextMenu.CancelOpening()) if (contextMenu.CancelOpening())
return; return;
contextMenu.Open(control); contextMenu.Open(control, e.Source as Control ?? control);
e.Handled = true; e.Handled = true;
} }
} }

4
src/Avalonia.Input/FocusManager.cs

@ -75,7 +75,9 @@ namespace Avalonia.Input
// If control is null, set focus to the topmost focus scope. // If control is null, set focus to the topmost focus scope.
foreach (var scope in GetFocusScopeAncestors(Current).Reverse().ToList()) foreach (var scope in GetFocusScopeAncestors(Current).Reverse().ToList())
{ {
if (_focusScopes.TryGetValue(scope, out var element) && element != null) if (scope != Scope &&
_focusScopes.TryGetValue(scope, out var element) &&
element != null)
{ {
Focus(element, method); Focus(element, method);
return; return;

11
src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/CompiledBindings/CompiledBindingPath.cs

@ -72,7 +72,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal object RawSource { get; } internal object RawSource { get; }
public override string ToString() public override string ToString()
=> string.Concat(_elements.Select(e => e.ToString())); => string.Concat(_elements);
} }
public class CompiledBindingPathBuilder public class CompiledBindingPathBuilder
@ -88,7 +88,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public CompiledBindingPathBuilder Property(IPropertyInfo info, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory) public CompiledBindingPathBuilder Property(IPropertyInfo info, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory)
{ {
_elements.Add(new PropertyElement(info, accessorFactory)); _elements.Add(new PropertyElement(info, accessorFactory, _elements.Count == 0));
return this; return this;
} }
@ -161,10 +161,13 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
internal class PropertyElement : ICompiledBindingPathElement internal class PropertyElement : ICompiledBindingPathElement
{ {
public PropertyElement(IPropertyInfo property, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory) private readonly bool _isFirstElement;
public PropertyElement(IPropertyInfo property, Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> accessorFactory, bool isFirstElement)
{ {
Property = property; Property = property;
AccessorFactory = accessorFactory; AccessorFactory = accessorFactory;
_isFirstElement = isFirstElement;
} }
public IPropertyInfo Property { get; } public IPropertyInfo Property { get; }
@ -172,7 +175,7 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions.CompiledBindings
public Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; } public Func<WeakReference<object>, IPropertyInfo, IPropertyAccessor> AccessorFactory { get; }
public override string ToString() public override string ToString()
=> $".{Property.Name}"; => _isFirstElement ? Property.Name : $".{Property.Name}";
} }
internal interface IStronglyTypedStreamElement : ICompiledBindingPathElement internal interface IStronglyTypedStreamElement : ICompiledBindingPathElement

19
tests/Avalonia.Input.UnitTests/InputElement_Focus.cs

@ -318,5 +318,24 @@ namespace Avalonia.Input.UnitTests
Assert.True(root2.IsKeyboardFocusWithin); Assert.True(root2.IsKeyboardFocusWithin);
} }
} }
[Fact]
public void Can_Clear_Focus()
{
Button target;
using (UnitTestApplication.Start(TestServices.RealFocus))
{
var root = new TestRoot
{
Child = target = new Button()
};
target.Focus();
FocusManager.Instance.Focus(null);
Assert.Null(FocusManager.Instance.Current);
}
}
} }
} }

Loading…
Cancel
Save