Browse Source

Ported IElementFactory from UWP/WinUI.

pull/4218/head
Steven Kirk 6 years ago
parent
commit
f545fb2a4d
  1. 66
      src/Avalonia.Controls/Repeater/IElementFactory.cs
  2. 20
      src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs
  3. 4
      src/Avalonia.Controls/Repeater/ItemsRepeater.cs
  4. 31
      src/Avalonia.Controls/Repeater/ViewManager.cs

66
src/Avalonia.Controls/Repeater/IElementFactory.cs

@ -0,0 +1,66 @@
using Avalonia.Controls.Templates;
namespace Avalonia.Controls
{
/// <summary>
/// Represents the optional arguments to use when calling an implementation of the
/// <see cref="IElementFactory"/>'s <see cref="IElementFactory.GetElement"/> method.
/// </summary>
public class ElementFactoryGetArgs
{
/// <summary>
/// Gets or sets the data item for which an appropriate element tree should be realized
/// when calling <see cref="IElementFactory.GetElement"/>.
/// </summary>
public object Data { get; set; }
/// <summary>
/// Gets or sets the <see cref="IControl"/> that is expected to be the parent of the
/// realized element from <see cref="IElementFactory.GetElement"/>.
/// </summary>
public IControl Parent { get; set; }
/// <summary>
/// Gets or sets the index of the item that should be realized.
/// </summary>
public int Index { get; set; }
}
/// <summary>
/// Represents the optional arguments to use when calling an implementation of the
/// <see cref="IElementFactory"/>'s <see cref="IElementFactory.GetElement"/> method.
/// </summary>
public class ElementFactoryRecycleArgs
{
/// <summary>
/// Gets or sets the <see cref="IControl"/> to recycle when calling
/// <see cref="IElementFactory.RecycleElement"/>.
/// </summary>
public IControl Element { get; set; }
/// <summary>
/// Gets or sets the <see cref="IControl"/> that is expected to be the parent of the
/// realized element from <see cref="IElementFactory.GetElement"/>.
/// </summary>
public IControl Parent { get; set; }
}
/// <summary>
/// A data template that supports creating and recyling elements for an <see cref="ItemsRepeater"/>.
/// </summary>
public interface IElementFactory : IDataTemplate
{
/// <summary>
/// Gets an <see cref="IControl"/>.
/// </summary>
/// <param name="args">The element args.</param>
public IControl GetElement(ElementFactoryGetArgs args);
/// <summary>
/// Recycles an <see cref="IControl"/> that was previously retrieved using
/// <see cref="GetElement"/>.
/// </summary>
/// <param name="args">The recycle args.</param>
public void RecycleElement(ElementFactoryRecycleArgs args);
}
}

20
src/Avalonia.Controls/Repeater/ItemTemplateWrapper.cs

@ -7,13 +7,27 @@ using Avalonia.Controls.Templates;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
internal class ItemTemplateWrapper internal class ItemTemplateWrapper : IElementFactory
{ {
private readonly IDataTemplate _dataTemplate; private readonly IDataTemplate _dataTemplate;
public ItemTemplateWrapper(IDataTemplate dataTemplate) => _dataTemplate = dataTemplate; public ItemTemplateWrapper(IDataTemplate dataTemplate) => _dataTemplate = dataTemplate;
public IControl GetElement(IControl parent, object data) public bool SupportsRecycling => false;
public IControl Build(object param) => GetElement(null, param);
public bool Match(object data) => _dataTemplate.Match(data);
public IControl GetElement(ElementFactoryGetArgs args)
{
return GetElement(args.Parent, args.Data);
}
public void RecycleElement(ElementFactoryRecycleArgs args)
{
RecycleElement(args.Parent, args.Element);
}
private IControl GetElement(IControl parent, object data)
{ {
var selectedTemplate = _dataTemplate; var selectedTemplate = _dataTemplate;
var recyclePool = RecyclePool.GetPoolInstance(selectedTemplate); var recyclePool = RecyclePool.GetPoolInstance(selectedTemplate);
@ -37,7 +51,7 @@ namespace Avalonia.Controls
return element; return element;
} }
public void RecycleElement(IControl parent, IControl element) private void RecycleElement(IControl parent, IControl element)
{ {
var selectedTemplate = _dataTemplate; var selectedTemplate = _dataTemplate;
var recyclePool = RecyclePool.GetPoolInstance(selectedTemplate); var recyclePool = RecyclePool.GetPoolInstance(selectedTemplate);

4
src/Avalonia.Controls/Repeater/ItemsRepeater.cs

@ -141,7 +141,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
public ItemsSourceView ItemsSourceView { get; private set; } public ItemsSourceView ItemsSourceView { get; private set; }
internal ItemTemplateWrapper ItemTemplateShim { get; set; } internal IElementFactory ItemTemplateShim { get; set; }
internal Point LayoutOrigin { get; set; } internal Point LayoutOrigin { get; set; }
internal object LayoutState { get; set; } internal object LayoutState { get; set; }
internal IControl MadeAnchor => _viewportManager.MadeAnchor; internal IControl MadeAnchor => _viewportManager.MadeAnchor;
@ -664,7 +664,7 @@ namespace Avalonia.Controls
} }
} }
ItemTemplateShim = new ItemTemplateWrapper(newValue); ItemTemplateShim = newValue as IElementFactory ?? new ItemTemplateWrapper(newValue);
InvalidateMeasure(); InvalidateMeasure();
} }

