diff options
Diffstat (limited to 'Xamarin.Forms.Platform.WP8/CarouselPageRenderer.cs')
-rw-r--r-- | Xamarin.Forms.Platform.WP8/CarouselPageRenderer.cs | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/Xamarin.Forms.Platform.WP8/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.WP8/CarouselPageRenderer.cs new file mode 100644 index 00000000..29446c43 --- /dev/null +++ b/Xamarin.Forms.Platform.WP8/CarouselPageRenderer.cs @@ -0,0 +1,219 @@ +using System; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using Microsoft.Phone.Controls; + +namespace Xamarin.Forms.Platform.WinPhone +{ + internal class BackgroundTracker<T> : VisualElementTracker<Page, T> where T : FrameworkElement + { + readonly DependencyProperty _backgroundProperty; + + bool _backgroundNeedsUpdate = true; + + public BackgroundTracker(DependencyProperty backgroundProperty) + { + if (backgroundProperty == null) + throw new ArgumentNullException("backgroundProperty"); + + _backgroundProperty = backgroundProperty; + } + + protected override void HandlePropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Page.BackgroundImageProperty.PropertyName) + UpdateBackground(); + + base.HandlePropertyChanged(sender, e); + } + + protected override void UpdateNativeControl() + { + base.UpdateNativeControl(); + + if (_backgroundNeedsUpdate) + UpdateBackground(); + } + + void UpdateBackground() + { + if (Model == null || Element == null) + return; + + if (Model.BackgroundImage != null) + { + Element.SetValue(_backgroundProperty, new ImageBrush { ImageSource = new BitmapImage(new Uri(Model.BackgroundImage, UriKind.Relative)) }); + } + else if (Model.BackgroundColor != Color.Default) + Element.SetValue(_backgroundProperty, Model.BackgroundColor.ToBrush()); + + _backgroundNeedsUpdate = false; + } + } + + public class CarouselPagePresenter : System.Windows.Controls.ContentPresenter + { + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + DependencyObject parent = VisualTreeHelper.GetParent(this); + while (parent != null && !(parent is PanoramaItem)) + parent = VisualTreeHelper.GetParent(parent); + + var panoramaItem = parent as PanoramaItem; + if (panoramaItem == null) + throw new Exception("No parent PanoramaItem found for carousel page"); + + var element = (FrameworkElement)VisualTreeHelper.GetChild(panoramaItem, 0); + element.SizeChanged += (s, e) => + { + if (element.ActualWidth > 0 && element.ActualHeight > 0) + { + var carouselItem = (Page)DataContext; + ((CarouselPage)carouselItem.RealParent).ContainerArea = new Rectangle(0, 0, element.ActualWidth, element.ActualHeight); + } + }; + } + } + + public class CarouselPageRenderer : Panorama, IVisualElementRenderer + { + static readonly System.Windows.DataTemplate PageTemplate; + + static readonly BindableProperty PageContainerProperty = BindableProperty.CreateAttached("PageContainer", typeof(PanoramaItem), typeof(CarouselPageRenderer), null); + + CarouselPage _page; + BackgroundTracker<Control> _tracker; + + static CarouselPageRenderer() + { + PageTemplate = (System.Windows.DataTemplate)System.Windows.Application.Current.Resources["CarouselPage"]; + } + + public CarouselPageRenderer() + { + SetBinding(TitleProperty, new System.Windows.Data.Binding("Title")); + } + + public UIElement ContainerElement + { + get { return this; } + } + + public VisualElement Element + { + get { return _page; } + } + + public event EventHandler<VisualElementChangedEventArgs> ElementChanged; + + public SizeRequest GetDesiredSize(double widthConstraint, double heightConstraint) + { + return new SizeRequest(new Size(widthConstraint, heightConstraint)); + } + + public void SetElement(VisualElement element) + { + CarouselPage oldElement = _page; + _page = (CarouselPage)element; + _tracker = new BackgroundTracker<Control>(BackgroundProperty) { Model = _page, Element = this }; + + DataContext = _page; + + SelectionChanged += OnSelectionChanged; + + OnPagesChanged(_page, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + + _page.PagesChanged += OnPagesChanged; + _page.PropertyChanged += OnPropertyChanged; + + Loaded += (sender, args) => _page.SendAppearing(); + Unloaded += (sender, args) => _page.SendDisappearing(); + + OnElementChanged(new VisualElementChangedEventArgs(oldElement, element)); + } + + protected virtual void OnElementChanged(VisualElementChangedEventArgs e) + { + EventHandler<VisualElementChangedEventArgs> changed = ElementChanged; + if (changed != null) + changed(this, e); + } + + static PanoramaItem GetPageContainer(BindableObject bindable) + { + return (PanoramaItem)bindable.GetValue(PageContainerProperty); + } + + void InsertItem(object item, int index, bool newItem) + { + DependencyObject pageContent = PageTemplate.LoadContent(); + + var pageItem = (Page)item; + PanoramaItem container = GetPageContainer(pageItem); + if (container == null) + { + container = new PanoramaItem { DataContext = item, Content = pageContent }; + + SetPageContainer(pageItem, container); + } + + Items.Insert(index, container); + } + + void OnPagesChanged(object sender, NotifyCollectionChangedEventArgs e) + { + e.Apply(InsertItem, RemoveItem, Reset); + } + + void OnPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == "CurrentPage") + { + ContentPage current = _page.CurrentPage; + if (current == null) + return; + + SetValue(SelectedItemProperty, GetPageContainer(current)); + OnItemsChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + } + + void OnSelectionChanged(object sender, SelectionChangedEventArgs e) + { + var panoramaItem = (PanoramaItem)SelectedItem; + if (panoramaItem == null) + _page.CurrentPage = null; + else + _page.CurrentPage = (ContentPage)panoramaItem.DataContext; + } + + void RemoveItem(object item, int index) + { + Items.RemoveAt(index); + } + + void Reset() + { + Items.Clear(); + + var i = 0; + foreach (Page pageItem in _page.Children) + InsertItem(pageItem, i++, true); + + ContentPage current = _page.CurrentPage; + if (current != null) + SetValue(SelectedItemProperty, GetPageContainer(current)); + } + + static void SetPageContainer(BindableObject bindable, PanoramaItem container) + { + bindable.SetValue(PageContainerProperty, container); + } + } +}
\ No newline at end of file |