Skip to content

Commit

Permalink
(GH-3910) Add Navigation Index to FlipView
Browse files Browse the repository at this point in the history
  • Loading branch information
punker76 committed Nov 26, 2020
1 parent 809828c commit 1142f4c
Show file tree
Hide file tree
Showing 5 changed files with 379 additions and 58 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,33 @@
Grid.Column="1"
Grid.ColumnSpan="2">
<Label Content="FlipView" Style="{DynamicResource DescriptionHeaderStyle}" />

<StackPanel Orientation="Horizontal">
<CheckBox x:Name="ShowBannerCheckBox"
Margin="2"
Content="Show Banner"
IsChecked="{Binding ElementName=FlipView1st, Path=IsBannerEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="ShowMouseOverCheckBox"
Margin="2"
Content="MouseOver Border"
IsChecked="{Binding ElementName=FlipView1st, Path=MouseHoverBorderEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="CircularNaviCheckBox"
Margin="2"
Content="Circular Navi"
IsChecked="{Binding ElementName=FlipView1st, Path=CircularNavigation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="ShowNaviCheckBox"
Margin="2"
Content="Show Navi Buttons"
IsChecked="{Binding ElementName=FlipView1st, Path=IsNavigationEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="ShowIndexCheckBox"
Margin="2"
Content="Show Navi Index"
IsChecked="{Binding ElementName=FlipView1st, Path=ShowIndex, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</StackPanel>

<Grid Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Group1" />
<ColumnDefinition Width="Auto" SharedSizeGroup="FlipViewSettingsLabel" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
Expand All @@ -120,47 +144,48 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<CheckBox x:Name="ShowBannerCheckBox"
Grid.Row="0"
Grid.Column="0"
Margin="5 2"
Content="Banner"
IsChecked="{Binding ElementName=FlipView1st, Path=IsBannerEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="ShowMouseOverCheckBox"

<Label Grid.Row="0"
Grid.Column="0"
Content="Navigation Button Orientation" />
<ComboBox x:Name="Orientation"
Grid.Row="0"
Grid.Column="1"
Margin="5 2"
Content="MouseOver Border"
IsChecked="{Binding ElementName=FlipView1st, Path=MouseHoverBorderEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="CircularNaviCheckBox"
Grid.Row="1"
Grid.Column="0"
Margin="5 2"
Content="Circular Navi"
IsChecked="{Binding ElementName=FlipView1st, Path=CircularNavigation, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<CheckBox x:Name="ShowNaviCheckBox"
Grid.Row="1"
Grid.Column="1"
Margin="5 2"
Content="Show NaviButtons"
IsChecked="{Binding ElementName=FlipView1st, Path=IsNavigationEnabled, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
<ComboBox x:Name="Orientation"
Grid.Row="2"
Grid.Column="0"
Grid.ColumnSpan="1"
Width="120"
Margin="2"
ItemsSource="{Binding Source={mx:EnumBindingSource {x:Type Orientation}}, Mode=OneTime}"
SelectedValue="{Binding ElementName=FlipView1st, Path=Orientation, FallbackValue=Horizontal, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
SelectedValue="{Binding ElementName=FlipView1st, Path=Orientation, FallbackValue={x:Static Orientation.Horizontal}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

<Label Grid.Row="1"
Grid.Column="0"
Content="Navigation Button Position" />
<ComboBox x:Name="NaviButtonsPosition"
Grid.Row="2"
Grid.Row="1"
Grid.Column="1"
Grid.ColumnSpan="1"
Width="120"
Margin="2"
ItemsSource="{Binding Source={mx:EnumBindingSource {x:Type mah:NavigationButtonsPosition}}, Mode=OneTime}"
SelectedValue="{Binding ElementName=FlipView1st, Path=NavigationButtonsPosition, FallbackValue=Inside, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
SelectedValue="{Binding ElementName=FlipView1st, Path=NavigationButtonsPosition, FallbackValue={x:Static mah:NavigationButtonsPosition.Inside}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />

<Label Grid.Row="2"
Grid.Column="0"
Content="Navigation Index Placement" />
<ComboBox x:Name="IndexPlacement"
Grid.Row="2"
Grid.Column="1"
Width="120"
Margin="2"
ItemsSource="{Binding Source={mx:EnumBindingSource {x:Type mah:NavigationIndexPlacement}}, Mode=OneTime}"
SelectedValue="{Binding ElementName=FlipView1st, Path=IndexPlacement, FallbackValue={x:Static mah:NavigationIndexPlacement.Bottom}, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</Grid>