31
src/Avalonia.Controls/Repeater/ViewManager.cs

@ -6,11 +6,9 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.Linq;
using Avalonia.Controls.Templates; using Avalonia.Controls.Templates;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Layout;
using Avalonia.Logging; using Avalonia.Logging;
using Avalonia.VisualTree; using Avalonia.VisualTree;
@ -26,6 +24,8 @@ namespace Avalonia.Controls
private readonly UniqueIdElementPool _resetPool; private readonly UniqueIdElementPool _resetPool;
private IControl _lastFocusedElement; private IControl _lastFocusedElement;
private bool _isDataSourceStableResetPending; private bool _isDataSourceStableResetPending;
private ElementFactoryGetArgs _elementFactoryGetArgs;
private ElementFactoryRecycleArgs _elementFactoryRecycleArgs;
private int _firstRealizedElementIndexHeldByLayout = FirstRealizedElementIndexDefault; private int _firstRealizedElementIndexHeldByLayout = FirstRealizedElementIndexDefault;
private int _lastRealizedElementIndexHeldByLayout = LastRealizedElementIndexDefault; private int _lastRealizedElementIndexHeldByLayout = LastRealizedElementIndexDefault;
private bool _eventsSubscribed; private bool _eventsSubscribed;
@ -134,7 +134,14 @@ namespace Avalonia.Controls
if (_owner.ItemTemplateShim != null) if (_owner.ItemTemplateShim != null)
{ {
_owner.ItemTemplateShim.RecycleElement(_owner, element); var context = _elementFactoryRecycleArgs ??= new ElementFactoryRecycleArgs();
context.Element = element;
context.Parent = _owner;
_owner.ItemTemplateShim.RecycleElement(context);
context.Element = null;
context.Parent = null;
} }
else else
{ {
@ -579,7 +586,7 @@ namespace Avalonia.Controls
var data = _owner.ItemsSourceView.GetAt(index); var data = _owner.ItemsSourceView.GetAt(index);
var providedElementFactory = _owner.ItemTemplateShim; var providedElementFactory = _owner.ItemTemplateShim;
ItemTemplateWrapper GetElementFactory() IElementFactory GetElementFactory()
{ {
if (providedElementFactory == null) if (providedElementFactory == null)
{ {
@ -602,7 +609,20 @@ namespace Avalonia.Controls
} }
var elementFactory = GetElementFactory(); var elementFactory = GetElementFactory();
return elementFactory.GetElement(_owner, data); var args = _elementFactoryGetArgs ??= new ElementFactoryGetArgs();
try
{
args.Data = data;
args.Parent = _owner;
args.Index = index;
return elementFactory.GetElement(args);
}
finally
{
args.Data = null;
args.Parent = null;
}
} }
var element = GetElement(); var element = GetElement();
@ -732,6 +752,7 @@ namespace Avalonia.Controls
{ {
_owner.GotFocus += OnFocusChanged; _owner.GotFocus += OnFocusChanged;
_owner.LostFocus += OnFocusChanged; _owner.LostFocus += OnFocusChanged;
_eventsSubscribed = true;
} }
} }

Loading…
Cancel
Save