Browse Source

Merge branch 'master' into fixes/2004-listbox-duplicates

pull/2673/head
Steven Kirk 7 years ago
committed by GitHub
parent
commit
067a601058
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 24
      src/Avalonia.Controls/AppBuilderBase.cs
  2. 2
      src/Avalonia.Controls/DesktopApplicationExtensions.cs
  3. 173
      src/Avalonia.Controls/DockPanel.cs
  4. 14
      src/Avalonia.Controls/ItemsControl.cs
  5. 10
      src/Avalonia.Controls/WrapPanel.cs

24
src/Avalonia.Controls/AppBuilderBase.cs

@ -4,6 +4,7 @@
using System;
using System.Reflection;
using System.Linq;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Platform;
namespace Avalonia.Controls
@ -106,19 +107,28 @@ namespace Avalonia.Controls
public void Start<TMainWindow>(Func<object> dataContextProvider = null)
where TMainWindow : Window, new()
{
var window = new TMainWindow();
if (dataContextProvider != null)
window.DataContext = dataContextProvider();
Instance.Run(window);
AfterSetup(builder =>
{
var window = new TMainWindow();
if (dataContextProvider != null)
window.DataContext = dataContextProvider();
((IClassicDesktopStyleApplicationLifetime)builder.Instance.ApplicationLifetime)
.MainWindow = window;
});
// Copy-pasted because we can't call extension methods due to generic constraints
var lifetime = new ClassicDesktopStyleApplicationLifetime(Instance) {ShutdownMode = ShutdownMode.OnMainWindowClose};
Instance.ApplicationLifetime = lifetime;
SetupWithoutStarting();
lifetime.Start(Array.Empty<string>());
}
public delegate void AppMainDelegate(Application app, string[] args);
[Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")]
[Obsolete("Use either lifetimes or AppMain overload. See see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)]
public void Start()
{
Setup();
Instance.Run();
throw new NotSupportedException();
}
public void Start(AppMainDelegate main, string[] args)

2
src/Avalonia.Controls/DesktopApplicationExtensions.cs

@ -8,7 +8,7 @@ namespace Avalonia.Controls
{
public static class DesktopApplicationExtensions
{
[Obsolete("Running application without a cancellation token and a lifetime is no longer supported, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details")]
[Obsolete("Running application without a cancellation token and a lifetime is no longer supported, see https://github.com/AvaloniaUI/Avalonia/wiki/Application-lifetimes for details", true)]
public static void Run(this Application app) => throw new NotSupportedException();
/// <summary>

173
src/Avalonia.Controls/DockPanel.cs

@ -1,7 +1,12 @@
// This source file is adapted from the Windows Presentation Foundation project.
// (https://github.com/dotnet/wpf/)
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System;
namespace Avalonia.Controls
{
using System;
/// <summary>
/// Defines the available docking modes for a control in a <see cref="DockPanel"/>.
/// </summary>
@ -70,107 +75,137 @@ namespace Avalonia.Controls
set { SetValue(LastChildFillProperty, value); }
}
/// <inheritdoc/>
/// <summary>
/// Updates DesiredSize of the DockPanel. Called by parent Control. This is the first pass of layout.
/// </summary>
/// <remarks>
/// Children are measured based on their sizing properties and <see cref="Dock" />.
/// Each child is allowed to consume all of the space on the side on which it is docked; Left/Right docked
/// children are granted all vertical space for their entire width, and Top/Bottom docked children are
/// granted all horizontal space for their entire height.
/// </remarks>
/// <param name="constraint">Constraint size is an "upper limit" that the return value should not exceed.</param>
/// <returns>The Panel's desired size.</returns>
protected override Size MeasureOverride(Size constraint)
{
double usedWidth = 0.0;
double usedHeight = 0.0;
double maximumWidth = 0.0;
double maximumHeight = 0.0;
var children = Children;
double parentWidth = 0; // Our current required width due to children thus far.
double parentHeight = 0; // Our current required height due to children thus far.
double accumulatedWidth = 0; // Total width consumed by children.
double accumulatedHeight = 0; // Total height consumed by children.
// Measure each of the Children
foreach (Control element in Children)
for (int i = 0, count = children.Count; i < count; ++i)
{
// Get the child's desired size
Size remainingSize = new Size(
Math.Max(0.0, constraint.Width - usedWidth),
Math.Max(0.0, constraint.Height - usedHeight));
element.Measure(remainingSize);
Size desiredSize = element.DesiredSize;
// Decrease the remaining space for the rest of the children
switch (GetDock(element))
var child = children[i];
Size childConstraint; // Contains the suggested input constraint for this child.
Size childDesiredSize; // Contains the return size from child measure.
if (child == null)
{ continue; }
// Child constraint is the remaining size; this is total size minus size consumed by previous children.
childConstraint = new Size(Math.Max(0.0, constraint.Width - accumulatedWidth),
Math.Max(0.0, constraint.Height - accumulatedHeight));
// Measure child.
child.Measure(childConstraint);
childDesiredSize = child.DesiredSize;
// Now, we adjust:
// 1. Size consumed by children (accumulatedSize). This will be used when computing subsequent
// children to determine how much space is remaining for them.
// 2. Parent size implied by this child (parentSize) when added to the current children (accumulatedSize).
// This is different from the size above in one respect: A Dock.Left child implies a height, but does
// not actually consume any height for subsequent children.
// If we accumulate size in a given dimension, the next child (or the end conditions after the child loop)
// will deal with computing our minimum size (parentSize) due to that accumulation.
// Therefore, we only need to compute our minimum size (parentSize) in dimensions that this child does
// not accumulate: Width for Top/Bottom, Height for Left/Right.
switch (DockPanel.GetDock((Control)child))
{
case Dock.Left:
case Dock.Right:
maximumHeight = Math.Max(maximumHeight, usedHeight + desiredSize.Height);
usedWidth += desiredSize.Width;
parentHeight = Math.Max(parentHeight, accumulatedHeight + childDesiredSize.Height);
accumulatedWidth += childDesiredSize.Width;
break;
case Dock.Top:
case Dock.Bottom:
maximumWidth = Math.Max(maximumWidth, usedWidth + desiredSize.Width);
usedHeight += desiredSize.Height;
parentWidth = Math.Max(parentWidth, accumulatedWidth + childDesiredSize.Width);
accumulatedHeight += childDesiredSize.Height;
break;
}
}
maximumWidth = Math.Max(maximumWidth, usedWidth);
maximumHeight = Math.Max(maximumHeight, usedHeight);
return new Size(maximumWidth, maximumHeight);
// Make sure the final accumulated size is reflected in parentSize.
parentWidth = Math.Max(parentWidth, accumulatedWidth);
parentHeight = Math.Max(parentHeight, accumulatedHeight);
return (new Size(parentWidth, parentHeight));
}
/// <inheritdoc/>
/// <summary>
/// DockPanel computes a position and final size for each of its children based upon their
/// <see cref="Dock" /> enum and sizing properties.
/// </summary>
/// <param name="arrangeSize">Size that DockPanel will assume to position children.</param>
protected override Size ArrangeOverride(Size arrangeSize)
{
double left = 0.0;
double top = 0.0;
double right = 0.0;
double bottom = 0.0;
// Arrange each of the Children
var children = Children;
int dockedCount = children.Count - (LastChildFill ? 1 : 0);
int index = 0;
int totalChildrenCount = children.Count;
int nonFillChildrenCount = totalChildrenCount - (LastChildFill ? 1 : 0);
double accumulatedLeft = 0;
double accumulatedTop = 0;
double accumulatedRight = 0;
double accumulatedBottom = 0;
foreach (Control element in children)
for (int i = 0; i < totalChildrenCount; ++i)
{
// Determine the remaining space left to arrange the element
Rect remainingRect = new Rect(
left,
top,
Math.Max(0.0, arrangeSize.Width - left - right),
Math.Max(0.0, arrangeSize.Height - top - bottom));
// Trim the remaining Rect to the docked size of the element
// (unless the element should fill the remaining space because
// of LastChildFill)
if (index < dockedCount)
var child = children[i];
if (child == null)
{ continue; }
Size childDesiredSize = child.DesiredSize;
Rect rcChild = new Rect(
accumulatedLeft,
accumulatedTop,
Math.Max(0.0, arrangeSize.Width - (accumulatedLeft + accumulatedRight)),
Math.Max(0.0, arrangeSize.Height - (accumulatedTop + accumulatedBottom)));
if (i < nonFillChildrenCount)
{
Size desiredSize = element.DesiredSize;
switch (GetDock(element))
switch (DockPanel.GetDock((Control)child))
{
case Dock.Left:
left += desiredSize.Width;
remainingRect = remainingRect.WithWidth(desiredSize.Width);
break;
case Dock.Top:
top += desiredSize.Height;
remainingRect = remainingRect.WithHeight(desiredSize.Height);
accumulatedLeft += childDesiredSize.Width;
rcChild = rcChild.WithWidth(childDesiredSize.Width);
break;
case Dock.Right:
right += desiredSize.Width;
remainingRect = new Rect(
Math.Max(0.0, arrangeSize.Width - right),
remainingRect.Y,
desiredSize.Width,
remainingRect.Height);
accumulatedRight += childDesiredSize.Width;
rcChild = rcChild.WithX(Math.Max(0.0, arrangeSize.Width - accumulatedRight));
rcChild = rcChild.WithWidth(childDesiredSize.Width);
break;
case Dock.Top:
accumulatedTop += childDesiredSize.Height;
rcChild = rcChild.WithHeight(childDesiredSize.Height);
break;
case Dock.Bottom:
bottom += desiredSize.Height;
remainingRect = new Rect(
remainingRect.X,
Math.Max(0.0, arrangeSize.Height - bottom),
remainingRect.Width,
desiredSize.Height);
accumulatedBottom += childDesiredSize.Height;
rcChild = rcChild.WithY(Math.Max(0.0, arrangeSize.Height - accumulatedBottom));
rcChild = rcChild.WithHeight(childDesiredSize.Height);
break;
}
}
element.Arrange(remainingRect);
index++;
child.Arrange(rcChild);
}
return arrangeSize;
return (arrangeSize);
}
}
}

14
src/Avalonia.Controls/ItemsControl.cs

@ -36,6 +36,12 @@ namespace Avalonia.Controls
public static readonly DirectProperty<ItemsControl, IEnumerable> ItemsProperty =
AvaloniaProperty.RegisterDirect<ItemsControl, IEnumerable>(nameof(Items), o => o.Items, (o, v) => o.Items = v);
/// <summary>
/// Defines the <see cref="ItemCount"/> property.
/// </summary>
public static readonly DirectProperty<ItemsControl, int> ItemCountProperty =
AvaloniaProperty.RegisterDirect<ItemsControl, int>(nameof(ItemCount), o => o.ItemCount);
/// <summary>
/// Defines the <see cref="ItemsPanel"/> property.
/// </summary>
@ -55,6 +61,7 @@ namespace Avalonia.Controls
AvaloniaProperty.Register<ItemsControl, IMemberSelector>(nameof(MemberSelector));
private IEnumerable _items = new AvaloniaList<object>();
private int _itemCount;
private IItemContainerGenerator _itemContainerGenerator;
private IDisposable _itemsCollectionChangedSubscription;
@ -110,10 +117,13 @@ namespace Avalonia.Controls
set { SetAndRaise(ItemsProperty, ref _items, value); }
}
/// <summary>
/// Gets the number of items in <see cref="Items"/>.
/// </summary>
public int ItemCount
{
get;
private set;
get => _itemCount;
private set => SetAndRaise(ItemCountProperty, ref _itemCount, value);
}
/// <summary>

10
src/Avalonia.Controls/WrapPanel.cs

@ -1,9 +1,7 @@
// Copyright (c) The Avalonia Project. All rights reserved.
// Licensed under the MIT license. See licence.md file in the project root for full license information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
// This source file is adapted from the Windows Presentation Foundation project.
// (https://github.com/dotnet/wpf/)
//
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using Avalonia.Input;
using Avalonia.Utilities;

Loading…
Cancel
Save