<mah:FlipView x:Name="FlipView1st"
Height="200"
Margin="0 0 5 0"
Foreground="{DynamicResource MahApps.Brushes.ThemeBackground}">
Foreground="{DynamicResource MahApps.Brushes.ThemeBackground}"
IndexHorizontalAlignment="Right"
IndexPlacement="TopOverItem"
ShowIndex="True">
<mah:FlipView.Items>
<mah:FlipViewItem Background="#2E8DEF"
BannerText="Cupcakes!"
Expand Down Expand Up @@ -188,6 +213,7 @@
</mah:FlipViewItem>
</mah:FlipView.Items>
</mah:FlipView>

<StackPanel HorizontalAlignment="Center"
DataContext="{Binding ElementName=FlipView1st, Mode=OneWay}"
Orientation="Horizontal">
Expand All @@ -204,18 +230,18 @@
</StackPanel>

<Separator Margin="0 5" />

<mah:FlipView x:Name="FlipView2nd"
Height="300"
Margin="0 0 5 0"
BannerText="Databound Items"
CircularNavigation="{Binding ElementName=CircularNaviCheckBox, Path=IsChecked, Mode=OneWay}"
IsBannerEnabled="{Binding ElementName=ShowBannerCheckBox, Path=IsChecked, Mode=OneWay}"
IsNavigationEnabled="{Binding ElementName=ShowNaviCheckBox, Path=IsChecked, Mode=OneWay}"
IndexPlacement="BottomOverItem"
IsBannerEnabled="False"
IsNavigationEnabled="False"
ItemTemplate="{StaticResource ImageDataTemplate}"
ItemsSource="{Binding FlipViewImages, Mode=OneWay}"
MouseHoverBorderEnabled="{Binding ElementName=ShowMouseOverCheckBox, Path=IsChecked, Mode=OneWay}"
NavigationButtonsPosition="{Binding ElementName=NaviButtonsPosition, Path=SelectedValue, Mode=OneWay}"
Orientation="{Binding ElementName=Orientation, Path=SelectedValue, Mode=OneWay}" />
Orientation="{Binding ElementName=Orientation, Path=SelectedValue, Mode=OneWay}"
ShowIndex="True" />
<StackPanel HorizontalAlignment="Center"
DataContext="{Binding ElementName=FlipView2nd, Mode=OneWay}"
Orientation="Horizontal">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,26 +10,32 @@ namespace MetroDemo.Markup
/// <summary>
/// Markup extension for Enum values.
/// </summary>
public class EnumBindingSourceExtension
: MarkupExtension
public class EnumBindingSourceExtension : MarkupExtension
{
private Type _EnumType;
private Type enumType;

/// <summary>
/// Gets or sets the type of the Enum.
/// </summary>
/// <exception cref="ArgumentException">Value is not an Enum type.</exception>
public Type EnumType
{
get { return this._EnumType; }
get => this.enumType;
set
{
if (!Object.Equals(value, this.EnumType))
if (value != this.enumType)
{
if (!Object.Equals(value, null) && !(Nullable.GetUnderlyingType(value) ?? value).IsEnum)
throw new ArgumentException("Type must be an Enum.");
if (null != value)
{
var type = Nullable.GetUnderlyingType(value) ?? value;

this._EnumType = value;
if (!type.IsEnum)
{
throw new ArgumentException("Type must be for an Enum.");
}
}

this.enumType = value;
}
}
}
Expand All @@ -50,23 +56,23 @@ public EnumBindingSourceExtension(Type enumType)
this.EnumType = enumType;
}

/// <summary>
///
/// </summary>
/// <param name="serviceProvider">Object that can provide services for the markup extension.</param>
/// <returns>The values of the Enum.</returns>
/// <exception cref="InvalidOperationException">The type of the Enum is undefined.</exception>
/// <inheritdoc />
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (Object.Equals(this.EnumType, null))
throw new InvalidOperationException("The type of the Enum is undefined.");
if (this.EnumType is null)
{
throw new InvalidOperationException("The EnumType must be specified.");
}

var underlyingEnumType = Nullable.GetUnderlyingType(this.EnumType) ?? this.EnumType;
var enumValues = Enum.GetValues(underlyingEnumType);
if (underlyingEnumType.Equals(this.EnumType))

if (underlyingEnumType == this.EnumType)
{
return enumValues;
}

var nullableEnumValues = Array.CreateInstance(underlyingEnumType, enumValues.Length);
var nullableEnumValues = Array.CreateInstance(underlyingEnumType, enumValues.Length + 1);
enumValues.CopyTo(nullableEnumValues, 1);
return nullableEnumValues;
}
Expand Down
79 changes: 79 additions & 0 deletions src/MahApps.Metro/Controls/FlipView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ namespace MahApps.Metro.Controls
[TemplatePart(Name = PART_BannerGrid, Type = typeof(Grid))]
[TemplatePart(Name = PART_BannerLabel, Type = typeof(Label))]
[StyleTypedProperty(Property = nameof(NavigationButtonStyle), StyleTargetType = typeof(Button))]
[StyleTypedProperty(Property = nameof(IndexItemContainerStyle), StyleTargetType = typeof(ListBoxItem))]
public class FlipView : Selector
{
/// <summary>Identifies the <see cref="MouseHoverBorderBrush"/> dependency property.</summary>
Expand Down Expand Up @@ -77,6 +78,84 @@ public Thickness MouseHoverBorderThickness
set => this.SetValue(MouseHoverBorderThicknessProperty, value);
}

