public delegate void FloppyPageNavigateEventHandler(IFloppyPage page, FloppyPageEventArgs e); public delegate void FloppyPageGoBackEventHandler(FloppyPageEventArgs e); public class FloppyPageEventArgs : EventArgs { public FloppyPageEventArgs() { } } public interface IFloppyPage { event FloppyPageNavigateEventHandler Navigate; event FloppyPageGoBackEventHandler GoBack; IFloppyPages IFloppyPages { get; set; } string Title { get; set; } }
public partial class Page1 : Page, IFloppyPage { public event FloppyPageNavigateEventHandler Navigate; public event FloppyPageGoBackEventHandler GoBack; public IFloppyPages IFloppyPages { get; set; } public Page1() : this(null) { } public Page1(object dataContext) { InitializeComponent(); if (dataContext != null) this.DataContext = dataContext; else this.DataContext = this; Title = " "; } private void NavigateTo_MainPage(object sender, RoutedEventArgs e) { if (Navigate != null) Navigate(new MainPage(DataContext), new FloppyPageEventArgs()); } private void NavigateTo_Page2(object sender, RoutedEventArgs e) { if (Navigate != null) Navigate(new Page2(DataContext), new FloppyPageEventArgs()); } private void NavigateTo_Page3(object sender, RoutedEventArgs e) { if (Navigate != null) Navigate(new Page3(DataContext), new FloppyPageEventArgs()); } private void Button_GoBack(object sender, RoutedEventArgs e) { if (GoBack != null) GoBack(new FloppyPageEventArgs()); } }
public interface IFloppyPages { IFloppyPage FirstPage { get; set; } IFloppyPage CurrentPage { get; set; } int JournalCount { get; set; } void Navigate(IFloppyPage page); bool GoBack(); bool CanGoBack { get; set; } }
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:UFC.UI.Controls"> <Thickness x:Key="Dynamic.ThicknessAnimation.Margin">10, 0, -10, 0</Thickness> <Style TargetType="local:FloppyPages"> <Style.Setters> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="local:FloppyPages"> <Grid Name="mainGrid"> <Grid Name="grid1"> <Frame Name="frame1" NavigationUIVisibility="Hidden"/> </Grid> <Grid Name="grid2"> <Frame Name="frame2" NavigationUIVisibility="Hidden"/> </Grid> <Grid.Resources> <BeginStoryboard x:Key="grid1Animation"> <Storyboard> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid1" Storyboard.TargetProperty="Margin" From="{DynamicResource Dynamic.ThicknessAnimation.Margin}" To="0"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid2" Storyboard.TargetProperty="Margin" From="0" To="-100, 20, 100, 20"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Key="grid2Animation"> <Storyboard> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid2" Storyboard.TargetProperty="Margin" From="{DynamicResource Dynamic.ThicknessAnimation.Margin}" To="0"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid1" Storyboard.TargetProperty="Margin" From="0" To="-100, 20, 100, 20"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Key="grid3Animation"> <Storyboard> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid1" Storyboard.TargetProperty="Margin" From="0" To="{DynamicResource Dynamic.ThicknessAnimation.Margin}"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid2" Storyboard.TargetProperty="Margin" From="-100, 20, 100, 20" To="0"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> </Storyboard> </BeginStoryboard> <BeginStoryboard x:Key="grid4Animation"> <Storyboard> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid2" Storyboard.TargetProperty="Margin" From="0" To="{DynamicResource Dynamic.ThicknessAnimation.Margin}"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> <ThicknessAnimation Duration="0:0:0.8" Storyboard.TargetName="grid1" Storyboard.TargetProperty="Margin" From="-100, 20, 100, 20" To="0"> <ThicknessAnimation.EasingFunction> <ElasticEase EasingMode="EaseOut" Oscillations="1"/> </ThicknessAnimation.EasingFunction> </ThicknessAnimation> </Storyboard> </BeginStoryboard> </Grid.Resources> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style.Setters> </Style> </ResourceDictionary>
using System; using System.Collections.Generic; using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Media.Animation; namespace UFC.UI { #region DefaultPage /// <summary> /// . /// </summary> internal class DefaultPage : IFloppyPage { public event FloppyPageNavigateEventHandler Navigate; public event FloppyPageGoBackEventHandler GoBack; public IFloppyPages IFloppyPages { get; set; } public string Title { get; set; } public DefaultPage() { Title = " "; } } #endregion #region IFloppyPage public delegate void FloppyPageNavigateEventHandler(IFloppyPage page, FloppyPageEventArgs e); public delegate void FloppyPageGoBackEventHandler(FloppyPageEventArgs e); public class FloppyPageEventArgs : EventArgs { public FloppyPageEventArgs() { } } public interface IFloppyPage { event FloppyPageNavigateEventHandler Navigate; event FloppyPageGoBackEventHandler GoBack; IFloppyPages IFloppyPages { get; set; } string Title { get; set; } } #endregion #region IFloppyPages public interface IFloppyPages { IFloppyPage FirstPage { get; set; } IFloppyPage CurrentPage { get; set; } int JournalCount { get; set; } void Navigate(IFloppyPage page); bool GoBack(); bool CanGoBack { get; set; } } #endregion } namespace UFC.UI.Controls { #region FloppyPages public class FloppyPages : Control, IFloppyPages, INotifyPropertyChanged { #region Private Members private bool GridNumber = false; private bool IsDoneAnimation = true; private bool IsDoneInitialization = false; private List<IFloppyPage> journal = new List<IFloppyPage>(); private Frame frame1 = null; private Frame frame2 = null; private Grid mainGrid = null; private Grid grid1 = null; private Grid grid2 = null; private BeginStoryboard animation1 = null; private BeginStoryboard animation2 = null; private BeginStoryboard animation3 = null; private BeginStoryboard animation4 = null; #endregion #region Constructors static FloppyPages() { DefaultStyleKeyProperty.OverrideMetadata(typeof(FloppyPages), new FrameworkPropertyMetadata(typeof(FloppyPages))); FloppyPages.NavigatedRoutedEvent = EventManager.RegisterRoutedEvent("Navigated", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FloppyPages)); FloppyPages.WentBackRoutedEvent = EventManager.RegisterRoutedEvent("WentBack", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(FloppyPages)); } public FloppyPages() { } #endregion #region Public Dependency Properties public static readonly DependencyProperty FirstPageProperty = DependencyProperty.RegisterAttached("FirstPage", typeof(IFloppyPage), typeof(FloppyPages)); #endregion #region Public Properties public IFloppyPage FirstPage { get { return (IFloppyPage)GetValue(FirstPageProperty); } set { SetValue(FirstPageProperty, value); OnFirstPage(FirstPage); OnPropertyChanged("FirstPage"); } } #endregion #region Public RoutedEvents public static readonly RoutedEvent NavigatedRoutedEvent; public static readonly RoutedEvent WentBackRoutedEvent; #endregion #region Public Events public event RoutedEventHandler Navigated { add { base.AddHandler(FloppyPages.NavigatedRoutedEvent, value); } remove { base.RemoveHandler(FloppyPages.NavigatedRoutedEvent, value); } } public event RoutedEventHandler WentBack { add { base.AddHandler(FloppyPages.WentBackRoutedEvent, value); } remove { base.RemoveHandler(FloppyPages.WentBackRoutedEvent, value); } } #endregion #region Public Members public IFloppyPage CurrentPage { get { if (journal.Count > 0) return journal[journal.Count - 1]; else return null; } set { /* Binding*/ } } public int JournalCount { get { return journal.Count; } set { /* Binding*/ } } public void Navigate(IFloppyPage page) { Start_Navigate(page); } public bool GoBack() { return Start_GoBack(); } public bool CanGoBack { get { if (journal.Count > 1) return true; else return false; } set { /* Binding*/ } } #endregion #region Private OnFirstPage private void OnFirstPage(IFloppyPage page) { if (page != null && IsDoneInitialization) { if (GridNumber) frame1.Navigate(page); else frame2.Navigate(page); page.Navigate += Page_Navigate; page.GoBack += Page_GoBack; journal.Clear(); journal.Add(page); OnPropertyChanged("JournalCount"); OnPropertyChanged("CanGoBack"); OnPropertyChanged("CurrentPage"); } } #endregion #region Public OnApplyTemplate public override void OnApplyTemplate() { base.OnApplyTemplate(); mainGrid = GetTemplateChild("mainGrid") as Grid; grid1 = GetTemplateChild("grid1") as Grid; if (grid1 != null) grid1.Margin = new Thickness(0); grid2 = GetTemplateChild("grid2") as Grid; if (grid2 != null) grid2.Margin = new Thickness(this.ActualWidth, 0, (-1 * this.ActualWidth), 0); frame1 = GetTemplateChild("frame1") as Frame; frame2 = GetTemplateChild("frame2") as Frame; animation1 = mainGrid.Resources["grid1Animation"] as BeginStoryboard; animation2 = mainGrid.Resources["grid2Animation"] as BeginStoryboard; animation3 = mainGrid.Resources["grid3Animation"] as BeginStoryboard; animation4 = mainGrid.Resources["grid4Animation"] as BeginStoryboard; if (animation1 != null) if (animation1.Storyboard != null) animation1.Storyboard.Completed += NewGridMargin_Completed; if (animation2 != null) if (animation2.Storyboard != null) animation2.Storyboard.Completed += NewGridMargin_Completed; if (animation3 != null) if (animation3.Storyboard != null) animation3.Storyboard.Completed += OldGridMargin_Completed; if (animation4 != null) if (animation4.Storyboard != null) animation4.Storyboard.Completed += OldGridMargin_Completed; if (mainGrid != null) { mainGrid.SizeChanged += (sender, e) => { Application.Current.Resources["Dynamic.ThicknessAnimation.Margin"] = new Thickness(this.ActualWidth, 0, -1 * this.ActualWidth, 0); }; } IsDoneInitialization = true; FirstPage = new DefaultPage(); } #endregion #region Private Events private void Page_Navigate(IFloppyPage page, FloppyPageEventArgs e) { Start_Navigate(page); } private void Page_GoBack(FloppyPageEventArgs e) { Start_GoBack(); } private void NewGridMargin_Completed(object sender, EventArgs e) { Set_NewMargin(); } private void OldGridMargin_Completed(object sender, EventArgs e) { Set_OldMargin(); } #endregion #region Private Navigate private void Start_Navigate(IFloppyPage page) { if (page != null && IsDoneAnimation) { IsDoneAnimation = false; GridNumber = !GridNumber; page.Navigate += Page_Navigate; page.GoBack += Page_GoBack; if (!GridNumber) { animation1.Storyboard.Stop(); frame2.Navigate(page); Panel.SetZIndex(grid1, 0); Panel.SetZIndex(grid2, 1); grid2.Visibility = Visibility.Visible; animation2.Storyboard.Begin(); } else { animation2.Storyboard.Stop(); frame1.Navigate(page); Panel.SetZIndex(grid2, 0); Panel.SetZIndex(grid1, 1); grid1.Visibility = Visibility.Visible; animation1.Storyboard.Begin(); } journal.Add(page); OnPropertyChanged("JournalCount"); OnPropertyChanged("CurrentPage"); OnPropertyChanged("CanGoBack"); base.RaiseEvent(new RoutedEventArgs(FloppyPages.NavigatedRoutedEvent, this)); } } private void Set_NewMargin() { if (!GridNumber) { grid2.Margin = new Thickness(0); grid1.Margin = new Thickness(this.ActualWidth, 0, (-1 * this.ActualWidth), 0); grid1.Visibility = Visibility.Hidden; } else { grid1.Margin = new Thickness(0); grid2.Margin = new Thickness(this.ActualWidth, 0, (-1 * this.ActualWidth), 0); grid2.Visibility = Visibility.Hidden; } IsDoneAnimation = true; } #endregion #region Private GoBack private bool Start_GoBack() { if (journal.Count > 1 && IsDoneAnimation) { IsDoneAnimation = false; GridNumber = !GridNumber; journal[journal.Count - 1].Navigate -= Page_Navigate; journal[journal.Count - 1].GoBack -= Page_GoBack; grid1.Visibility = Visibility.Visible; grid2.Visibility = Visibility.Visible; if (!GridNumber) { animation4.Storyboard.Stop(); grid2.Margin = new Thickness(0); frame2.Navigate(journal[journal.Count - 2]); animation3.Storyboard.Begin(); } else { animation3.Storyboard.Stop(); grid1.Margin = new Thickness(0); frame1.Navigate(journal[journal.Count - 2]); animation4.Storyboard.Begin(); } journal.Remove(journal[journal.Count - 1]); OnPropertyChanged("JournalCount"); OnPropertyChanged("CurrentPage"); OnPropertyChanged("CanGoBack"); base.RaiseEvent(new RoutedEventArgs(FloppyPages.WentBackRoutedEvent, this)); return true; } else return false; } private void Set_OldMargin() { if (!GridNumber) { Panel.SetZIndex(grid1, 0); Panel.SetZIndex(grid2, 1); grid1.Margin = new Thickness(this.ActualWidth, 0, (-1 * this.ActualWidth), 0); grid1.Visibility = Visibility.Hidden; } else { Panel.SetZIndex(grid1, 1); Panel.SetZIndex(grid2, 0); grid2.Margin = new Thickness(this.ActualWidth, 0, (-1 * this.ActualWidth), 0); grid2.Visibility = Visibility.Hidden; } IsDoneAnimation = true; } #endregion #region INotifyPropertyChanged Members public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); } #endregion } #endregion }
if (mainGrid != null) { mainGrid.SizeChanged += (sender, e) => { Application.Current.Resources["Dynamic.ThicknessAnimation.Margin"] = new Thickness(this.ActualWidth, 0, -1 * this.ActualWidth, 0); }; }
using System.Windows; using UFC.Pages; namespace UFC { public partial class Browser : Window { public Browser() { InitializeComponent(); } private void floppyPages_Navigated(object sender, RoutedEventArgs e) { if (floppyPages.CanGoBack) BackButton.Visibility = Visibility.Visible; } private void floppyPages_WentBack(object sender, RoutedEventArgs e) { if (!floppyPages.CanGoBack) BackButton.Visibility = Visibility.Hidden; } private void Button_GoBack(object sender, RoutedEventArgs e) { floppyPages.GoBack(); } private void Window_Loaded(object sender, RoutedEventArgs e) { floppyPages.FirstPage = new MainPage(); } } }
<Window x:Class="UFC.Browser" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ufc="clr-namespace:UFC.UI.Controls;assembly=UFC.UI" Title="UFC" Height="640" Width="380" Loaded="Window_Loaded"> <Grid Background="LightGray"> <Grid.RowDefinitions> <RowDefinition Height="40"/> <RowDefinition/> </Grid.RowDefinitions> <ufc:FloppyPages Grid.Row="1" Name="floppyPages" Navigated="floppyPages_Navigated" WentBack="floppyPages_WentBack"/> <Grid Grid.Row="0" Background="LightGray"> <Grid.ColumnDefinitions> <ColumnDefinition Width="40"/> <ColumnDefinition Width="1*"/> <ColumnDefinition Width="40"/> </Grid.ColumnDefinitions> <TextBox Grid.Column="1" VerticalContentAlignment="Center" HorizontalContentAlignment="Center" IsReadOnly="True" Background="Transparent" FontSize="20" Text="{Binding ElementName=floppyPages, Path=CurrentPage.Title, UpdateSourceTrigger=PropertyChanged}"/> <Button Name="MenuButton" Grid.Column="0" Visibility="Visible"> <Path Margin="5" Stretch="UniformToFill" Fill="Black" Data="F1 M 19,23L 27,23L 27,31L 19,31L 19,23 ZM 19,34L 27,34L 27,42L 19,42L 19,34 ZM 31,23L 57,23L 57,31L 31,31L 31,23 ZM 19,45L 27,45L 27,53L 19,53L 19,45 ZM 31,34L 57,34L 57,42L 31,42L 31,34 ZM 31,45L 57,45L 57,53L 31,53L 31,45 Z "/> </Button> <Button Name="BackButton" Grid.Column="0" Visibility="Hidden" Click="Button_GoBack"> <Path Margin="5,9" Stretch="UniformToFill" Fill="Black" Data="F1 M 18.0147,41.5355C 16.0621,39.5829 16.0621,36.4171 18.0147,34.4645L 26.9646,25.5149C 28.0683,24.4113 29,24 31,24L 52,24C 54.7614,24 57,26.2386 57,29L 57,47C 57,49.7614 54.7614,52 52,52L 31,52C 29,52 28.0683,51.589 26.9646,50.4854L 18.0147,41.5355 ZM 47.5281,42.9497L 42.5784,37.9999L 47.5281,33.0502L 44.9497,30.4717L 40,35.4215L 35.0502,30.4717L 32.4718,33.0502L 37.4215,37.9999L 32.4718,42.9497L 35.0502,45.5281L 40,40.5783L 44.9497,45.5281L 47.5281,42.9497 Z "/> </Button> <Button Grid.Column="2"> <Path Margin="5,9" Stretch="UniformToFill" Fill="Black" Data="F1 M 57.9853,41.5355L 49.0354,50.4854C 47.9317,51.589 47,52 45,52L 24,52C 21.2386,52 19,49.7614 19,47L 19,29C 19,26.2386 21.2386,24 24,24L 45,24C 47,24 47.9317,24.4113 49.0354,25.5149L 57.9853,34.4645C 59.9379,36.4171 59.9379,39.5829 57.9853,41.5355 ZM 28.4719,42.9497L 31.0503,45.5281L 36,40.5784L 40.9498,45.5281L 43.5282,42.9497L 38.5785,37.9999L 43.5282,33.0502L 40.9498,30.4718L 36,35.4215L 31.0503,30.4718L 28.4719,33.0502L 33.4216,37.9999L 28.4719,42.9497 Z "/> </Button> </Grid> </Grid> </Window>
Source: https://habr.com/ru/post/317896/