Created
June 21, 2016 06:17
-
-
Save robmikh/1b9d89de53617feb037e5db6074680ab to your computer and use it in GitHub Desktop.
Quick and dirty FlipView indicator using Composition+XAML
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Collections.ObjectModel; | |
using System.Linq; | |
using System.Runtime.InteropServices.WindowsRuntime; | |
using Windows.UI.Composition; | |
using Windows.UI.Xaml; | |
using Windows.UI.Xaml.Controls; | |
using Windows.UI.Xaml.Data; | |
using Windows.UI.Xaml.Documents; | |
using Windows.UI.Xaml.Hosting; | |
using Windows.UI.Xaml.Input; | |
using Windows.UI.Xaml.Media; | |
// The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235 | |
namespace FlipViewIndicator | |
{ | |
public sealed class FlipViewIndicator : Control | |
{ | |
private static readonly DependencyProperty FlipViewProperty = DependencyProperty.Register(nameof(FlipView), typeof(FlipView), typeof(FlipViewIndicator), new PropertyMetadata(null, OnFlipViewPropertyChanged)); | |
private static void OnFlipViewPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) | |
{ | |
var control = d as FlipViewIndicator; | |
var newValue = e.NewValue as FlipView; | |
var oldValue = e.OldValue as FlipView; | |
if (control != null && newValue != oldValue) | |
{ | |
if (oldValue != null) | |
{ | |
control.DeregisterFlipView(oldValue); | |
} | |
if (newValue != null) | |
{ | |
control.RegisterFlipView(newValue); | |
} | |
} | |
} | |
public FlipView FlipView { get { return (FlipView)GetValue(FlipViewProperty); } set { SetValue(FlipViewProperty, value); } } | |
private int _listCount; | |
private CompositionPropertySet _propertySet; | |
private ObservableCollection<int> _dummyList; | |
public FlipViewIndicator() | |
{ | |
_listCount = 0; | |
_dummyList = new ObservableCollection<int>(); | |
this.DefaultStyleKey = typeof(FlipViewIndicator); | |
SizeChanged += OnControlSizeChanged; | |
} | |
private void OnControlSizeChanged(object sender, SizeChangedEventArgs e) | |
{ | |
UpdatePropertySetValues(); | |
} | |
protected override void OnApplyTemplate() | |
{ | |
base.OnApplyTemplate(); | |
var itemsControl = GetTemplateChild("ContentItemsControl") as ItemsControl; | |
itemsControl.ItemsSource = _dummyList; | |
} | |
private void RegisterFlipView(FlipView flipView) | |
{ | |
var numItems = flipView.Items.Count(); | |
UpdateNumItems(numItems); | |
flipView.SelectionChanged += FlipView_SelectionChanged; | |
flipView.SizeChanged += OnControlSizeChanged; | |
SetupExpression(); | |
} | |
private void DeregisterFlipView(FlipView flipView) | |
{ | |
UpdateNumItems(0); | |
flipView.SelectionChanged -= FlipView_SelectionChanged; | |
flipView.SizeChanged -= OnControlSizeChanged; | |
RemoveExpression(); | |
} | |
private void EnsurePropertySet() | |
{ | |
if (_propertySet == null) | |
{ | |
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; | |
_propertySet = compositor.CreatePropertySet(); | |
UpdatePropertySetValues(); | |
} | |
} | |
private void UpdatePropertySetValues() | |
{ | |
if (_propertySet != null) | |
{ | |
float scrollViewerWidth = FlipView != null ? (float)(FlipView.Items.Count * FlipView.Width) : 0; | |
_propertySet.InsertScalar("ScrollViewerWidth", scrollViewerWidth); | |
_propertySet.InsertScalar("ControlWidth", (float)ActualWidth); | |
} | |
} | |
private void SetupExpression() | |
{ | |
var currentIndexIndicator = GetTemplateChild("CurrentIndexIndicator") as UIElement; | |
if (currentIndexIndicator != null) | |
{ | |
var compositor = ElementCompositionPreview.GetElementVisual(this).Compositor; | |
var scrollViewer = GetChildOfType<ScrollViewer>(FlipView); | |
var scrollViewerPropertySet = ElementCompositionPreview.GetScrollViewerManipulationPropertySet(scrollViewer); | |
EnsurePropertySet(); | |
UpdatePropertySetValues(); | |
var expression = compositor.CreateExpressionAnimation(); | |
expression.Expression = "Vector3((scrollViewerPropertySet.Translation.X / propertySet.ScrollViewerWidth) * -1 * propertySet.ControlWidth, 0, 0)"; | |
expression.SetReferenceParameter("scrollViewerPropertySet", scrollViewerPropertySet); | |
expression.SetReferenceParameter("propertySet", _propertySet); | |
var visual = ElementCompositionPreview.GetElementVisual(currentIndexIndicator); | |
visual.StartAnimation(nameof(Visual.Offset), expression); | |
} | |
} | |
private void RemoveExpression() | |
{ | |
var currentIndexIndicator = GetTemplateChild("CurrentIndexIndicator") as UIElement; | |
if (currentIndexIndicator != null) | |
{ | |
var visual = ElementCompositionPreview.GetElementVisual(currentIndexIndicator); | |
visual.StopAnimation(nameof(Visual.Offset)); | |
} | |
} | |
private void UpdateNumItems(int numItems) | |
{ | |
if (_listCount < numItems) | |
{ | |
for (int i = _listCount; i < numItems; i++) | |
{ | |
_dummyList.Add(i + 1); | |
} | |
} | |
else if (_listCount > numItems) | |
{ | |
for (int i = _listCount - 1; i > numItems; i--) | |
{ | |
_dummyList.RemoveAt(i); | |
} | |
} | |
_listCount = numItems; | |
} | |
private void FlipView_SelectionChanged(object sender, SelectionChangedEventArgs e) | |
{ | |
var numItems = FlipView.Items.Count(); | |
UpdateNumItems(numItems); | |
UpdatePropertySetValues(); | |
} | |
private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject | |
{ | |
if (depObj == null) return null; | |
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) | |
{ | |
var child = VisualTreeHelper.GetChild(depObj, i); | |
var result = (child as T) ?? GetChildOfType<T>(child); | |
if (result != null) return result; | |
} | |
return null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Runtime.InteropServices.WindowsRuntime; | |
using Windows.UI.Xaml; | |
using Windows.UI.Xaml.Controls; | |
using Windows.UI.Xaml.Data; | |
using Windows.UI.Xaml.Documents; | |
using Windows.UI.Xaml.Input; | |
using Windows.UI.Xaml.Media; | |
// The Templated Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234235 | |
namespace FlipViewIndicator | |
{ | |
public sealed class FlipViewItemIndicator : Control | |
{ | |
private static readonly DependencyProperty IndexProperty = DependencyProperty.Register(nameof(Index), typeof(int), typeof(FlipViewItemIndicator), new PropertyMetadata(0)); | |
public int Index { get { return (int)GetValue(IndexProperty); } set { SetValue(IndexProperty, value); } } | |
public FlipViewItemIndicator() | |
{ | |
this.DefaultStyleKey = typeof(FlipViewItemIndicator); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<ResourceDictionary | |
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | |
xmlns:local="using:FlipViewIndicator"> | |
<Style TargetType="local:FlipViewIndicator" > | |
<Setter Property="Padding" Value="2.5" /> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="local:FlipViewIndicator"> | |
<Grid HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Background="{TemplateBinding Background}"> | |
<ItemsControl x:Name="ContentItemsControl" | |
HorizontalAlignment="Left" | |
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"> | |
<ItemsControl.ItemsPanel> | |
<ItemsPanelTemplate> | |
<StackPanel Orientation="Horizontal" /> | |
</ItemsPanelTemplate> | |
</ItemsControl.ItemsPanel> | |
<ItemsControl.ItemTemplate> | |
<DataTemplate> | |
<local:FlipViewItemIndicator Index="{Binding}" Margin="{Binding ElementName=CurrentIndexIndicator, Path=Margin}" Foreground="{Binding ElementName=CurrentIndexIndicator, Path=Foreground}"/> | |
</DataTemplate> | |
</ItemsControl.ItemTemplate> | |
</ItemsControl> | |
<local:FlipViewItemIndicator x:Name="CurrentIndexIndicator" Style="{StaticResource CurrentFlipViewItemIndicatorStyle}" HorizontalAlignment="Left" Margin="{TemplateBinding Padding}" Foreground="{TemplateBinding Foreground}"/> | |
</Grid> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
<Style TargetType="local:FlipViewItemIndicator" > | |
<Setter Property="Width" Value="10" /> | |
<Setter Property="Height" Value="10" /> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="local:FlipViewItemIndicator"> | |
<Ellipse Width="{TemplateBinding Width}" | |
Height="{TemplateBinding Height}" | |
Stroke="{TemplateBinding Foreground}" /> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
<Style TargetType="local:FlipViewItemIndicator" x:Key="CurrentFlipViewItemIndicatorStyle" > | |
<Setter Property="Width" Value="10" /> | |
<Setter Property="Height" Value="10" /> | |
<Setter Property="Template"> | |
<Setter.Value> | |
<ControlTemplate TargetType="local:FlipViewItemIndicator"> | |
<Ellipse Width="{TemplateBinding Width}" | |
Height="{TemplateBinding Height}" | |
Fill="{TemplateBinding Foreground}"/> | |
</ControlTemplate> | |
</Setter.Value> | |
</Setter> | |
</Style> | |
</ResourceDictionary> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Quick and dirty FlipView indicator using Composition+XAML
License: