Browse Source

Documented ItemsPresenter.

And tidied up a couple of things.
pull/69/head
Steven Kirk 11 years ago
parent
commit
362abd481c
  1. 111
      Perspex.Controls/Presenters/ItemsPresenter.cs

111
Perspex.Controls/Presenters/ItemsPresenter.cs

@ -6,60 +6,90 @@
namespace Perspex.Controls.Presenters
{
using System.Collections;
using System.Collections.Specialized;
using Perspex.Controls.Generators;
using Perspex.Input;
using Perspex.Styling;
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reactive.Linq;
/// <summary>
/// Displays items inside an <see cref="ItemsControl"/>.
/// </summary>
public class ItemsPresenter : Control, IItemsPresenter, ITemplatedControl
{
/// <summary>
/// Defines the <see cref="Items"/> property.
/// </summary>
public static readonly PerspexProperty<IEnumerable> ItemsProperty =
ItemsControl.ItemsProperty.AddOwner<ItemsPresenter>();
/// <summary>
/// Defines the <see cref="ItemsPanel"/> property.
/// </summary>
public static readonly PerspexProperty<ItemsPanelTemplate> ItemsPanelProperty =
ItemsControl.ItemsPanelProperty.AddOwner<ItemsPresenter>();
private bool createdPanel;
private IItemContainerGenerator generator;
/// <summary>
/// Initializes static members of the <see cref="ItemsPresenter"/> class.
/// </summary>
static ItemsPresenter()
{
KeyboardNavigation.TabNavigationProperty.OverrideDefaultValue(
typeof(ItemsPresenter),
KeyboardNavigationMode.Once);
ItemsProperty.Changed.AddClassHandler<ItemsPresenter>(x => x.ItemsChanged);
}
public ItemsPresenter()
/// <summary>
/// Gets the <see cref="IItemContainerGenerator"/> used to generate item container
/// controls.
/// </summary>
public IItemContainerGenerator ItemContainerGenerator
{
this.GetObservableWithHistory(ItemsProperty).Subscribe(this.ItemsChanged);
}
get
{
if (this.generator == null)
{
var i = this.TemplatedParent as ItemsControl;
this.generator = i?.ItemContainerGenerator ?? new ItemContainerGenerator(this);
}
public ItemContainerGenerator ItemContainerGenerator
{
get;
private set;
return this.generator;
}
}
/// <summary>
/// Gets or sets the items to be displayed.
/// </summary>
public IEnumerable Items
{
get { return this.GetValue(ItemsProperty); }
set { this.SetValue(ItemsProperty, value); }
}
/// <summary>
/// Gets or sets a template which creates the <see cref="Panel"/> used to display the items.
/// </summary>
public ItemsPanelTemplate ItemsPanel
{
get { return this.GetValue(ItemsPanelProperty); }
set { this.SetValue(ItemsPanelProperty, value); }
}
/// <summary>
/// Gets the panel used to display the items.
/// </summary>
public Panel Panel
{
get;
private set;
}
/// <inheritdoc/>
public override sealed void ApplyTemplate()
{
if (!this.createdPanel)
@ -68,18 +98,24 @@ namespace Perspex.Controls.Presenters
}
}
/// <inheritdoc/>
protected override Size MeasureOverride(Size availableSize)
{
this.Panel.Measure(availableSize);
return this.Panel.DesiredSize;
}
/// <inheritdoc/>
protected override Size ArrangeOverride(Size finalSize)
{
this.Panel.Arrange(new Rect(finalSize));
return finalSize;
}
/// <summary>
/// Creates the <see cref="Panel"/> when <see cref="ApplyTemplate"/> is called for the first
/// time.
/// </summary>
private void CreatePanel()
{
this.ClearVisualChildren();
@ -89,32 +125,44 @@ namespace Perspex.Controls.Presenters
((IItemsPanel)this.Panel).ChildLogicalParent = this.TemplatedParent as ILogical;
this.AddVisualChild(this.Panel);
this.createdPanel = true;
this.ItemsChanged(Tuple.Create(default(IEnumerable), this.Items));
this.CreateItemsAndListenForChanges(this.Items);
}
private IItemContainerGenerator GetGenerator()
/// <summary>
/// Creates the items for a collection and starts listening for changes on the collection.
/// </summary>
/// <param name="items">The items, may be null.</param>
private void CreateItemsAndListenForChanges(IEnumerable items)
{
if (this.ItemContainerGenerator == null)
if (items != null)
{
ItemsControl i = this.TemplatedParent as ItemsControl;
this.ItemContainerGenerator = i?.ItemContainerGenerator ?? new ItemContainerGenerator(this);
}
this.Panel.Children.AddRange(this.ItemContainerGenerator.Generate(this.Items));
return this.ItemContainerGenerator;
INotifyCollectionChanged incc = items as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged += this.ItemsCollectionChanged;
}
}
}
private void ItemsChanged(Tuple<IEnumerable, IEnumerable> value)
/// <summary>
/// Called when the <see cref="Items"/> property changes.
/// </summary>
/// <param name="e">The event args.</param>
private void ItemsChanged(PerspexPropertyChangedEventArgs e)
{
if (this.createdPanel)
{
var generator = this.GetGenerator();
var generator = this.ItemContainerGenerator;
if (value.Item1 != null)
if (e.OldValue != null)
{
generator.RemoveAll();
this.Panel.Children.Clear();
INotifyCollectionChanged incc = value.Item1 as INotifyCollectionChanged;
INotifyCollectionChanged incc = e.OldValue as INotifyCollectionChanged;
if (incc != null)
{
@ -124,26 +172,21 @@ namespace Perspex.Controls.Presenters
if (this.Panel != null)
{
if (value.Item2 != null)
{
this.Panel.Children.AddRange(generator.Generate(this.Items));
INotifyCollectionChanged incc = value.Item2 as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged += this.ItemsCollectionChanged;
}
}
this.CreateItemsAndListenForChanges((IEnumerable)e.NewValue);
}
}
}
/// <summary>
/// Called when the <see cref="Items"/> collection changes.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The event args.</param>
private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.createdPanel)
{
var generator = this.GetGenerator();
var generator = this.ItemContainerGenerator;
// TODO: Handle Move and Replace etc.
switch (e.Action)

Loading…
Cancel
Save