A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

142 lines
4.4 KiB

// -----------------------------------------------------------------------
// <copyright file="ItemsPresenter.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Presenters
{
using System;
using System.Collections;
using System.Collections.Specialized;
using System.Reactive.Linq;
using Perspex.Controls.Generators;
public class ItemsPresenter : Control, IVisual
{
public static readonly PerspexProperty<IEnumerable> ItemsProperty =
ItemsControl.ItemsProperty.AddOwner<ItemsPresenter>();
public static readonly PerspexProperty<ItemsPanelTemplate> ItemsPanelProperty =
ItemsControl.ItemsPanelProperty.AddOwner<ItemsPresenter>();
private Panel panel;
private bool createdPanel;
public ItemsPresenter()
{
this.GetObservableWithHistory(ItemsProperty).Skip(1).Subscribe(this.ItemsChanged);
}
public IEnumerable Items
{
get { return this.GetValue(ItemsProperty); }
set { this.SetValue(ItemsProperty, value); }
}
public ItemsPanelTemplate ItemsPanel
{
get { return this.GetValue(ItemsPanelProperty); }
set { this.SetValue(ItemsPanelProperty, value); }
}
protected override sealed void ApplyTemplate()
{
if (!this.createdPanel)
{
this.CreatePanel();
}
}
protected override Size MeasureOverride(Size availableSize)
{
this.panel.Measure(availableSize);
return this.panel.DesiredSize.Value;
}
protected override Size ArrangeOverride(Size finalSize)
{
this.panel.Arrange(new Rect(finalSize));
return finalSize;
}
private void CreatePanel()
{
this.ClearVisualChildren();
this.panel = this.ItemsPanel.Build();
this.AddVisualChild(this.panel);
this.createdPanel = true;
this.ItemsChanged(Tuple.Create(default(IEnumerable), this.Items));
}
private IItemContainerGenerator GetGenerator()
{
ItemsControl i = this.TemplatedParent as ItemsControl;
if (i == null)
{
throw new InvalidOperationException("ItemsPresenter must be part of an ItemsControl template.");
}
return i.ItemContainerGenerator;
}
private void ItemsChanged(Tuple<IEnumerable, IEnumerable> value)
{
if (this.createdPanel)
{
var generator = this.GetGenerator();
if (value.Item1 != null)
{
this.panel.Children.RemoveAll(generator.Remove(value.Item1));
INotifyCollectionChanged incc = value.Item1 as INotifyCollectionChanged;
if (incc != null)
{
incc.CollectionChanged -= this.ItemsCollectionChanged;
}
}
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;
}
}
}
}
}
private void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (this.createdPanel)
{
var generator = this.GetGenerator();
// TODO: Handle Move and Replace etc.
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
this.panel.Children.AddRange(generator.Generate(e.NewItems));
break;
case NotifyCollectionChangedAction.Remove:
this.panel.Children.RemoveAll(generator.Remove(e.OldItems));
break;
}
this.InvalidateMeasure();
}
}
}
}