using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Windows.Threading; namespace HistoryDLL { /// /// HomePage.xaml 的互動邏輯 /// public partial class HomePage : UserControl { public event EventHandler OnLoadProgessComplete; DispatcherTimer dt = new DispatcherTimer(); Storyboard progressWidthStoryBoard = new Storyboard(); Storyboard progressHeightStoryBoard = new Storyboard(); DoubleAnimation dbOffsetWidth; DoubleAnimation dbOffsetHeight; //亂數飛入 private Random rnd = new Random(Guid.NewGuid().GetHashCode()); //Block size private int blockWidth = 0; private int blockHeight = 0; private int nonesize = 0; //事件數量 private int eventTotalCount = 0; //載入完成數量 private int eventLoadCount = 0; //歷史牆控制項 private Grid HistoryWallControl = new Grid(); //區塊大小設定 private static int cutForTwowidth = 289; private static int cutForTwoheight = 224; private static int cutForSixwidth = 209; private static int cutForSixheight = 157; //紀錄顯示畫面的年份 public List xmlDataList = new List(); public List borderlist = new List(); public List myborderList = new List(); public int StoryBoardTime = 200; public int DelayTimeRate = 100; public int HistoryWallTime = 600; SolidColorBrush sb = new SolidColorBrush(ConfigSettingClass.TimelineCollect.BackgroundColor); private SolidColorBrush TextBlockExtendColor = new SolidColorBrush(ConfigSettingClass.TimelineCollect.TextColor); public HomePage(int width, int height) { InitializeComponent(); this.uxLoadBar.Width = width; this.uxLoadBar.Height = height; if (GlobalFunction.isSolutionUsing4K) { cutForTwowidth *= 2; cutForTwoheight *= 2; cutForSixwidth *= 2; cutForSixheight *= 2; uxProgressBar.Height *= 2; uxProgressBar.Margin = new Thickness(0, uxProgressBar.Margin.Top * 2, 0, 0); } SetStoryboardMotionX(); SetStoryboardMotionY(); uxProgressBar.Background = sb; uxLoadingProgress.LoadingCompleted += new EventHandler(uxLoadingProgress_LoadingCompleted); uxLoadingProgress.Start(); uxLoadingProgress.Minimum = 0; uxLoadingProgress.Maximum = 100; } private void uxLoadingProgress_LoadingCompleted(object sender, EventArgs e) { progressWidthStoryBoard.Stop(); dbOffsetWidth.From = this.uxProgressBar.Width; dbOffsetWidth.To = (eventLoadCount * this.uxLoadBar.Width) / eventTotalCount; progressWidthStoryBoard.Begin(); uxLoadingProgress.Visibility = System.Windows.Visibility.Collapsed; CloseLoadingMap(); OnLoadProgessComplete?.Invoke(this,null); } private void CloseLoadingMap() { for (int i = 0; i < 60; i++) { Path path = new Path(); path = FindName("m" + string.Format("{0:D2}", i)) as Path; path.Visibility = System.Windows.Visibility.Collapsed; } Grid gd = new Grid(); gd = FindName("m60") as Grid; gd.Visibility = System.Windows.Visibility.Collapsed; } public void SetBlockCommonSetting(int width, int height, int nousesize) { blockWidth = width; blockHeight = height; nonesize = nousesize; if (GlobalFunction.isSolutionUsing4K) { //blockWidth *= 2; //blockHeight *= 2; //nonesize *= 2; } } private void HistoryWallStart() { dt.Interval = TimeSpan.FromMilliseconds(HistoryWallTime); dt.Tick += new EventHandler(dt_Tick); dt.Start(); } void dt_Tick(object sender, EventArgs e) { dt.Stop(); //將歷史牆提到最上層 Canvas.SetZIndex(HistoryWallControl, 1); OpacityFadeInAndOut(); } //設定時間讓歷史牆的Opacity漸改變 private void OpacityFadeInAndOut() { Storyboard historywallshow = new Storyboard(); DoubleAnimation dbOffset = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(200), EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseIn, Exponent = 3, }, From = 0, To = 1 }; Storyboard.SetTarget(dbOffset, HistoryWallControl); Storyboard.SetTargetProperty(dbOffset, new PropertyPath(Grid.OpacityProperty)); historywallshow.Completed += new EventHandler(historywallshow_Completed); historywallshow.Children.Add(dbOffset); historywallshow.FillBehavior = FillBehavior.HoldEnd; historywallshow.Begin(); } void historywallshow_Completed(object sender, EventArgs e) { HistoryWallControl.Opacity = 1; //結束後~將歷史牆降到最下層~不然點擊會點不到 Canvas.SetZIndex(HistoryWallControl, 0); uxLoadBar.Opacity = 0; ReleaseAllSetting(); } //釋放所有資源 private void ReleaseAllSetting() { xmlDataList = new List(); borderlist = new List(); myborderList = new List(); progressWidthStoryBoard = new Storyboard(); progressHeightStoryBoard = new Storyboard(); uxLoadBar.Visibility = System.Windows.Visibility.Collapsed; } //將每個年分區塊顯示出來~並且播放飛入的動畫 private void ShowBlock() { uxProgressBar.Opacity = 0; uxGradientStop.Offset = 1; for (int i = 0; i < borderlist.Count; i++) { uxLoadBar.Children.Add(borderlist[i]); } this.Refresh(); for (int i = 0; i < myborderList.Count; i++) { uxLoadBar.Children.Add(myborderList[i]); myborderList[i].FlyAnimationStart(); this.Refresh(); } } /// /// 設定每個Block的位置 /// private void SetBlockPos() { int marginbtm = 250; if (GlobalFunction.isSolutionUsing4K) marginbtm *= 2; //設定每個年分區塊的位置 for (int count = 0; count < borderlist.Count; count++) { //先設定第一個 if (count == 0) { borderlist[count].Margin = new Thickness(-nonesize, 0, 0, marginbtm); continue; } borderlist[count].Margin = new Thickness(borderlist[count - 1].Margin.Left + blockWidth, 0, 0, marginbtm); } } /// /// 根據事件的數量~新建出Image並設定其動畫 /// private void SetEventAnimation() { int eventcount = xmlDataList.Count; for (int index = 0; index < eventcount; index++) { //如果該年只有兩個事件~的動畫位置 if (xmlDataList[index].monthclassList.Count <= 2) { for (int i = 0; i < xmlDataList[index].monthclassList.Count; i++) { int randonvalue = rnd.Next(0, 401); if (i == 0) { int fitValue = 92; if (GlobalFunction.isSolutionUsing4K) fitValue *= 2; //區塊寬度, 區塊高度, 該區塊的起始位置 (左 + 底), 該區塊飛入後的終點位置 (左 + 底) + 動畫時間, 動畫的延遲時間 //91 : 77 (年份寬度) + "上下"區塊間的Thickness寬度 10 + 切割該區塊的係數 4 MyBorder newimage = new MyBorder(cutForTwowidth, cutForTwoheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - cutForTwowidth) / 2, borderlist[index].Margin.Bottom + fitValue, StoryBoardTime, randonvalue); myborderList.Add(newimage); } else { int fitValue = 103; if (GlobalFunction.isSolutionUsing4K) fitValue *= 2; //97 : 77 (年份寬度) + "上下"區塊間的Thickness寬度 10 + 切割下區塊的係數 (上下) 4 + 往上多飛一個Thickness寬度 5 + 切割該區塊的係數(下) 2 MyBorder newimage = new MyBorder(cutForTwowidth, cutForTwoheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - cutForTwowidth) / 2, borderlist[index].Margin.Bottom + fitValue + (i * cutForTwoheight), StoryBoardTime, randonvalue); myborderList.Add(newimage); } } } //如果該年超過兩個事件~則動畫位置 else { for (int i = 0; i < xmlDataList[index].monthclassList.Count; i++) { int randonvalue = rnd.Next(0, 401); if (i > 5) { break; } //排(橫) int Row = i / 2; //列(直) int colu = i % 2; int thicknessValue = 5; int fitXvalue = 210; int fitYvalue = 91; if (GlobalFunction.isSolutionUsing4K) { thicknessValue *= 2; fitXvalue *= 2; fitYvalue *= 2; } if (Row == 0) { if (colu == 0) { MyBorder newimage = new MyBorder(cutForSixwidth, cutForSixheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - ((fitXvalue + thicknessValue) * 2)) / 2, borderlist[index].Margin.Bottom + fitYvalue, StoryBoardTime, randonvalue); myborderList.Add(newimage); } else { //225 : cutForSixwidth 210 + 該區塊的"左右"的Thickness 10 + 右邊區塊的"左"Thickness 5 MyBorder newimage = new MyBorder(cutForSixwidth, cutForSixheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - ((fitXvalue + thicknessValue) * 2)) / 2 + ((fitXvalue + thicknessValue * 2)), borderlist[index].Margin.Bottom + fitYvalue, StoryBoardTime, randonvalue); myborderList.Add(newimage); } } else { if (colu == 0) { //14 : 區塊"上下"的Thickness 10 + 切割該區塊的係數 4 MyBorder newimage = new MyBorder(cutForSixwidth, cutForSixheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - ((fitXvalue + thicknessValue) * 2)) / 2, borderlist[index].Margin.Bottom + fitYvalue + (Row * cutForSixheight) + (11 * Row), StoryBoardTime, randonvalue); myborderList.Add(newimage); } else { //225 : cutForSixwidth 210 + 該區塊的"左右"的Thickness 10 + 右邊區塊的"左"Thickness 5 MyBorder newimage = new MyBorder(cutForSixwidth, cutForSixheight, borderlist[index].Margin.Left, borderlist[index].Margin.Bottom, borderlist[index].Margin.Left + (blockWidth - ((fitXvalue + thicknessValue) * 2)) / 2 + (fitXvalue + thicknessValue * 2), borderlist[index].Margin.Bottom + fitYvalue + (Row * cutForSixheight) + (11 * Row), StoryBoardTime, randonvalue); myborderList.Add(newimage); } } } } } } #region X 與 Y 軸動畫 private void SetStoryboardMotionX() { progressWidthStoryBoard = new Storyboard(); dbOffsetWidth = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(1000), EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseIn, Exponent = 0.3 }, }; Storyboard.SetTarget(dbOffsetWidth, this.uxProgressBar); Storyboard.SetTargetProperty(dbOffsetWidth, new PropertyPath(Grid.WidthProperty)); progressWidthStoryBoard.Children.Add(dbOffsetWidth); progressWidthStoryBoard.Completed += new EventHandler(progressStoryBoard_Completed); progressWidthStoryBoard.FillBehavior = FillBehavior.HoldEnd; } void progressStoryBoard_Completed(object sender, EventArgs e) { progressHeightStoryBoard.Begin(); } public void SetEventCount(int count) { eventTotalCount = count; } private void SetStoryboardMotionY() { progressHeightStoryBoard = new Storyboard(); int aniHeight = 77; if (GlobalFunction.isSolutionUsing4K) aniHeight *= 2; dbOffsetHeight = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(500), EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseIn, Exponent = 0.3 }, From = this.uxProgressBar.Height, To = aniHeight, }; Storyboard.SetTarget(dbOffsetHeight, this.uxProgressBar); Storyboard.SetTargetProperty(dbOffsetHeight, new PropertyPath(Grid.HeightProperty)); progressHeightStoryBoard.Children.Add(dbOffsetHeight); progressHeightStoryBoard.Completed += new EventHandler(progressHeightStoryBoard_Completed); progressHeightStoryBoard.FillBehavior = FillBehavior.HoldEnd; } void progressHeightStoryBoard_Completed(object sender, EventArgs e) { while (true) { if (xmlDataList.Count > 0) { for (int i = 0; i < xmlDataList.Count; i++) { Border bd = new Border(); TextBlock tb = new TextBlock(); tb.Foreground = TextBlockExtendColor; tb.FontSize = GlobalFunction.isSolutionUsing4K ? 40 * 1.5 : 40; tb.TextTrimming = TextTrimming.CharacterEllipsis; tb.VerticalAlignment = System.Windows.VerticalAlignment.Center; tb.HorizontalAlignment = System.Windows.HorizontalAlignment.Center; string langStr = xmlDataList[i].yearlan1; if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 1) { langStr = xmlDataList[i].yearlan2; } else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 2) { langStr = xmlDataList[i].yearlan3; } else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 3) { langStr = xmlDataList[i].yearlan4; } tb.Text = langStr; bd.Child = tb; bd.Width = blockWidth; bd.Height = blockHeight; bd.BorderThickness = new Thickness(5); bd.BorderBrush = Brushes.Transparent; bd.Background = sb; bd.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; bd.VerticalAlignment = System.Windows.VerticalAlignment.Bottom; borderlist.Add(bd); } break; } } //在整個動畫結束後~代表資料已經載入完成此時才知道顯示在前面個年份是哪幾個~ //設定每個Block的位置 SetBlockPos(); //根據事件的數量~新建出Image並設定其動畫 SetEventAnimation(); //顯示區塊及動畫 ShowBlock(); //設定時間歷史牆啟動 HistoryWallStart(); } #endregion //觸發整個動畫起始位置 public void AddLoadCount() { eventLoadCount++; RunProgressStoryboard(); } private void RunProgressStoryboard() { uxLoadingProgress.EndValue = ((double)eventLoadCount / (double)eventTotalCount) * 100d; } internal void SetHistoryWallControl(Grid uxCyclicGrid) { HistoryWallControl = uxCyclicGrid; } } /// 擴充uiElement類別的方法 /// 為uiElement類別增加element即時重整的功能 public static class uiElementExtension { private static Action NoDoDelegate = delegate () { }; public static void Refresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.Render, NoDoDelegate); } public static void WebRefresh(this UIElement uiElement) { uiElement.Dispatcher.Invoke(DispatcherPriority.ContextIdle, NoDoDelegate); } } //自訂義Image public class MyBorder : Border { //區塊大小 public int borderwidth; public int borderheight; //動畫起始位置 public double beginPosX; public double beginPosY; //動畫結束位置 public double endPosX; public double endPosY; public Storyboard myborderStoryboard = new Storyboard(); //動畫運行時間 public int storyboardTime; //動畫的Delay time 讓整個飛入的物件不會同時飛 public int storyboardBeginTime; private SolidColorBrush RotateContainColor = new SolidColorBrush(ConfigSettingClass.EventCollect.BackgroundColor); public MyBorder(int width, int height, double bPosX, double bPosY, double ePosX, double ePosY, int StoryboardTime, int STbeginTime) { borderwidth = width; borderheight = height; beginPosX = bPosX; beginPosY = bPosY; endPosX = ePosX; endPosY = ePosY; storyboardTime = StoryboardTime; storyboardBeginTime = STbeginTime; this.HorizontalAlignment = System.Windows.HorizontalAlignment.Left; this.VerticalAlignment = System.Windows.VerticalAlignment.Bottom; this.Background = RotateContainColor; this.BorderThickness = new Thickness(0); this.Opacity = 0; SetTheFlyStoryboard(); } public void FlyAnimationStart() { this.Opacity = 1; myborderStoryboard.Begin(); } //飛入的動畫 private void SetTheFlyStoryboard() { ThicknessAnimation dbOffset = new ThicknessAnimation() { Duration = TimeSpan.FromMilliseconds(storyboardTime), EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, }, From = new Thickness(beginPosX, 0, 0, beginPosY), To = new Thickness(endPosX, 0, 0, endPosY) }; DoubleAnimation dbOffsetWidth = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(storyboardTime), EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, }, From = 0, To = borderwidth }; DoubleAnimation dbOffsetHeight = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(storyboardTime), EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, }, From = 0, To = borderheight }; DoubleAnimation dbOffsetOpacity = new DoubleAnimation() { Duration = TimeSpan.FromMilliseconds(storyboardTime), EasingFunction = new CircleEase() { EasingMode = EasingMode.EaseOut, }, From = 0, To = 1 }; Storyboard.SetTarget(dbOffset, this); Storyboard.SetTarget(dbOffsetWidth, this); Storyboard.SetTarget(dbOffsetHeight, this); Storyboard.SetTarget(dbOffsetOpacity, this); Storyboard.SetTargetProperty(dbOffset, new PropertyPath(Border.MarginProperty)); Storyboard.SetTargetProperty(dbOffsetWidth, new PropertyPath(Border.WidthProperty)); Storyboard.SetTargetProperty(dbOffsetHeight, new PropertyPath(Border.HeightProperty)); Storyboard.SetTargetProperty(dbOffsetOpacity, new PropertyPath(Border.OpacityProperty)); myborderStoryboard.BeginTime = TimeSpan.FromMilliseconds(storyboardBeginTime); myborderStoryboard.Children.Add(dbOffset); myborderStoryboard.Children.Add(dbOffsetWidth); myborderStoryboard.Children.Add(dbOffsetHeight); myborderStoryboard.Children.Add(dbOffsetOpacity); myborderStoryboard.FillBehavior = FillBehavior.HoldEnd; } } }