/// <summary>Identifies the <see cref="ShowIndex"/> dependency property.</summary>
public static readonly DependencyProperty ShowIndexProperty
= DependencyProperty.Register(nameof(ShowIndex),
typeof(bool),
typeof(FlipView),
new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));

/// <summary>
/// Gets or sets a value indicating whether the navigation index should be visible.
/// </summary>
public bool ShowIndex
{
get => (bool)this.GetValue(ShowIndexProperty);
set => this.SetValue(ShowIndexProperty, BooleanBoxes.Box(value));
}

/// <summary>Identifies the <see cref="IndexItemContainerStyle"/> dependency property.</summary>
public static readonly DependencyProperty IndexItemContainerStyleProperty
= DependencyProperty.Register(nameof(IndexItemContainerStyle),
typeof(Style),
typeof(FlipView),
new FrameworkPropertyMetadata(default(Style), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));

/// <summary>
/// Gets or sets a style for the navigation index items.
/// </summary>
public Style IndexItemContainerStyle
{
get => (Style)this.GetValue(IndexItemContainerStyleProperty);
set => this.SetValue(IndexItemContainerStyleProperty, value);
}

/// <summary>Identifies the <see cref="IndexPlacement"/> dependency property.</summary>
public static readonly DependencyProperty IndexPlacementProperty
= DependencyProperty.Register(nameof(IndexPlacement),
typeof(NavigationIndexPlacement),
typeof(FlipView),
new FrameworkPropertyMetadata(NavigationIndexPlacement.Bottom, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));

/// <summary>
/// Gets or sets a value specifying where the navigation index should be rendered.
/// </summary>
public NavigationIndexPlacement IndexPlacement
{
get => (NavigationIndexPlacement)this.GetValue(IndexPlacementProperty);
set => this.SetValue(IndexPlacementProperty, value);
}

public static readonly DependencyProperty IndexHorizontalAlignmentProperty
= DependencyProperty.Register(nameof(IndexHorizontalAlignment),
typeof(HorizontalAlignment),
typeof(FlipView),
new FrameworkPropertyMetadata(HorizontalAlignment.Center, FrameworkPropertyMetadataOptions.AffectsArrange));

/// <summary>
/// Gets or sets the horizontal alignment characteristics applied to the navigation index.
/// </summary>
public HorizontalAlignment IndexHorizontalAlignment
{
get => (HorizontalAlignment)this.GetValue(IndexHorizontalAlignmentProperty);
set => this.SetValue(IndexHorizontalAlignmentProperty, (object)value);
}

public static readonly DependencyProperty IndexVerticalAlignmentProperty
= DependencyProperty.Register(nameof(IndexVerticalAlignment),
typeof(VerticalAlignment),
typeof(FlipView),
new FrameworkPropertyMetadata(VerticalAlignment.Center, FrameworkPropertyMetadataOptions.AffectsArrange));

/// <summary>
/// Gets or sets the vertical alignment characteristics applied to the navigation index.
/// </summary>
public VerticalAlignment IndexVerticalAlignment
{
get => (VerticalAlignment)this.GetValue(IndexVerticalAlignmentProperty);
set => this.SetValue(IndexVerticalAlignmentProperty, (object)value);
}

/// <summary>Identifies the <see cref="CircularNavigation"/> dependency property.</summary>
public static readonly DependencyProperty CircularNavigationProperty
= DependencyProperty.Register(nameof(CircularNavigation),
Expand Down
46 changes: 46 additions & 0 deletions src/MahApps.Metro/Controls/NavigationIndexPlacement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

namespace MahApps.Metro.Controls
{
/// <summary>
/// For specifying where the navigation index is placed relative to the <see cref="FlipViewItem"/>.
/// </summary>
public enum NavigationIndexPlacement
{
/// <summary>
/// Index on left side
/// </summary>
Left,
/// <summary>
/// Index on right side
/// </summary>
Right,
/// <summary>
/// Index on top side
/// </summary>
Top,
/// <summary>
/// Index on bottom side
/// </summary>
Bottom,

/// <summary>
/// Index on left side over the item
/// </summary>
LeftOverItem,
/// <summary>
/// Index on right side over the item
/// </summary>
RightOverItem,
/// <summary>
/// Index on top side over the item
/// </summary>
TopOverItem,
/// <summary>
/// Index on bottom side over the item
/// </summary>
BottomOverItem
}
}
Loading

0 comments on commit 1142f4c

Please sign in to comment.