Browse Source

Add project files.

Robert 3 years ago
parent
commit
39f4b50e92
100 changed files with 7017 additions and 0 deletions
  1. 49 0
      Bellwether.sln
  2. 21 0
      Bellwether/App.config
  3. 9 0
      Bellwether/App.xaml
  4. 17 0
      Bellwether/App.xaml.cs
  5. 174 0
      Bellwether/Bellwether.csproj
  6. BIN
      Bellwether/DLL/ICSharpCode.SharpZipLib.dll
  7. BIN
      Bellwether/DLL/Microsoft.WindowsAPICodePack.Shell.dll
  8. BIN
      Bellwether/DLL/Microsoft.WindowsAPICodePack.dll
  9. BIN
      Bellwether/DLL/NLPlaneRotator.dll
  10. BIN
      Bellwether/DLL/Newtonsoft.Json.dll
  11. BIN
      Bellwether/DLL/SocketTransfer.dll
  12. 28 0
      Bellwether/MainWindow.xaml
  13. 81 0
      Bellwether/MainWindow.xaml.cs
  14. 41 0
      Bellwether/Pages/ucFrontPage.xaml
  15. 127 0
      Bellwether/Pages/ucFrontPage.xaml.cs
  16. 47 0
      Bellwether/Pages/ucHistoryHW.xaml
  17. 71 0
      Bellwether/Pages/ucHistoryHW.xaml.cs
  18. 55 0
      Bellwether/Properties/AssemblyInfo.cs
  19. 70 0
      Bellwether/Properties/Resources.Designer.cs
  20. 117 0
      Bellwether/Properties/Resources.resx
  21. 50 0
      Bellwether/Properties/Settings.Designer.cs
  22. 12 0
      Bellwether/Properties/Settings.settings
  23. 203 0
      Bellwether/Utility/GlobalFunction.cs
  24. 129 0
      Bellwether/Utility/SbAssist.cs
  25. 75 0
      Bellwether/Utility/Setting.cs
  26. 459 0
      Bellwether/Utility/UpdateProcess.cs
  27. 79 0
      Bellwether/app.manifest
  28. 4 0
      Bellwether/packages.config
  29. 15 0
      Bellwether/ucMainControlPage.xaml
  30. 121 0
      Bellwether/ucMainControlPage.xaml.cs
  31. 21 0
      BellwetherBackend/App.config
  32. 18 0
      BellwetherBackend/App.xaml
  33. 17 0
      BellwetherBackend/App.xaml.cs
  34. 4 0
      BellwetherBackend/Assets/appbar.control.add.xaml
  35. 4 0
      BellwetherBackend/Assets/appbar.control.connect.xaml
  36. 4 0
      BellwetherBackend/Assets/appbar.control.delete.xaml
  37. 4 0
      BellwetherBackend/Assets/appbar.control.disconnect.xaml
  38. 4 0
      BellwetherBackend/Assets/appbar.control.downward.xaml
  39. 4 0
      BellwetherBackend/Assets/appbar.control.imgdelete.xaml
  40. 4 0
      BellwetherBackend/Assets/appbar.control.map.xaml
  41. 4 0
      BellwetherBackend/Assets/appbar.control.update.xaml
  42. 4 0
      BellwetherBackend/Assets/appbar.control.upward.xaml
  43. 193 0
      BellwetherBackend/BellwetherBackend.csproj
  44. BIN
      BellwetherBackend/DLL/FirstFloor.ModernUI.dll
  45. BIN
      BellwetherBackend/DLL/ICSharpCode.SharpZipLib.dll
  46. BIN
      BellwetherBackend/DLL/Microsoft.Windows.Shell.dll
  47. BIN
      BellwetherBackend/DLL/Microsoft.WindowsAPICodePack.Shell.dll
  48. BIN
      BellwetherBackend/DLL/Microsoft.WindowsAPICodePack.dll
  49. BIN
      BellwetherBackend/DLL/Newtonsoft.Json.dll
  50. BIN
      BellwetherBackend/DLL/SocketTransfer.dll
  51. 63 0
      BellwetherBackend/MainWindow.xaml
  52. 85 0
      BellwetherBackend/MainWindow.xaml.cs
  53. 236 0
      BellwetherBackend/ModernWindowResource.xaml
  54. 114 0
      BellwetherBackend/MyDictionary.xaml
  55. 55 0
      BellwetherBackend/Properties/AssemblyInfo.cs
  56. 70 0
      BellwetherBackend/Properties/Resources.Designer.cs
  57. 117 0
      BellwetherBackend/Properties/Resources.resx
  58. 50 0
      BellwetherBackend/Properties/Settings.Designer.cs
  59. 12 0
      BellwetherBackend/Properties/Settings.settings
  60. 46 0
      BellwetherBackend/SubPage/UcBasicSetting.xaml
  61. 51 0
      BellwetherBackend/SubPage/UcBasicSetting.xaml.cs
  62. 202 0
      BellwetherBackend/SubPage/UpdatePage.xaml
  63. 768 0
      BellwetherBackend/SubPage/UpdatePage.xaml.cs
  64. 257 0
      BellwetherBackend/Utility/GlobalFunction.cs
  65. 94 0
      BellwetherBackend/Utility/Setting.cs
  66. 24 0
      HistoryDLL/CompleteEventArgs.cs
  67. 200 0
      HistoryDLL/ConfigSettingClass.cs
  68. 100 0
      HistoryDLL/CutThumbnail.cs
  69. 42 0
      HistoryDLL/CyclicScroller.xaml
  70. 857 0
      HistoryDLL/CyclicScroller.xaml.cs
  71. 390 0
      HistoryDLL/CyclicScrollerCommunication.cs
  72. 323 0
      HistoryDLL/CyclicScrollerOpcityMask.cs
  73. 518 0
      HistoryDLL/CyclicScrollerSubFunction.cs
  74. BIN
      HistoryDLL/DLL/KernelViewerCtrlDll.dll
  75. BIN
      HistoryDLL/DLL/MediaGalleryDll.dll
  76. BIN
      HistoryDLL/DLL/MediaViewerLib.dll
  77. BIN
      HistoryDLL/DLL/Microsoft.WindowsAPICodePack.Shell.dll
  78. BIN
      HistoryDLL/DLL/Microsoft.WindowsAPICodePack.dll
  79. BIN
      HistoryDLL/DLL/NLLoadingIndicator.dll
  80. BIN
      HistoryDLL/DLL/NLPlaneRotator.dll
  81. BIN
      HistoryDLL/DLL/Newtonsoft.Json.dll
  82. BIN
      HistoryDLL/DLL/nLightenLibs.dll
  83. 1 0
      HistoryDLL/Data/HistoryWallPage/Setting/ChangeLan.txt
  84. 1 0
      HistoryDLL/Data/HistoryWallPage/Setting/HomeClick.txt
  85. 1 0
      HistoryDLL/Data/HistoryWallPage/Setting/ScaleDetailviewer.txt
  86. 1 0
      HistoryDLL/Data/HistoryWallPage/Setting/Velocity.txt
  87. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/1x1.jpg
  88. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/1x2.jpg
  89. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/1x3.jpg
  90. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/color322x212.png
  91. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/exit_focus.png
  92. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/exit_idle.png
  93. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/home.png
  94. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/language_bk.png
  95. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/launch_icon.ico
  96. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/logo.png
  97. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/ok_focus.png
  98. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/ok_idle.png
  99. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/registration_bk.jpg
  100. BIN
      HistoryDLL/Data/HistoryWallPage/Thumb/shadow_big.png

+ 49 - 0
Bellwether.sln

@@ -0,0 +1,49 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31911.196
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bellwether", "Bellwether\Bellwether.csproj", "{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BellwetherBackend", "BellwetherBackend\BellwetherBackend.csproj", "{852F7BF5-E998-48D1-8512-5CD77F0E10C2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HistoryDLL", "HistoryDLL\HistoryDLL.csproj", "{F313210C-FBD1-44D4-B111-C3816DF5F234}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HistoryWallEditTool", "HistoryWallEditTool\HistoryWallEditTool\HistoryWallEditTool.csproj", "{94FE2AC5-787C-41D0-882A-61DA973EA378}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VideoPlayer", "VideoPlayer\VideoPlayer.csproj", "{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}.Release|Any CPU.Build.0 = Release|Any CPU
+		{852F7BF5-E998-48D1-8512-5CD77F0E10C2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{852F7BF5-E998-48D1-8512-5CD77F0E10C2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{852F7BF5-E998-48D1-8512-5CD77F0E10C2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{852F7BF5-E998-48D1-8512-5CD77F0E10C2}.Release|Any CPU.Build.0 = Release|Any CPU
+		{F313210C-FBD1-44D4-B111-C3816DF5F234}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{F313210C-FBD1-44D4-B111-C3816DF5F234}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{F313210C-FBD1-44D4-B111-C3816DF5F234}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{F313210C-FBD1-44D4-B111-C3816DF5F234}.Release|Any CPU.Build.0 = Release|Any CPU
+		{94FE2AC5-787C-41D0-882A-61DA973EA378}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{94FE2AC5-787C-41D0-882A-61DA973EA378}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{94FE2AC5-787C-41D0-882A-61DA973EA378}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{94FE2AC5-787C-41D0-882A-61DA973EA378}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {0482EBC4-5A5D-4203-9128-5CCB76C0E367}
+	EndGlobalSection
+EndGlobal

+ 21 - 0
Bellwether/App.config

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <configSections>
+        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+            <section name="Bellwether.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
+        </sectionGroup>
+    </configSections>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
+    </startup>
+    <userSettings>
+        <Bellwether.Properties.Settings>
+            <setting name="SocketPort" serializeAs="String">
+                <value>54188</value>
+            </setting>
+            <setting name="SocketIP" serializeAs="String">
+                <value>127.0.0.1</value>
+            </setting>
+        </Bellwether.Properties.Settings>
+    </userSettings>
+</configuration>

+ 9 - 0
Bellwether/App.xaml

@@ -0,0 +1,9 @@
+<Application x:Class="Bellwether.App"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:local="clr-namespace:Bellwether"
+             StartupUri="MainWindow.xaml">
+    <Application.Resources>
+         
+    </Application.Resources>
+</Application>

+ 17 - 0
Bellwether/App.xaml.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Bellwether
+{
+    /// <summary>
+    /// Interaction logic for App.xaml
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}

+ 174 - 0
Bellwether/Bellwether.csproj

@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{D30DC432-4721-4200-9D64-E8DA6B2AD5E1}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>Bellwether</RootNamespace>
+    <AssemblyName>Bellwether</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ApplicationManifest>app.manifest</ApplicationManifest>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\ICSharpCode.SharpZipLib.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.WindowsAPICodePack, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\Microsoft.WindowsAPICodePack.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.WindowsAPICodePack.Shell, Version=1.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\Microsoft.WindowsAPICodePack.Shell.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="NLPlaneRotator, Version=1.0.0.9122, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\NLPlaneRotator.dll</HintPath>
+    </Reference>
+    <Reference Include="RestSharp, Version=106.13.0.0, Culture=neutral, PublicKeyToken=598062e77f915f75, processorArchitecture=MSIL">
+      <HintPath>..\packages\RestSharp.106.13.0\lib\net452\RestSharp.dll</HintPath>
+    </Reference>
+    <Reference Include="SocketTransfer, Version=1.0.0.10178, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\SocketTransfer.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+  </ItemGroup>
+  <ItemGroup>
+    <ApplicationDefinition Include="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </ApplicationDefinition>
+    <Compile Include="Pages\ucHistoryHW.xaml.cs">
+      <DependentUpon>ucHistoryHW.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="ucMainControlPage.xaml.cs">
+      <DependentUpon>ucMainControlPage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Utility\GlobalFunction.cs" />
+    <Compile Include="Utility\SbAssist.cs" />
+    <Compile Include="Utility\Setting.cs" />
+    <Compile Include="Utility\UpdateProcess.cs" />
+    <Page Include="MainWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Compile Include="App.xaml.cs">
+      <DependentUpon>App.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="MainWindow.xaml.cs">
+      <DependentUpon>MainWindow.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Page Include="Pages\ucFrontPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="Pages\ucHistoryHW.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="ucMainControlPage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Pages\ucFrontPage.xaml.cs">
+      <DependentUpon>ucFrontPage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\AssemblyInfo.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <None Include="app.manifest" />
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="DLL\ICSharpCode.SharpZipLib.dll" />
+    <Content Include="DLL\Microsoft.WindowsAPICodePack.dll" />
+    <Content Include="DLL\Microsoft.WindowsAPICodePack.Shell.dll" />
+    <Content Include="DLL\Newtonsoft.Json.dll" />
+    <Content Include="DLL\NLPlaneRotator.dll" />
+    <Content Include="DLL\SocketTransfer.dll" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HistoryDLL\HistoryDLL.csproj">
+      <Project>{f313210c-fbd1-44d4-b111-c3816df5f234}</Project>
+      <Name>HistoryDLL</Name>
+    </ProjectReference>
+    <ProjectReference Include="..\VideoPlayer\VideoPlayer.csproj">
+      <Project>{D4CBAEAC-4953-4F59-8F06-ABE37A9455F7}</Project>
+      <Name>VideoPlayer</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

BIN
Bellwether/DLL/ICSharpCode.SharpZipLib.dll


BIN
Bellwether/DLL/Microsoft.WindowsAPICodePack.Shell.dll


BIN
Bellwether/DLL/Microsoft.WindowsAPICodePack.dll


BIN
Bellwether/DLL/NLPlaneRotator.dll


BIN
Bellwether/DLL/Newtonsoft.Json.dll


BIN
Bellwether/DLL/SocketTransfer.dll


+ 28 - 0
Bellwether/MainWindow.xaml

@@ -0,0 +1,28 @@
+<Window
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:Bellwether"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    Title="MainWindow"
+    d:DesignHeight="1080"
+    d:DesignWidth="1920"
+    Stylus.IsPressAndHoldEnabled="False"
+    WindowState="Maximized"
+    WindowStyle="None"
+    mc:Ignorable="d"
+    x:Class="Bellwether.MainWindow">
+    <Window.Resources>
+        <Storyboard x:Key="HideStoryboard">
+            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="uxMainGrid" Storyboard.TargetProperty="(UIElement.Opacity)">
+                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0" />
+            </DoubleAnimationUsingKeyFrames>
+        </Storyboard>
+        <Storyboard x:Key="ShowStoryboard">
+            <DoubleAnimationUsingKeyFrames Storyboard.TargetName="uxMainGrid" Storyboard.TargetProperty="(UIElement.Opacity)">
+                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" />
+            </DoubleAnimationUsingKeyFrames>
+        </Storyboard>
+    </Window.Resources>
+    <Grid x:Name="uxMainGrid" />
+</Window>

+ 81 - 0
Bellwether/MainWindow.xaml.cs

@@ -0,0 +1,81 @@
+using Bellwether.Utility;
+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;
+
+namespace Bellwether
+{
+    public enum PageType : int
+    {
+        FrontPage,
+        History,
+        Product,
+        CSR,
+    }
+
+    /// <summary>
+    /// Interaction logic for MainWindow.xaml
+    /// </summary>
+    public partial class MainWindow : Window
+    {
+        private UpdateProcess updateProcess;
+
+        private Storyboard showStoryboard = new Storyboard();
+        private Storyboard hideStoryboard = new Storyboard();
+
+        public MainWindow()
+        {
+            InitializeComponent();
+
+            AddHideAndShowSt();
+
+            updateProcess = new UpdateProcess();
+            updateProcess.OnUpdateReady += UpdateProcess_OnUpdateReady;
+            updateProcess.OnUpdateComplete += UpdateProcess_OnUpdateComplete;
+
+            this.Loaded += MainWindow_Loaded;
+        }
+
+        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
+        {
+            uxMainGrid.Children.Add(new ucMainControlPage());
+        }
+
+        private void AddHideAndShowSt()
+        {
+            showStoryboard = FindResource("ShowStoryboard") as Storyboard;
+            hideStoryboard = FindResource("HideStoryboard") as Storyboard;
+            hideStoryboard.Completed += hideStoryboard_Completed;
+        }
+        private void UpdateProcess_OnUpdateReady(object sender, EventArgs e)
+        {
+            hideStoryboard.Begin();
+        }
+
+        private void hideStoryboard_Completed(object sender, EventArgs e)
+        {
+            uxMainGrid.Children.Clear();
+            GC.Collect();
+            updateProcess.StartUpdateProcess();
+        }
+
+        private void UpdateProcess_OnUpdateComplete(object sender, EventArgs e)
+        {
+            Setting.Reload();
+            uxMainGrid.Children.Add(new ucMainControlPage());
+            showStoryboard.Begin();
+        }
+    }
+}

+ 41 - 0
Bellwether/Pages/ucFrontPage.xaml

@@ -0,0 +1,41 @@
+<UserControl
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:Bellwether.Pages"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    Width="5760"
+    Height="1080"
+    d:DesignHeight="1080"
+    d:DesignWidth="5760"
+    mc:Ignorable="d"
+    x:Class="Bellwether.Pages.ucFrontPage">
+    <UserControl.Content>
+        <Grid>
+            <StackPanel
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
+                Orientation="Horizontal">
+                <Button
+                    Width="300"
+                    Height="300"
+                    Click="Button_Click">
+                    <Label>大事紀</Label>
+                </Button>
+                <Button
+                    Width="300"
+                    Height="300"
+                    Click="Button1_Click">
+                    <Label>產品展示</Label>
+                </Button>
+                <Button
+                    Width="300"
+                    Height="300"
+                    Click="Button2_Click">
+                    <Label>社會責任</Label>
+                </Button>
+
+            </StackPanel>
+        </Grid>
+    </UserControl.Content>
+</UserControl>

+ 127 - 0
Bellwether/Pages/ucFrontPage.xaml.cs

@@ -0,0 +1,127 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Timers;
+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.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Bellwether.Pages
+{
+    /// <summary>
+    /// Interaction logic for ucFrontPage.xaml
+    /// </summary>
+    public partial class ucFrontPage : UserControl
+    {
+        public event EventHandler<PageType> GoPageRequested;
+
+        private Timer SolarInfpoUpdateTimer;
+
+        public ucFrontPage()
+        {
+            InitializeComponent();
+
+            SolarInfpoUpdateTimer = new Timer() { Interval = 60_0000 };
+
+            Loaded += UcFrontPage_Load;
+            Unloaded += UcFrontPage_Unload;
+        }
+
+        private void UcFrontPage_Load(object sender, EventArgs e)
+        {
+            SolarInfpoUpdateTimer.Elapsed += SolarInfpoUpdateTimer_Elapsed;
+
+            UpdateSolarInfo();
+            SolarInfpoUpdateTimer.Start();
+        }
+
+        private void UcFrontPage_Unload(object sender, EventArgs e)
+        {
+            SolarInfpoUpdateTimer.Elapsed -= SolarInfpoUpdateTimer_Elapsed;
+            SolarInfpoUpdateTimer.Stop();
+        }
+
+        private void SolarInfpoUpdateTimer_Elapsed(object sender, ElapsedEventArgs e)
+        {
+            UpdateSolarInfo();
+        }
+
+        private void UpdateSolarInfo()
+        {
+            var client = new RestSharp.RestClient("https://dsegomspoctestenv.azurewebsites.net/api/siteoverview?act=9237&token=BWsolarenergy");
+            var request = new RestSharp.RestRequest(RestSharp.Method.GET);
+            //request.AddParameter("act", "9237");
+            //request.AddParameter("token", "BWsolarenergy");
+
+            var response = client.Execute(request);
+
+            if (response.IsSuccessful)
+            {
+                var result = response.Content;
+
+                if (result.StartsWith("\""))
+                {
+                    result = result.Substring(1);
+                }
+                if (result.EndsWith("\""))
+                {
+                    result = result.Substring(0,result.Length - 1);
+                }
+                result = result.Replace("\\\"", "\"");
+
+                try
+                {
+                    var data = JsonConvert.DeserializeObject<SolarInfoModel>(result);
+
+                    if (data !=null)
+                    {
+
+                    }
+                }
+                catch(Exception e)
+                {
+                    return;
+                }
+            }
+            else
+            {
+                var errmsg = response.Content;
+            }
+        }
+
+        private void Button_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.History);
+        }
+
+        private void Button1_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.Product);
+        }
+
+        private void Button2_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.CSR);
+        }
+    }
+
+    public class SolarInfoModel
+    {
+        public float Capacity { get; set; }
+        public double Energy_Today { get; set; }
+        public double CO2EmissionSaved_Today { get; set; }
+        public double EquivalentTreesPlanted_Today { get; set; }
+        public double Energy_ThisYear { get; set; }
+        public double CO2EmissionSaved_ThisYear { get; set; }
+        public double EquivalentTreesPlanted_ThisYear { get; set; }
+    }
+}

+ 47 - 0
Bellwether/Pages/ucHistoryHW.xaml

@@ -0,0 +1,47 @@
+<UserControl
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:Bellwether.Pages"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    Width="5760"
+    Height="1080"
+    d:DesignHeight="1080"
+    d:DesignWidth="5760"
+    mc:Ignorable="d"
+    x:Class="Bellwether.Pages.ucHistoryHW">
+    <Grid>
+        <Grid x:Name="uxHwContainer" />
+
+        <StackPanel
+            HorizontalAlignment="Left"
+            VerticalAlignment="Top"
+            Orientation="Horizontal">
+            <Button
+                Width="300"
+                Height="300"
+                Click="Button_Click">
+                <Label>首頁</Label>
+            </Button>
+            <Button
+                Width="300"
+                Height="300"
+                Click="Button1_Click">
+                <Label>大事紀</Label>
+            </Button>
+            <Button
+                Width="300"
+                Height="300"
+                Click="Button2_Click">
+                <Label>產品展示</Label>
+            </Button>
+            <Button
+                Width="300"
+                Height="300"
+                Click="Button3_Click">
+                <Label>社會責任</Label>
+            </Button>
+
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 71 - 0
Bellwether/Pages/ucHistoryHW.xaml.cs

@@ -0,0 +1,71 @@
+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.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Bellwether.Pages
+{
+    /// <summary>
+    /// Interaction logic for ucHistoryHW.xaml
+    /// </summary>
+    public partial class ucHistoryHW : UserControl
+    {
+        private static Dictionary<PageType, string> PageFolderName
+            = new Dictionary<PageType, string>() {
+                { PageType.History, "History" },
+                { PageType.Product, "Product" },
+                { PageType.CSR, "CSR" },
+            };
+
+        public event EventHandler<PageType> GoPageRequested;
+
+        private HistoryDLL.CyclicScroller uiHistory;
+        private PageType currentPage;
+
+        public ucHistoryHW(PageType type)
+        {
+            InitializeComponent();
+
+            currentPage = type;
+            Loaded += UcHistoryHW_Loaded;
+        }
+
+        private void UcHistoryHW_Loaded(object sender, RoutedEventArgs e)
+        {
+            var pageFolderName = PageFolderName[currentPage];
+            HistoryDLL.GlobalFunction.historyWalldataFolderName = pageFolderName;
+            uiHistory = new HistoryDLL.CyclicScroller(0);
+            uxHwContainer.Children.Insert(0, uiHistory);
+        }
+
+        private void Button_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.FrontPage);
+        }
+
+        private void Button1_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.History);
+        }
+
+        private void Button2_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.Product);
+        }
+
+        private void Button3_Click(object sender, RoutedEventArgs e)
+        {
+            GoPageRequested?.Invoke(this, PageType.CSR);
+        }
+    }
+}

+ 55 - 0
Bellwether/Properties/AssemblyInfo.cs

@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Bellwether")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Bellwether")]
+[assembly: AssemblyCopyright("Copyright ©  2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>.  For example, if you are using US english
+//in your source files, set the <UICulture> to en-US.  Then uncomment
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+                                     //(used if a resource is not found in the page,
+                                     // or application resource dictionaries)
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+                                              //(used if a resource is not found in the page,
+                                              // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 70 - 0
Bellwether/Properties/Resources.Designer.cs

@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+
+namespace Bellwether.Properties
+{
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Bellwether.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
Bellwether/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 50 - 0
Bellwether/Properties/Settings.Designer.cs

@@ -0,0 +1,50 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace Bellwether.Properties {
+    
+    
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+        
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+        
+        public static Settings Default {
+            get {
+                return defaultInstance;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("54188")]
+        public string SocketPort {
+            get {
+                return ((string)(this["SocketPort"]));
+            }
+            set {
+                this["SocketPort"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("127.0.0.1")]
+        public string SocketIP {
+            get {
+                return ((string)(this["SocketIP"]));
+            }
+            set {
+                this["SocketIP"] = value;
+            }
+        }
+    }
+}

+ 12 - 0
Bellwether/Properties/Settings.settings

@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="Bellwether.Properties" GeneratedClassName="Settings">
+  <Profiles />
+  <Settings>
+    <Setting Name="SocketPort" Type="System.String" Scope="User">
+      <Value Profile="(Default)">54188</Value>
+    </Setting>
+    <Setting Name="SocketIP" Type="System.String" Scope="User">
+      <Value Profile="(Default)">127.0.0.1</Value>
+    </Setting>
+  </Settings>
+</SettingsFile>

+ 203 - 0
Bellwether/Utility/GlobalFunction.cs

@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+
+namespace Bellwether.Utility
+{
+    public class GlobalFunction
+    {
+        //圖片規格
+        public static string[] imgDimList = { ".jpg", ".png", ".bmp", ".jpeg" };
+        //影片規格
+        public static string[] mediaDimList = { ".avi", ".mp4", "mpeg", ".mpg", ".wmv" };
+        //簡報
+        public static string[] pptDimList = { ".ppt", ".pptx" };
+
+        public static ImageSource GetBitMap(string imgpath)
+        {
+            BitmapImage bitmapImg = new BitmapImage();
+
+            if (File.Exists(imgpath))
+            {
+                bitmapImg.BeginInit();
+                bitmapImg.UriSource = new Uri(imgpath, UriKind.RelativeOrAbsolute);
+                //忽略原始圖檔的色盤設定,使用預設值,可縮短載入圖檔的時間
+                //如有遇到色彩不正確的問題,或者原圖有特殊的自定義色盤,請不要使用此設定
+                bitmapImg.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+                //使用以下的預先載入設定,在BitmapImage創建完成之後,可立刻釋放其所占用或鎖住的資源,以免咬住檔案
+                bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
+                //根據欲顯示的區域長或寬,來設定 DecodePixelHeight 或 DecodePixelWidth 的值
+                //bitmapImg.DecodePixelHeight = THUMB_HEIGHT;
+                //bitmapImg.DecodePixelWidth = THUMB_WIDTH;
+                bitmapImg.EndInit();
+                bitmapImg.Freeze();
+            }
+            return bitmapImg;
+        }
+
+        public static ImageSource GetBitMap(string imgpath, double resolutionWidth, double resolutionHeight)
+        {
+            BitmapImage bitmapImg = new BitmapImage();
+
+            if (File.Exists(imgpath))
+            {
+                bitmapImg.BeginInit();
+                bitmapImg.UriSource = new Uri(imgpath, UriKind.RelativeOrAbsolute);
+                //忽略原始圖檔的色盤設定,使用預設值,可縮短載入圖檔的時間
+                //如有遇到色彩不正確的問題,或者原圖有特殊的自定義色盤,請不要使用此設定
+                bitmapImg.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+                //使用以下的預先載入設定,在BitmapImage創建完成之後,可立刻釋放其所占用或鎖住的資源,以免咬住檔案
+                bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
+                //根據欲顯示的區域長或寬,來設定 DecodePixelHeight 或 DecodePixelWidth 的值
+                BitmapDecoder decoder = BitmapDecoder.Create(new Uri(imgpath), BitmapCreateOptions.None, BitmapCacheOption.None);
+                BitmapFrame frame = decoder.Frames[0];
+
+                //ShellFile shellFile = ShellFile.FromFilePath(imgpath);
+                var imageSourceHeight = frame.PixelHeight; //shellFile.Properties.System.Image.VerticalSize.Value;
+                var imageSourceWidth = frame.PixelWidth;//shellFile.Properties.System.Image.HorizontalSize.Value;
+                double imageSourceRatio = imageSourceWidth / (imageSourceHeight == 0 ? (double)1 : imageSourceHeight);
+
+                if (imageSourceHeight > resolutionHeight && imageSourceWidth > resolutionWidth)
+                {
+                    if (imageSourceRatio > resolutionWidth / resolutionHeight)
+                    {
+                        bitmapImg.DecodePixelWidth = Convert.ToInt32(resolutionWidth);
+                    }
+                    else
+                    {
+                        bitmapImg.DecodePixelHeight = Convert.ToInt32(resolutionHeight);
+                    }
+                }
+                else if (imageSourceHeight > resolutionHeight)
+                {
+                    bitmapImg.DecodePixelHeight = Convert.ToInt32(resolutionHeight);
+                }
+                else if (imageSourceWidth > resolutionWidth)
+                {
+                    bitmapImg.DecodePixelWidth = Convert.ToInt32(resolutionWidth);
+                }
+                bitmapImg.EndInit();
+                bitmapImg.Freeze();
+            }
+            else
+                return null;
+            return bitmapImg;
+        }
+
+        public static bool CheckFileIsImage(string file)
+        {
+            if (GlobalFunction.imgDimList.Contains(System.IO.Path.GetExtension(file.ToLower())))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        public static bool CheckFileIsVideo(string file)
+        {
+            if (GlobalFunction.mediaDimList.Contains(System.IO.Path.GetExtension(file.ToLower())))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        public static bool CheckNetworkStatus()
+        {
+            if (System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable())
+                return true;
+
+            return false;
+        }
+    }
+
+    public class ScrollViewerUtilities
+    {
+        #region HorizontalOffset
+
+        /// <summary>
+        /// HorizontalOffset Attached Dependency Property
+        /// </summary>
+        public static readonly DependencyProperty HorizontalOffsetProperty =
+            DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtilities),
+                new FrameworkPropertyMetadata((double)0.0,
+                    new PropertyChangedCallback(OnHorizontalOffsetChanged)));
+
+        /// <summary>
+        /// Gets the HorizontalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static double GetHorizontalOffset(DependencyObject d)
+        {
+            return (double)d.GetValue(HorizontalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the HorizontalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static void SetHorizontalOffset(DependencyObject d, double value)
+        {
+            d.SetValue(HorizontalOffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Handles changes to the HorizontalOffset property.
+        /// </summary>
+        private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            var viewer = (ScrollViewer)d;
+            viewer.ScrollToHorizontalOffset((double)e.NewValue);
+        }
+
+        #endregion
+
+        #region VerticalOffset
+
+        /// <summary>
+        /// VerticalOffset Attached Dependency Property
+        /// </summary>
+        public static readonly DependencyProperty VerticalOffsetProperty =
+            DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtilities),
+                new FrameworkPropertyMetadata((double)0.0,
+                    new PropertyChangedCallback(OnVerticalOffsetChanged)));
+
+        /// <summary>
+        /// Gets the VerticalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static double GetVerticalOffset(DependencyObject d)
+        {
+            return (double)d.GetValue(VerticalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the VerticalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static void SetVerticalOffset(DependencyObject d, double value)
+        {
+            d.SetValue(VerticalOffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Handles changes to the VerticalOffset property.
+        /// </summary>
+        private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            var viewer = (ScrollViewer)d;
+            viewer.ScrollToVerticalOffset((double)e.NewValue);
+        }
+
+        #endregion
+    }
+}

+ 129 - 0
Bellwether/Utility/SbAssist.cs

@@ -0,0 +1,129 @@
+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.Media;
+using System.Windows.Media.Animation;
+
+namespace Bellwether.Utility
+{
+    public static class SbAssist
+    {
+        /// <summary>
+        /// FlashDirection denoted by 3*3 position to direction {}
+        /// </summary>
+        public enum FlashDirection
+        {
+            direction64,
+            direction91,
+        }
+
+        public static Storyboard CreateFlashStoryBoard(UIElement flashImg, double width = 1, double duration = 1000, FlashDirection direction = FlashDirection.direction64)
+        {
+            //if (wireImgContainer.Children.Count != 2)
+            //    return null;
+            var _flashImg = flashImg;///.Children[1];
+            Point[] startPoints = null;
+            Point[] endPoints = null;
+            if (direction == FlashDirection.direction64)
+            {
+                startPoints = new Point[] { new Point(1f, 0), new Point(width * -0.1f, 0) };
+                endPoints = new Point[] { new Point(1 + width * 0.1f, 0), new Point(0f, 0) };
+            }
+            else if (direction == FlashDirection.direction91)
+            {
+                startPoints = new Point[] { new Point(1f, 1f), new Point(width * -0.1f, width * -0.1f) };
+                endPoints = new Point[] { new Point(1 + width * 0.1f, 1 + width * 0.1f), new Point(0f, 0) };
+            }
+
+            _flashImg.OpacityMask = CreateFlashOpacityMask();
+            Storyboard flashSb = new Storyboard() { BeginTime = TimeSpan.FromSeconds(0), Duration = TimeSpan.FromMilliseconds(duration) };
+
+            var startPA = new PointAnimation(startPoints[0], startPoints[1], TimeSpan.FromMilliseconds(duration));
+            Storyboard.SetTarget(startPA, (DependencyObject)_flashImg);
+            Storyboard.SetTargetProperty(startPA, new PropertyPath("OpacityMask.StartPoint"));
+            flashSb.Children.Add(startPA);
+
+            var endPA = new PointAnimation(endPoints[0], endPoints[1], TimeSpan.FromMilliseconds(duration));
+            Storyboard.SetTarget(endPA, (DependencyObject)_flashImg);
+            Storyboard.SetTargetProperty(endPA, new PropertyPath("OpacityMask.EndPoint"));
+            flashSb.Children.Add(endPA);
+
+            flashSb.Begin();
+            return flashSb;
+        }
+
+        public static Brush CreateFlashOpacityMask()
+        {
+            //var om = (LinearGradientBrush)FindResource("rsFlashMask");
+            var om = new LinearGradientBrush();
+            om.MappingMode = BrushMappingMode.RelativeToBoundingBox;
+            om.StartPoint = new Point(0, 0);
+            om.EndPoint = new Point(1, 0);
+            om.GradientStops = new GradientStopCollection()
+            {
+                new GradientStop(){ Offset = 0, Color = Colors.Transparent },
+                new GradientStop() { Offset = 0.3, Color = Colors.White },
+                new GradientStop() { Offset = 0.6, Color = Colors.White },
+                new GradientStop() { Offset = 1, Color = Colors.Transparent }
+            };
+            return om;
+        }
+
+        public static Storyboard CreateOpacitySb(DependencyObject dependencyObject, double from, double to, double duration, bool isLoop = false, bool isReverse = false)
+        {
+            var sb = new Storyboard();
+            var da = new DoubleAnimation(from, to, TimeSpan.FromMilliseconds(duration));
+            if (isLoop)
+                da.RepeatBehavior = RepeatBehavior.Forever;
+            if (isReverse)
+                da.AutoReverse = true;
+            Storyboard.SetTarget(da, dependencyObject);
+            Storyboard.SetTargetProperty(da, new PropertyPath(FrameworkElement.OpacityProperty));
+            sb.Children.Add(da);
+            return sb;
+        }
+
+        public static Storyboard CreateOpacityBlinkSb(DependencyObject dependencyObject, double from, double to, double duration, double sustainDuration = 0, double timeInterval = 1000, bool IsLoop = true)
+        {
+            var sb = new Storyboard();
+            var a1 = CreateOpacitySb(dependencyObject, from, to, duration);
+            a1.BeginTime = TimeSpan.FromMilliseconds(0);
+            sb.Children.Add(a1);
+            var a2 = CreateOpacitySb(dependencyObject, to, to, sustainDuration);
+            a2.BeginTime = TimeSpan.FromMilliseconds(duration);
+            sb.Children.Add(a2);
+            var a3 = CreateOpacitySb(dependencyObject, to, from, duration);
+            a3.BeginTime = TimeSpan.FromMilliseconds(duration + sustainDuration);
+            sb.Children.Add(a3);
+            var a4 = CreateOpacitySb(dependencyObject, from, from, timeInterval);
+            a4.BeginTime = TimeSpan.FromMilliseconds(duration * 2 + sustainDuration);
+            sb.Children.Add(a4);
+            if (IsLoop)
+                sb.RepeatBehavior = RepeatBehavior.Forever;
+            return sb;
+        }
+
+        public static Storyboard CreateRotationSb(FrameworkElement frameworkElement, double from, double to, double duration, bool isLoop = false, bool isReverse = false)
+        {
+            //check property
+            if (frameworkElement.Width == 0 || frameworkElement.Height == 0)
+                throw new Exception("Rotation Stortyboard need static Width and Height");
+            frameworkElement.RenderTransform = new RotateTransform() { CenterX = frameworkElement.Width / 2, CenterY = frameworkElement.Height / 2 };
+
+            var sb = new Storyboard();
+            var da = new DoubleAnimation(from, to, TimeSpan.FromMilliseconds(duration));
+            if (isLoop)
+                da.RepeatBehavior = RepeatBehavior.Forever;
+            if (isReverse)
+                da.AutoReverse = true;
+            Storyboard.SetTarget(da, frameworkElement);
+            Storyboard.SetTargetProperty(da, new PropertyPath("(UIElement.RenderTransform).(RotateTransform.Angle)"));
+            sb.Children.Add(da);
+            return sb;
+        }
+    }
+}

+ 75 - 0
Bellwether/Utility/Setting.cs

@@ -0,0 +1,75 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Bellwether.Utility
+{
+    public static class Setting
+    {
+        public static readonly List<string> PageNameList = new List<string>() { "大事記", "產品展示", "社會責任" };
+
+        public static int BackHomeSec { get => settingJsonFile.BackHomeSec; }
+
+        private static string dataDirectory = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Data");
+        private static string settingJsonDataPath = System.IO.Path.Combine(dataDirectory, "setting.ini");
+
+        private static SettingJson _settingJsonFile;
+        private static SettingJson settingJsonFile
+        {
+            get
+            {
+                if (_settingJsonFile != null)
+                    return _settingJsonFile;
+                else
+                {
+                    AnalyzJsonFile();
+                    return _settingJsonFile;
+                }
+            }
+        }
+
+        public static void Reload()
+        {
+            AnalyzJsonFile();
+        }
+
+        #region 解析 json
+        public static T DeserializeFromJson<T>(string jsonStr)
+        {
+            T deserializedProduct = JsonConvert.DeserializeObject<T>(jsonStr);
+            return deserializedProduct;
+        }
+
+        private static void AnalyzJsonFile()
+        {
+            string jsonResult;
+
+            if (!File.Exists(settingJsonDataPath))
+            {
+                _settingJsonFile = new SettingJson()
+                {
+                    BackHomeSec = 60,
+                };
+            }
+            else
+            {
+                using (StreamReader sr = new StreamReader(settingJsonDataPath))
+                {
+                    jsonResult = sr.ReadToEnd();
+                }
+                _settingJsonFile = DeserializeFromJson<SettingJson>(jsonResult);
+            }
+        }
+        #endregion
+
+    }
+
+    public class SettingJson
+    {
+        public int BackHomeSec { get; set; }
+    }
+}

+ 459 - 0
Bellwether/Utility/UpdateProcess.cs

@@ -0,0 +1,459 @@
+using ICSharpCode.SharpZipLib.Zip;
+using SocketTransfer;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace Bellwether.Utility
+{
+    public class UpdateProcess
+    {
+        public event EventHandler OnUpdateReady;
+        public event EventHandler OnUpdateComplete;
+
+        private string kioskIP;
+        private int kioskPort;
+        private SocketServer socketServer;
+        private int updateFileCount = 0;
+        private BackgroundWorker unzipWorker;
+
+        private string zipName = "Temp.zip";
+        private static string tempFolder = @"Temp\";
+        private static string tempFolderPath = Path.Combine(Directory.GetCurrentDirectory(), @"Temp\");
+        private string segmentsFilePath = tempFolderPath + @"\Data[{0}].cut";
+
+        private string dataPath = Path.Combine(Directory.GetCurrentDirectory(), "Data");
+
+        public static readonly Dictionary<PageType, string> PageFolderName
+            = new Dictionary<PageType, string>() {
+                { PageType.History, "History" },
+                { PageType.Product, "Product" },
+                { PageType.CSR, "CSR" },
+            };
+
+        public UpdateProcess()
+        {
+            if (GlobalFunction.CheckNetworkStatus())
+            {
+                try
+                {
+                    CreateSocketFunction();
+                }
+                catch (System.Exception ex)
+                {
+                    MessageBox.Show("位址設定錯誤!!~ " + Properties.Settings.Default["SocketIP"].ToString() + ex.Message.ToString());
+                    Application.Current.MainWindow.Close();
+                }
+            }
+        }
+
+
+        public void StartUpdateProcess()
+        {
+            //移動檔案並覆蓋
+            if (MoveFileCheck())
+            {
+                socketServer.NotifyMessage("Success");
+            }
+            else
+            {
+                socketServer.NotifyMessage("Fail");
+            }
+
+            OnUpdateComplete.Invoke(this, null);
+            //清除 Temp 資料夾內的所有檔案
+            ClearFolderDataByPath(Path.Combine(Directory.GetCurrentDirectory(), tempFolder));
+
+            //showStoryboard.Begin();
+            //ReloadPage();
+        }
+
+        private void UpdateFileStart()
+        {
+            //hideStoryboard.Begin();
+            OnUpdateReady?.Invoke(this, null);
+        }
+
+        private void unzipWorker_DoWork(object sender, DoWorkEventArgs e)
+        {
+            //合併
+            if (MergerFileToZip())
+            {
+                //解壓縮
+                DecompressFile();
+                //將所有檔案刪除 (.zip & .cut)
+                DeleteZipAndCutFile();
+            }
+            Thread.Sleep(5000);
+        }
+
+        private void unzipWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            //檔案下載完畢~處理程序開始~ (直接更新)
+            UpdateFileStart();
+        }
+
+        private void MoveFileDirect(string fromFilePath, string toFilePath)
+        {
+            File.Copy(fromFilePath, toFilePath, true);
+        }
+
+        private void MoveDirectoryDirect(string fromDirectory, string toDirectory)
+        {
+            Directory.Move(fromDirectory, toDirectory);
+        }
+
+        private void MoveImageOrMediaFile(string fromFileFolder, string toFileFolder)
+        {
+            if (Directory.Exists(fromFileFolder))
+            {
+                string[] files = Directory.GetFiles(fromFileFolder);
+
+                foreach (string file in files)
+                {
+                    MoveFileDirect(file, toFileFolder + System.IO.Path.GetFileName(file));
+                }
+            }
+        }
+
+        private void ClearFolderDataByPath(string willClearFolder)
+        {
+            if (Directory.Exists(willClearFolder))
+            {
+                string[] files = Directory.GetFiles(willClearFolder);
+                string[] dirs = Directory.GetDirectories(willClearFolder);
+
+                foreach (string file in files)
+                {
+                    File.Delete(file);
+                }
+
+                foreach (string file in dirs)
+                {
+                    Directory.Delete(file, true);
+                }
+            }
+            else
+            {
+                Directory.CreateDirectory(willClearFolder);
+            }
+        }
+
+        private List<string> GetIntrofolderListByPath(string tempIntroFolder)
+        {
+            List<string> result = new List<string>();
+            List<string> routeList = new List<string>();
+
+            if (Directory.Exists(tempIntroFolder))
+            {
+                routeList.AddRange(Directory.GetDirectories(tempIntroFolder));
+
+                foreach (string item in routeList)
+                {
+                    result.Add(Path.GetFileNameWithoutExtension(item) + @"\");
+                }
+            }
+
+            return result;
+        }
+
+        private void UpdateAboutFunctionbySource(string sourceFolder)
+        {
+            // 更新圖片 : 整個刪掉, 整個搬
+            if (Directory.Exists(sourceFolder))
+            {
+                string targetDirectoryPath = Path.Combine(dataPath, "About");
+                if (Directory.Exists(targetDirectoryPath))
+                {
+                    Directory.Delete(targetDirectoryPath, true);
+                }
+
+                //MoveDirectoryDirect(sourceFolder + Global.GlobalFunction.enviromentFolderName + Global.GlobalFunction.enviromentImageFolderName,
+                //    Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.enviromentFolderName + Global.GlobalFunction.enviromentImageFolderName);
+                MoveDirectoryDirect(sourceFolder,
+                    targetDirectoryPath);
+            }
+        }
+
+        private void UpdateHistoryWallFunctionBySource(string sourceFolder, PageType pageType)
+        {
+            string historySettingFolder = @"Setting\";
+            string historyConfigJsonName = "ConfigSetting.ini";
+            string historyInfoFolder = @"HistoryWallData\";
+            string historyEventJsonName = "HistoryFile.ini";
+            string historyThumbFolder = @"Thumb\";
+            string historyImgFolder = @"HistoryImage\";
+
+            // 該資料夾包含 HistoryWallData, HistoryImage, Setting, Thumb 四個資料夾
+            // 1. 更新 ini
+            if (File.Exists(Path.Combine(sourceFolder, historySettingFolder, historyConfigJsonName)))
+            {
+                MoveFileDirect(Path.Combine(sourceFolder, historySettingFolder, historyConfigJsonName),
+                    Path.Combine(dataPath, PageFolderName[pageType], historySettingFolder, historyConfigJsonName));
+            }
+
+            if (File.Exists(Path.Combine(sourceFolder, historyInfoFolder, historyEventJsonName)))
+            {
+                MoveFileDirect(Path.Combine(sourceFolder, historyInfoFolder, historyEventJsonName),
+                    Path.Combine(dataPath, PageFolderName[pageType], historyInfoFolder, historyEventJsonName));
+            }
+
+            // 更新 bg 及 logo
+            if (Directory.Exists(Path.Combine(sourceFolder, historyThumbFolder)))
+            {
+                string[] files = Directory.GetFiles(Path.Combine(sourceFolder, historyThumbFolder));
+
+                foreach (string file in files)
+                {
+                    MoveFileDirect(file, Path.Combine(dataPath, PageFolderName[pageType], historyThumbFolder, System.IO.Path.GetFileName(file)));
+                    //Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyThumbFolder + System.IO.Path.GetFileName(file));
+                }
+            }
+
+            // 更新圖片 : 整個刪掉, 整個搬
+            if (Directory.Exists(Path.Combine(sourceFolder, historyImgFolder)))
+            {
+                //if (Directory.Exists(Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyImgFolder))
+                //{
+                //    Directory.Delete(Global.GlobalFunction.dataFolderPath + Global.GlobalFunction.historyFolder + Global.GlobalFunction.historyImgFolder, true);
+                //}
+                string imgFolderPath = Path.Combine(dataPath, PageFolderName[pageType], historyImgFolder);
+                if (Directory.Exists(imgFolderPath))
+                {
+                    Directory.Delete(imgFolderPath, true);
+                }
+
+                MoveDirectoryDirect(Path.Combine(sourceFolder, historyImgFolder),
+                    imgFolderPath);
+            }
+        }
+
+        private void UpdateImageFunctionBySource(string sourceFolder)
+        {
+            // 更新圖片 : 整個刪掉, 整個搬
+            if (Directory.Exists(sourceFolder))
+            {
+                string targetDirectoryPath = Path.Combine(dataPath, "Image");
+                if (Directory.Exists(targetDirectoryPath))
+                {
+                    Directory.Delete(targetDirectoryPath, true);
+                }
+
+                MoveDirectoryDirect(sourceFolder, targetDirectoryPath);
+            }
+        }
+
+        private void UpdatePPTFunctionBySource(string sourceFolder)
+        {
+            // 更新圖片 : 整個刪掉, 整個搬
+            if (Directory.Exists(sourceFolder))
+            {
+                string targetDirectoryPath = Path.Combine(dataPath, "PPT");
+                if (Directory.Exists(targetDirectoryPath))
+                {
+                    Directory.Delete(targetDirectoryPath, true);
+                }
+
+                MoveDirectoryDirect(sourceFolder, targetDirectoryPath);
+            }
+        }
+
+        private bool MoveFileCheck()
+        {
+            bool result = true;
+
+            try
+            {
+                string tempDataPath = Path.Combine(tempFolderPath, "Data");
+                if (Directory.Exists(tempDataPath))
+                {
+                    string checkPath;
+
+                    checkPath = Path.Combine(tempDataPath, "setting.ini");
+                    if (File.Exists(checkPath))
+                    {
+                        MoveFileDirect(checkPath, Path.Combine(dataPath, "setting.ini"));
+                    }
+
+                    checkPath = Path.Combine(tempDataPath, "History");
+                    if (Directory.Exists(checkPath))
+                    {
+                        UpdateHistoryWallFunctionBySource(checkPath, PageType.History);
+                    }
+                    checkPath = Path.Combine(tempDataPath, "Product");
+                    if (Directory.Exists(checkPath))
+                    {
+                        UpdateHistoryWallFunctionBySource(checkPath, PageType.Product);
+                    }
+                    checkPath = Path.Combine(tempDataPath, "CSR");
+                    if (Directory.Exists(checkPath))
+                    {
+                        UpdateHistoryWallFunctionBySource(checkPath, PageType.CSR);
+                    }
+                }
+                else
+                {
+                    result = false;
+                }
+            }
+            catch (Exception e)
+            {
+                result = false;
+            }
+
+            return result;
+        }
+
+        private void CreateSocketFunction()
+        {
+            DetectTempFolder();
+
+            //取得IP 與 Port
+            kioskIP = Properties.Settings.Default["SocketIP"].ToString();
+            kioskPort = int.Parse(Properties.Settings.Default["SocketPort"].ToString());
+
+            socketServer = new SocketServer(kioskIP, kioskPort, tempFolder);
+            socketServer.ReceiveSegmentFileFinish += new ReceiveSegmentFileFinishHandler(socketServer_ReceiveSegmentFileFinish);
+            socketServer.ReceiveFileFail += new ReceiveFileFailHandler(socketServer_ReceiveFileFail);
+            socketServer.StartListen();
+        }
+
+        #region socket 後臺通知
+        private void socketServer_ReceiveFileFail()
+        {
+            socketServer.StopListen();
+            socketServer.Close();
+            socketServer = null;
+            CreateSocketFunction();
+        }
+
+        private void socketServer_ReceiveSegmentFileFinish(string file)
+        {
+            if (socketServer.FileReceiveCount == socketServer.FileTransferCount)
+            {
+                //當前取的檔案數量
+                updateFileCount = socketServer.FileTransferCount;
+                //合併~解壓縮~
+                unzipWorker = new BackgroundWorker();
+                unzipWorker.WorkerSupportsCancellation = true;
+                unzipWorker.DoWork += new DoWorkEventHandler(unzipWorker_DoWork);
+                unzipWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(unzipWorker_RunWorkerCompleted);
+                unzipWorker.RunWorkerAsync();
+            }
+        }
+        #endregion
+
+        private void DetectTempFolder()
+        {
+            if (Directory.Exists(tempFolder))
+            {
+                //刪除子資料夾
+                foreach (string d in Directory.GetDirectories(tempFolder))
+                {
+                    System.IO.Directory.Delete(d, true);
+                }
+            }
+            else
+            {
+                Directory.CreateDirectory(tempFolder);
+            }
+        }
+
+        private bool MergerFileToZip()
+        {
+            bool result = false;
+            int index = 1;
+            int datas = 0;
+            int bufferSize = 1048576;
+            FileStream fileStream = File.OpenWrite(tempFolder + @"/" + zipName);
+            byte[] binaryData = new byte[bufferSize];
+
+            while (File.Exists(String.Format(segmentsFilePath, index.ToString())))
+            {
+                string curFilePath = String.Format(segmentsFilePath, index.ToString());
+                {
+                    FileStream fs = File.OpenRead(curFilePath);
+                    datas = fs.Read(binaryData, 0, bufferSize);
+                    while (datas > 0)
+                    {
+                        fileStream.Write(binaryData, 0, datas);
+                        datas = fs.Read(binaryData, 0, bufferSize);
+                    }
+
+                    fs.Flush();
+                    fs.Close();
+                    //計數當前 .cut 數量
+                    index++;
+                }
+            }
+
+            fileStream.Flush();
+            fileStream.Close();
+
+
+            if (updateFileCount == index - 1)
+            {
+                //完整合併
+                result = true;
+            }
+
+            return result;
+        }
+
+        private void DecompressFile()
+        {
+            //解壓縮
+            using (ZipInputStream s = new ZipInputStream(File.OpenRead(tempFolder + "/" + zipName)))
+            {
+                ZipEntry theEntry;
+                while ((theEntry = s.GetNextEntry()) != null)
+                {
+                    string filePath = tempFolder + "/" + theEntry.Name;
+                    if (!Directory.Exists(System.IO.Path.GetDirectoryName(filePath)))
+                    {
+                        Directory.CreateDirectory(System.IO.Path.GetDirectoryName(filePath));
+                    }
+                    if (filePath != String.Empty)
+                    {
+                        using (FileStream streamWriter = File.Create(filePath))
+                        {
+                            int size = 2048;
+                            byte[] data = new byte[2048];
+                            while (true)
+                            {
+                                size = s.Read(data, 0, data.Length);
+                                if (size > 0)
+                                {
+                                    streamWriter.Write(data, 0, size);
+                                }
+                                else
+                                {
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        private void DeleteZipAndCutFile()
+        {
+            string[] fileList = Directory.GetFiles(tempFolder);
+
+            foreach (string filename in fileList)
+            {
+                if (File.Exists(filename))
+                {
+                    File.Delete(filename);
+                }
+            }
+        }
+    }
+}

+ 79 - 0
Bellwether/app.manifest

@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
+  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
+  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+    <security>
+      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
+        <!-- UAC Manifest Options
+             If you want to change the Windows User Account Control level replace the 
+             requestedExecutionLevel node with one of the following.
+
+        <requestedExecutionLevel  level="asInvoker" uiAccess="false" />
+        <requestedExecutionLevel  level="requireAdministrator" uiAccess="false" />
+        <requestedExecutionLevel  level="highestAvailable" uiAccess="false" />
+
+            Specifying requestedExecutionLevel element will disable file and registry virtualization. 
+            Remove this element if your application requires this virtualization for backwards
+            compatibility.
+        -->
+        <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
+      </requestedPrivileges>
+    </security>
+  </trustInfo>
+
+  <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
+    <application>
+      <!-- A list of the Windows versions that this application has been tested on
+           and is designed to work with. Uncomment the appropriate elements
+           and Windows will automatically select the most compatible environment. -->
+
+      <!-- Windows Vista -->
+      <!--<supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}" />-->
+
+      <!-- Windows 7 -->
+      <!--<supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}" />-->
+
+      <!-- Windows 8 -->
+      <!--<supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}" />-->
+
+      <!-- Windows 8.1 -->
+      <!--<supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}" />-->
+
+      <!-- Windows 10 -->
+      <!--<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />-->
+
+    </application>
+  </compatibility>
+
+  <!-- Indicates that the application is DPI-aware and will not be automatically scaled by Windows at higher
+       DPIs. Windows Presentation Foundation (WPF) applications are automatically DPI-aware and do not need 
+       to opt in. Windows Forms applications targeting .NET Framework 4.6 that opt into this setting, should 
+       also set the 'EnableWindowsFormsHighDpiAutoResizing' setting to 'true' in their app.config. 
+       
+       Makes the application long-path aware. See https://docs.microsoft.com/windows/win32/fileio/maximum-file-path-limitation -->
+  <!--
+  <application xmlns="urn:schemas-microsoft-com:asm.v3">
+    <windowsSettings>
+      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
+      <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware>
+    </windowsSettings>
+  </application>
+  -->
+
+  <!-- Enable themes for Windows common controls and dialogs (Windows XP and later) -->
+  <!--
+  <dependency>
+    <dependentAssembly>
+      <assemblyIdentity
+          type="win32"
+          name="Microsoft.Windows.Common-Controls"
+          version="6.0.0.0"
+          processorArchitecture="*"
+          publicKeyToken="6595b64144ccf1df"
+          language="*"
+        />
+    </dependentAssembly>
+  </dependency>
+  -->
+
+</assembly>

+ 4 - 0
Bellwether/packages.config

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+  <package id="RestSharp" version="106.13.0" targetFramework="net48" />
+</packages>

+ 15 - 0
Bellwether/ucMainControlPage.xaml

@@ -0,0 +1,15 @@
+<UserControl
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:Bellwether"
+    xmlns:local1="clr-namespace:Bellwether.Pages"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="Bellwether.ucMainControlPage">
+    <Viewbox x:Name="uxMainContainter">
+        <local1:ucFrontPage />
+    </Viewbox>
+</UserControl>

+ 121 - 0
Bellwether/ucMainControlPage.xaml.cs

@@ -0,0 +1,121 @@
+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;
+using VideoPlayer;
+
+namespace Bellwether
+{
+    /// <summary>
+    /// Interaction logic for ucMainControlPage.xaml
+    /// </summary>
+    public partial class ucMainControlPage : UserControl
+    {
+        private UIElement frontPage;
+
+        private Storyboard mainContainterFadeOutSb;
+        private Storyboard mainContainterFadeInSb;
+
+        private PageType nextPage;
+
+        private DispatcherTimer backHomeTimer;
+
+        public ucMainControlPage()
+        {
+            InitializeComponent();
+            InitializeStoryBoard();
+
+            this.Loaded += UcFrontPage_Loaded;
+            this.TouchDown += new EventHandler<TouchEventArgs>(ResetRoutedEvent);
+            this.TouchUp += new EventHandler<TouchEventArgs>(ResetRoutedEvent);
+            this.TouchMove += new EventHandler<TouchEventArgs>(ResetRoutedEvent);
+            this.MouseDown += new MouseButtonEventHandler(ResetRoutedEvent);
+            this.MouseMove += new MouseEventHandler(ResetRoutedEvent);
+        }
+
+        private void UcFrontPage_Loaded(object sender, RoutedEventArgs re)
+        {
+            frontPage = this.uxMainContainter.Child;
+            if (frontPage is Pages.ucFrontPage frontpage)
+            {
+                frontpage.GoPageRequested += Page_GoPageRequested;
+            }
+            backHomeTimer = new DispatcherTimer();
+            backHomeTimer.Interval = TimeSpan.FromSeconds(Utility.Setting.BackHomeSec);
+            backHomeTimer.Tick += BackHomeTimer_Tick;
+        }
+
+        private void BackHomeTimer_Tick(object sender, EventArgs e)
+        {
+            if (VideoPlayer.VideoPlayer.playingCount == 0)
+            {
+                Page_GoPageRequested(null, PageType.FrontPage);
+                backHomeTimer.Stop();
+            }
+        }
+
+        private void InitializeStoryBoard()
+        {
+            mainContainterFadeOutSb = Utility.SbAssist.CreateOpacitySb(uxMainContainter, 1, 0, 500);
+            mainContainterFadeOutSb.Completed += MainContainterFadeOutSb_Completed;
+            mainContainterFadeInSb = Utility.SbAssist.CreateOpacitySb(uxMainContainter, 0, 1, 500);
+            mainContainterFadeInSb.Completed += MainContainterFadeInSb_Completed;
+        }
+
+        private void MainContainterFadeInSb_Completed(object sender, EventArgs e)
+        {
+            if (nextPage != PageType.FrontPage)
+                backHomeTimer.Start();
+            else
+                backHomeTimer.Stop();
+        }
+
+        private void MainContainterFadeOutSb_Completed(object sender, EventArgs e)
+        {
+            if (nextPage == PageType.FrontPage)
+            {
+                this.uxMainContainter.Child = frontPage;
+            }
+            else
+            {
+                this.uxMainContainter.Child = CreateHistoryUc(nextPage);
+            }
+
+            mainContainterFadeInSb.Begin();
+        }
+
+        private void Page_GoPageRequested(object sender, PageType e)
+        {
+            nextPage = e;
+            mainContainterFadeOutSb.Begin();
+        }
+
+        private Pages.ucHistoryHW CreateHistoryUc(PageType type)
+        {
+            var tmp = new Pages.ucHistoryHW(type);
+            tmp.GoPageRequested += Page_GoPageRequested;
+            return tmp;
+        }
+
+        private void ResetRoutedEvent(object sender, RoutedEventArgs e)
+        {
+            if (backHomeTimer.IsEnabled)
+            {
+                backHomeTimer.Stop();
+                backHomeTimer.Start();
+            }
+        }
+    }
+}

+ 21 - 0
BellwetherBackend/App.config

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<configuration>
+    <configSections>
+        <sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
+            <section name="BellwetherBackend.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
+        </sectionGroup>
+    </configSections>
+    <startup> 
+        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8" />
+    </startup>
+    <userSettings>
+        <BellwetherBackend.Properties.Settings>
+            <setting name="ConnectIP" serializeAs="String">
+                <value>172.17.20.61</value>
+            </setting>
+            <setting name="ConnectPort" serializeAs="String">
+                <value>54188</value>
+            </setting>
+        </BellwetherBackend.Properties.Settings>
+    </userSettings>
+</configuration>

+ 18 - 0
BellwetherBackend/App.xaml

@@ -0,0 +1,18 @@
+<Application
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:local="clr-namespace:BellwetherBackend"
+    StartupUri="MainWindow.xaml"
+    x:Class="BellwetherBackend.App">
+    <Application.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.xaml" />
+                <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/ModernUI.Light.xaml" />
+                <ResourceDictionary Source="ModernWindowResource.xaml" />
+                <ResourceDictionary Source="/HistoryWallEditTool;component/Style.xaml" />
+                <ResourceDictionary Source="MyDictionary.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </Application.Resources>
+</Application>

+ 17 - 0
BellwetherBackend/App.xaml.cs

@@ -0,0 +1,17 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Data;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace BellwetherBackend
+{
+    /// <summary>
+    /// Interaction logic for App.xaml
+    /// </summary>
+    public partial class App : Application
+    {
+    }
+}

+ 4 - 0
BellwetherBackend/Assets/appbar.control.add.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_add" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="38" Height="38" Canvas.Left="19" Canvas.Top="19" Stretch="Fill" Fill="#FF000000" Data="F1 M 35,19L 41,19L 41,35L 57,35L 57,41L 41,41L 41,57L 35,57L 35,41L 19,41L 19,35L 35,35L 35,19 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.connect.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_image" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="42" Height="36" Canvas.Left="17" Canvas.Top="20" Stretch="Fill" Fill="#FF000000" Data="F1 M 25.3333,23.7501L 28.4999,23.7501L 28.5,33.25L 25.3333,33.2501L 25.3333,23.7501 Z M 30.0833,25.3335L 33.2499,25.3335L 33.25,39.5834L 30.0833,39.5834L 28.5,41.1667L 28.5,50.6667L 25.3333,50.6667L 25.3333,41.1667L 23.75,39.5834L 20.5833,39.5835L 20.5832,25.3335L 23.7499,25.3335L 23.7499,34.8334L 24.5416,34.8334L 29.2916,34.8334L 30.0833,34.8334L 30.0833,25.3335 Z M 30.0833,47.5L 30.0833,44.3334L 50.6667,44.3334L 50.6667,30.0833L 34.8333,30.0834L 34.8333,26.9167L 55.4166,26.9167L 55.4166,47.5L 41.1666,47.5L 41.1667,50.6667L 45.125,50.6667L 45.9166,53.8333L 33.25,53.8333L 34.0417,50.6667L 38,50.6667L 38,47.5L 30.0833,47.5 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.delete.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_delete" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="27.7083" Height="35.625" Canvas.Left="24.1458" Canvas.Top="19.7917" Stretch="Fill" Fill="#FF000000" Data="F1 M 25.3333,23.75L 50.6667,23.75C 51.5411,23.75 51.8541,27.3125 51.8541,27.3125L 24.1458,27.3125C 24.1458,27.3125 24.4589,23.75 25.3333,23.75 Z M 35.625,19.7917L 40.375,19.7917C 40.8122,19.7917 41.9583,20.9378 41.9583,21.375C 41.9583,21.8122 40.8122,22.9584 40.375,22.9584L 35.625,22.9584C 35.1878,22.9584 34.0416,21.8122 34.0416,21.375C 34.0416,20.9378 35.1878,19.7917 35.625,19.7917 Z M 27.7083,28.5L 48.2916,28.5C 49.1661,28.5 49.875,29.2089 49.875,30.0834L 48.2916,53.8334C 48.2916,54.7078 47.5828,55.4167 46.7083,55.4167L 29.2917,55.4167C 28.4172,55.4167 27.7083,54.7078 27.7083,53.8334L 26.125,30.0834C 26.125,29.2089 26.8339,28.5 27.7083,28.5 Z M 30.0833,31.6667L 30.4792,52.25L 33.25,52.25L 32.8542,31.6667L 30.0833,31.6667 Z M 36.4167,31.6667L 36.4167,52.25L 39.5833,52.25L 39.5833,31.6667L 36.4167,31.6667 Z M 43.1458,31.6667L 42.75,52.25L 45.5208,52.25L 45.9167,31.6667L 43.1458,31.6667 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.disconnect.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_image" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="42" Height="36" Canvas.Left="17" Canvas.Top="20" Stretch="Fill" Fill="#FF000000" Data="F1 M 48.0542,39.5833L 53.0417,44.5708L 58.0291,39.5834L 60.1666,41.7209L 55.1792,46.7083L 60.1667,51.6958L 58.0292,53.8333L 53.0417,48.8458L 48.0542,53.8333L 45.9167,51.6958L 50.9042,46.7083L 45.9167,41.7208L 48.0542,39.5833 Z M 23.7499,23.7501L 26.9166,23.7501L 26.9166,33.25L 23.75,33.2501L 23.7499,23.7501 Z M 28.4999,25.3335L 31.6666,25.3335L 31.6666,39.5835L 28.5,39.5834L 26.9166,41.1667L 26.9166,50.6667L 23.7499,50.6667L 23.75,41.1667L 22.1666,39.5834L 18.9999,39.5835L 18.9999,25.3335L 22.1666,25.3335L 22.1666,34.8334L 22.9583,34.8335L 27.7083,34.8334L 28.5,34.8334L 28.4999,25.3335 Z M 28.5,47.5001L 28.5,44.3334L 45.6792,44.3334L 48.0541,46.7083L 47.2624,47.5001L 39.5833,47.5L 39.5833,50.6667L 43.5416,50.6667L 44.3333,53.8334L 31.6667,53.8334L 32.4583,50.6667L 36.4166,50.6667L 36.4166,47.5L 28.5,47.5001 Z M 49.0833,30.0834L 33.25,30.0834L 33.25,26.9167L 53.8333,26.9167L 53.8332,40.9293L 53.0416,41.7209L 49.0833,37.7625L 49.0833,30.0834 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.downward.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_arrow_down" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="28" Height="39.25" Canvas.Left="24" Canvas.Top="19.0002" Stretch="Fill" Fill="#FF000000" Data="F1 M 42,19.0002L 34,19.0002L 34,43.7502L 24,33.7502L 24,44.2502L 38,58.2502L 52,44.2502L 52,33.7502L 42,43.7502L 42,19.0002 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.imgdelete.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_page_delete" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+	<Path Width="36" Height="42" Canvas.Left="20" Canvas.Top="17" Stretch="Fill" Fill="#FF000000" Data="F1 M 43,30L 50.75,30L 43,22.25L 43,30 Z M 52,34L 39,34L 39,21L 24,21L 24,39L 20,43L 20,17L 43.25,17L 56,29.75L 56,59L 36.5,59L 40.5,55L 52,55L 52,34 Z M 35.1379,40.67L 38.4967,44.0287L 32.8988,49.6266L 38.4967,55.2246L 35.1379,58.5833L 29.54,52.9854L 23.9421,58.5833L 20.5833,55.2246L 26.1813,49.6266L 20.5833,44.0287L 23.9421,40.67L 29.54,46.2679L 35.1379,40.67 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.map.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_image" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+	<Path Width="42" Height="36" Canvas.Left="17" Canvas.Top="20" Stretch="Fill" Fill="#FF000000" Data="F1 M 17,20L 59,20L 59,56L 17,56L 17,20 Z M 20,23L 20,53L 56,53L 56,23L 20,23 Z M 24,51L 30.0833,44.3333L 33.25,47.5L 45.9167,34.8333L 50.6667,39.5833L 54,36L 54,51L 24,51 Z M 30.0833,26.9167C 30.0833,30.4145 27.2478,33.25 23.75,33.25C 23.2033,33.25 22.5061,33.1302 22,33L 22,25L 29.6666,25C 29.7968,25.5061 30.0833,26.3699 30.0833,26.9167 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.update.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_inbox_out" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+	<Path Width="34.8333" Height="41.1666" Canvas.Left="20.5833" Canvas.Top="15.8334" Stretch="Fill" Fill="#FF000000" Data="F1 M 25.3333,52.25L 50.6667,52.25L 50.6667,45.9167L 55.4167,45.9167L 55.4167,57L 50.6667,57L 25.3333,57L 20.5833,57L 20.5833,45.9167L 25.3333,45.9167L 25.3333,52.25 Z M 34.8333,49.0834L 41.1667,49.0834L 41.1666,28.5L 49.0833,38L 49.0833,28.5L 38,15.8334L 26.9167,28.5L 26.9167,38L 34.8333,28.5L 34.8333,49.0834 Z "/>
+</Canvas>

+ 4 - 0
BellwetherBackend/Assets/appbar.control.upward.xaml

@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Name="appbar_arrow_up" Width="76" Height="76" Clip="F1 M 0,0L 76,0L 76,76L 0,76L 0,0">
+    <Path Width="28" Height="39.25" Canvas.Left="24" Canvas.Top="17.75" Stretch="Fill" Fill="#FF000000" Data="F1 M 34,57L 42,57L 42,32.25L 52,42.25L 52,31.75L 38,17.75L 24,31.75L 24,42.25L 34,32.25L 34,57 Z "/>
+</Canvas>

+ 193 - 0
BellwetherBackend/BellwetherBackend.csproj

@@ -0,0 +1,193 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{852F7BF5-E998-48D1-8512-5CD77F0E10C2}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>BellwetherBackend</RootNamespace>
+    <AssemblyName>BellwetherBackend</AssemblyName>
+    <TargetFrameworkVersion>v4.8</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+    <WarningLevel>4</WarningLevel>
+    <AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
+    <Deterministic>true</Deterministic>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="FirstFloor.ModernUI, Version=1.0.5.0, Culture=neutral, PublicKeyToken=2d21ec3cd074c59a, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\FirstFloor.ModernUI.dll</HintPath>
+    </Reference>
+    <Reference Include="ICSharpCode.SharpZipLib, Version=0.86.0.518, Culture=neutral, PublicKeyToken=1b03e6acf1164f73, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\ICSharpCode.SharpZipLib.dll</HintPath>
+    </Reference>
+    <Reference Include="Microsoft.Windows.Shell, Version=3.5.41019.1, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\Microsoft.Windows.Shell.dll</HintPath>
+    </Reference>
+    <Reference Include="Newtonsoft.Json, Version=4.5.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="SocketTransfer, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
+      <SpecificVersion>False</SpecificVersion>
+      <HintPath>DLL\SocketTransfer.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Xml" />
+    <Reference Include="Microsoft.CSharp" />
+    <Reference Include="System.Core" />
+    <Reference Include="System.Xml.Linq" />
+    <Reference Include="System.Data.DataSetExtensions" />
+    <Reference Include="System.Net.Http" />
+    <Reference Include="System.Xaml">
+      <RequiredTargetFramework>4.0</RequiredTargetFramework>
+    </Reference>
+    <Reference Include="WindowsBase" />
+    <Reference Include="PresentationCore" />
+    <Reference Include="PresentationFramework" />
+  </ItemGroup>
+  <ItemGroup>
+    <ApplicationDefinition Include="App.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </ApplicationDefinition>
+    <Compile Include="SubPage\UcBasicSetting.xaml.cs">
+      <DependentUpon>UcBasicSetting.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="SubPage\UpdatePage.xaml.cs">
+      <DependentUpon>UpdatePage.xaml</DependentUpon>
+    </Compile>
+    <Compile Include="Utility\GlobalFunction.cs" />
+    <Compile Include="Utility\Setting.cs" />
+    <EmbeddedResource Include="Assets\appbar.control.add.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.connect.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.delete.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.disconnect.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.downward.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.imgdelete.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.map.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.update.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Assets\appbar.control.upward.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Page Include="MainWindow.xaml">
+      <Generator>MSBuild:Compile</Generator>
+      <SubType>Designer</SubType>
+    </Page>
+    <Compile Include="App.xaml.cs">
+      <DependentUpon>App.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="MainWindow.xaml.cs">
+      <DependentUpon>MainWindow.xaml</DependentUpon>
+      <SubType>Code</SubType>
+    </Compile>
+    <Page Include="ModernWindowResource.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="MyDictionary.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="SubPage\UcBasicSetting.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+    <Page Include="SubPage\UpdatePage.xaml">
+      <SubType>Designer</SubType>
+      <Generator>MSBuild:Compile</Generator>
+    </Page>
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Properties\AssemblyInfo.cs">
+      <SubType>Code</SubType>
+    </Compile>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="App.config" />
+  </ItemGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\HistoryWallEditTool\HistoryWallEditTool\HistoryWallEditTool.csproj">
+      <Project>{94fe2ac5-787c-41d0-882a-61da973ea378}</Project>
+      <Name>HistoryWallEditTool</Name>
+    </ProjectReference>
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="DLL\FirstFloor.ModernUI.dll" />
+    <Content Include="DLL\ICSharpCode.SharpZipLib.dll" />
+    <Content Include="DLL\Microsoft.Windows.Shell.dll" />
+    <Content Include="DLL\Microsoft.WindowsAPICodePack.dll" />
+    <Content Include="DLL\Microsoft.WindowsAPICodePack.Shell.dll" />
+    <Content Include="DLL\Newtonsoft.Json.dll" />
+    <Content Include="DLL\SocketTransfer.dll" />
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

BIN
BellwetherBackend/DLL/FirstFloor.ModernUI.dll


BIN
BellwetherBackend/DLL/ICSharpCode.SharpZipLib.dll


BIN
BellwetherBackend/DLL/Microsoft.Windows.Shell.dll


BIN
BellwetherBackend/DLL/Microsoft.WindowsAPICodePack.Shell.dll


BIN
BellwetherBackend/DLL/Microsoft.WindowsAPICodePack.dll


BIN
BellwetherBackend/DLL/Newtonsoft.Json.dll


BIN
BellwetherBackend/DLL/SocketTransfer.dll


+ 63 - 0
BellwetherBackend/MainWindow.xaml

@@ -0,0 +1,63 @@
+<Window
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:BellwetherBackend"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    Title="貝爾威勒"
+    Width="1920"
+    Height="1080"
+    WindowState="Maximized"
+    mc:Ignorable="d"
+    x:Class="BellwetherBackend.MainWindow">
+    <Viewbox Stretch="Uniform">
+        <Grid Width="1920" Height="1080">
+            <Grid.RowDefinitions>
+                <RowDefinition Height="20" />
+                <RowDefinition Height="159.847" />
+                <RowDefinition Height="5" />
+                <RowDefinition Height="*" />
+            </Grid.RowDefinitions>
+            <Rectangle Grid.Row="2" Fill="Green" />
+            <WrapPanel
+                x:Name="uxTopRButtonParent"
+                Grid.RowSpan="3"
+                Width="1100"
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
+                Orientation="Horizontal">
+                <RadioButton
+                    Checked="RadioButton_Checked"
+                    Content="首頁設定"
+                    Style="{StaticResource uxTopRadioButton}" />
+                <RadioButton
+                    Checked="RadioButton_Checked"
+                    Content="大事記"
+                    Style="{StaticResource uxTopRadioButton}" />
+                <RadioButton
+                    Checked="RadioButton_Checked"
+                    Content="產品展示"
+                    Style="{StaticResource uxTopRadioButton}" />
+                <RadioButton
+                    Checked="RadioButton_Checked"
+                    Content="社會責任"
+                    Style="{StaticResource uxTopRadioButton}" />
+                <RadioButton
+                    Checked="RadioButton_Checked"
+                    Content="上傳"
+                    Style="{StaticResource uxTopRadioButton}" />
+            </WrapPanel>
+            <Grid Grid.Row="3">
+                <Grid.ColumnDefinitions>
+                    <ColumnDefinition Width="*" />
+                    <ColumnDefinition Width="auto" />
+                    <ColumnDefinition Width="*" />
+                </Grid.ColumnDefinitions>
+                <Grid
+                    x:Name="uxMainGrid"
+                    Grid.Column="1"
+                    HorizontalAlignment="Center" />
+            </Grid>
+        </Grid>
+    </Viewbox>
+</Window>

+ 85 - 0
BellwetherBackend/MainWindow.xaml.cs

@@ -0,0 +1,85 @@
+using BellwetherBackend.Utility;
+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.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace BellwetherBackend
+{
+    /// <summary>
+    /// Interaction logic for MainWindow.xaml
+    /// </summary>
+    public partial class MainWindow : Window
+    {
+        private UIElement currentPage;
+
+        public MainWindow()
+        {
+            InitializeComponent();
+        }
+
+        private void RadioButton_Checked(object sender, RoutedEventArgs e)
+        {
+            SaveCurrentPage();
+            int selectedTab = uxTopRButtonParent.Children.IndexOf(sender as UIElement);
+            if (selectedTab == 0)
+            {
+                currentPage = new SubPage.UcBasicSetting();
+                uxMainGrid.Children.Clear();
+                uxMainGrid.Children.Add(currentPage);
+            }
+            else if (selectedTab == 4)
+            {
+                currentPage = new SubPage.UpdatePage();
+                uxMainGrid.Children.Clear();
+                uxMainGrid.Children.Add(currentPage);
+            }
+            else
+            {
+                string pageFolderName = null;
+
+                if (selectedTab == 1)
+                    pageFolderName = Setting.PageFolderName[Setting.PageType.History];
+                else if (selectedTab == 2)
+                    pageFolderName = Setting.PageFolderName[Setting.PageType.Product];
+                else if (selectedTab == 3)
+                    pageFolderName = Setting.PageFolderName[Setting.PageType.CSR];
+
+                if (!string.IsNullOrEmpty(pageFolderName))
+                {
+                    HistoryWallEditTool.GlobalFunction.historyWalldataFolderName = pageFolderName;
+                    currentPage = new HistoryWallEditTool.HistoryWall();
+
+                    uxMainGrid.Children.Clear();
+                    uxMainGrid.Children.Add(currentPage);
+                }
+            }
+        }
+
+        private void SaveCurrentPage()
+        {
+            if (currentPage is HistoryWallEditTool.HistoryWall histortywall)
+            {
+                histortywall.SaveWholeConfig();
+            }
+            else if (currentPage is SubPage.UcBasicSetting basicSetting)
+            {
+
+            }
+            else if (currentPage is SubPage.UpdatePage updatePage)
+            {
+                updatePage.Disconnect();
+            }
+        }
+    }
+}

+ 236 - 0
BellwetherBackend/ModernWindowResource.xaml

@@ -0,0 +1,236 @@
+<ResourceDictionary
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:controls="http://firstfloorsoftware.com/ModernUI"
+    xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell">
+
+    <ResourceDictionary.MergedDictionaries>
+        <ResourceDictionary Source="/FirstFloor.ModernUI;component/Assets/Button.xaml" />
+    </ResourceDictionary.MergedDictionaries>
+
+    <!--  additional ModernWindow styles  -->
+
+    <!--  empty window style, no backbutton, menu, title links and logo  -->
+    <Style
+        x:Key="MyEmptyWindow"
+        BasedOn="{StaticResource {x:Type controls:ModernWindow}}"
+        TargetType="{x:Type controls:ModernWindow}">
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="{x:Type controls:ModernWindow}">
+                    <Border x:Name="WindowBorder" Margin="{Binding Source={x:Static shell:SystemParameters2.Current}, Path=WindowNonClientFrameThickness}">
+                        <Border.Background>
+                            <SolidColorBrush x:Name="WindowBorderBackground" Color="{DynamicResource WindowBackgroundColor}" />
+                        </Border.Background>
+                        <Border.Resources>
+                            <Storyboard x:Key="BackgroundAnimation">
+                                <ColorAnimation
+                                    Storyboard.TargetName="WindowBorderBackground"
+                                    Storyboard.TargetProperty="Color"
+                                    To="{DynamicResource WindowBackgroundColor}"
+                                    Duration="0:0:.6" />
+                            </Storyboard>
+                        </Border.Resources>
+
+                        <Grid>
+                            <Border BorderBrush="{DynamicResource WindowBorder}" BorderThickness="1">
+                                <AdornerDecorator>
+                                    <Grid x:Name="LayoutRoot">
+                                        <Grid.RowDefinitions>
+                                            <RowDefinition Height="*" />
+                                            <RowDefinition Height="15" />
+                                        </Grid.RowDefinitions>
+
+                                        <!--  window background content  -->
+                                        <ContentControl Grid.RowSpan="2" Content="{TemplateBinding BackgroundContent}" />
+
+                                        <!--  window content  -->
+                                        <ContentControl Grid.RowSpan="2" Content="{TemplateBinding Content}" />
+
+                                        <!--  title blob  -->
+                                        <Border
+                                            Grid.RowSpan="2"
+                                            MinWidth="500"
+                                            MinHeight="53"
+                                            HorizontalAlignment="Left"
+                                            VerticalAlignment="Top"
+                                            Background="Transparent"
+                                            RenderTransform="1,0,0,1,-10,-10">
+                                            <TextBlock
+                                                Margin="0,8"
+                                                VerticalAlignment="Center"
+                                                Text="{TemplateBinding Title,
+                                                                       Converter={StaticResource ToUpperConverter}}"
+                                                FontSize="50"
+                                                DataContext="{TemplateBinding IsTitleVisible}"
+                                                Foreground="White"
+                                                Style="{DynamicResource ModernWindowTitle}"
+                                                Visibility="Visible">
+                                                <TextBlock.Effect>
+                                                    <DropShadowEffect
+                                                        BlurRadius="2"
+                                                        Direction="330"
+                                                        Opacity="0.3"
+                                                        ShadowDepth="3"
+                                                        Color="LightGray" />
+                                                </TextBlock.Effect>
+                                                <TextBlock.OpacityMask>
+                                                    <LinearGradientBrush StartPoint="0.5,0.1" EndPoint="0.5,0.9">
+                                                        <LinearGradientBrush.GradientStops>
+                                                            <GradientStop Offset="0" Color="White" />
+                                                            <GradientStop Offset="1" Color="Transparent" />
+                                                        </LinearGradientBrush.GradientStops>
+                                                    </LinearGradientBrush>
+                                                </TextBlock.OpacityMask>
+                                            </TextBlock>
+                                        </Border>
+
+                                        <!--  window system buttons  -->
+                                        <Grid
+                                            Width="1920"
+                                            Height="20"
+                                            HorizontalAlignment="Left"
+                                            VerticalAlignment="Top"
+                                            Background="Transparent"
+                                            Opacity="1" />
+                                        <StackPanel
+                                            Margin="0,8,6,0"
+                                            HorizontalAlignment="Right"
+                                            VerticalAlignment="Top"
+                                            shell:WindowChrome.IsHitTestVisibleInChrome="True"
+                                            Orientation="Horizontal"
+                                            Visibility="Visible">
+                                            <Button
+                                                Command="{Binding Source={x:Static shell:SystemCommands.MinimizeWindowCommand}}"
+                                                Style="{StaticResource SystemButton}"
+                                                ToolTip="minimize">
+                                                <Button.Content>
+                                                    <Grid
+                                                        Width="13"
+                                                        Height="12"
+                                                        RenderTransform="1,0,0,1,0,1">
+                                                        <Path
+                                                            Width="8"
+                                                            Height="7"
+                                                            HorizontalAlignment="Center"
+                                                            VerticalAlignment="Center"
+                                                            Data="M0,6 L8,6 Z"
+                                                            Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"
+                                                            StrokeThickness="2" />
+                                                    </Grid>
+                                                </Button.Content>
+                                            </Button>
+                                            <Grid Margin="1,0,1,0">
+                                                <Button
+                                                    x:Name="Restore"
+                                                    Command="{Binding Source={x:Static shell:SystemCommands.RestoreWindowCommand}}"
+                                                    Style="{StaticResource SystemButton}"
+                                                    ToolTip="restore"
+                                                    Visibility="Collapsed">
+                                                    <Button.Content>
+                                                        <Grid
+                                                            Width="13"
+                                                            Height="12"
+                                                            RenderTransform="1,0,0,1,.5,.5"
+                                                            UseLayoutRounding="True">
+                                                            <Path
+                                                                Width="8"
+                                                                Height="8"
+                                                                HorizontalAlignment="Center"
+                                                                VerticalAlignment="Center"
+                                                                Data="M2,0 L8,0 L8,6 M0,3 L6,3 M0,2 L6,2 L6,8 L0,8 Z"
+                                                                Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"
+                                                                StrokeThickness="1" />
+                                                        </Grid>
+                                                    </Button.Content>
+                                                </Button>
+                                                <Button
+                                                    x:Name="Maximize"
+                                                    Command="{Binding Source={x:Static shell:SystemCommands.MaximizeWindowCommand}}"
+                                                    Style="{StaticResource SystemButton}"
+                                                    ToolTip="maximize"
+                                                    Visibility="Collapsed">
+                                                    <Button.Content>
+                                                        <Grid Width="13" Height="12">
+                                                            <Path
+                                                                Width="9"
+                                                                Height="8"
+                                                                HorizontalAlignment="Center"
+                                                                VerticalAlignment="Center"
+                                                                Data="M0,1 L9,1 L9,8 L0,8 Z"
+                                                                Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"
+                                                                StrokeThickness="2" />
+                                                        </Grid>
+                                                    </Button.Content>
+                                                </Button>
+                                            </Grid>
+                                            <Button
+                                                Command="{Binding Source={x:Static shell:SystemCommands.CloseWindowCommand}}"
+                                                Style="{StaticResource SystemButton}"
+                                                ToolTip="close"
+                                                Visibility="Visible">
+                                                <Button.Content>
+                                                    <Grid
+                                                        Width="13"
+                                                        Height="12"
+                                                        RenderTransform="1,0,0,1,0,1">
+                                                        <Path
+                                                            Width="8"
+                                                            Height="7"
+                                                            HorizontalAlignment="Center"
+                                                            VerticalAlignment="Center"
+                                                            Data="M0,0 L8,7 M8,0 L0,7 Z"
+                                                            Stroke="{Binding Foreground, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Button}}"
+                                                            StrokeThickness="1.5" />
+                                                    </Grid>
+                                                </Button.Content>
+                                            </Button>
+                                        </StackPanel>
+
+                                        <!--  resize grip  -->
+                                        <Grid Grid.Row="1">
+                                            <Path
+                                                x:Name="ResizeGrip"
+                                                Width="12"
+                                                Height="12"
+                                                Margin="1"
+                                                HorizontalAlignment="Right"
+                                                Data="F1 M1,10 L3,10 M5,10 L7,10 M9,10 L11,10 M2,9 L2,11 M6,9 L6,11 M10,9 L10,11 M5,6 L7,6 M9,6 L11,6 M6,5 L6,7 M10,5 L10,7 M9,2 L11,2 M10,1 L10,3"
+                                                Stretch="None"
+                                                Stroke="{DynamicResource WindowText}"
+                                                StrokeThickness="1"
+                                                Visibility="Collapsed" />
+                                        </Grid>
+                                    </Grid>
+                                </AdornerDecorator>
+                            </Border>
+                            <Border
+                                BorderBrush="{DynamicResource WindowBorderActive}"
+                                BorderThickness="1"
+                                Visibility="{Binding IsActive, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Converter={StaticResource BooleanToVisibilityConverter}}" />
+                        </Grid>
+                    </Border>
+
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="WindowState" Value="Maximized">
+                            <Setter TargetName="Maximize" Property="Visibility" Value="Collapsed" />
+                            <Setter TargetName="Restore" Property="Visibility" Value="Visible" />
+                            <Setter TargetName="LayoutRoot" Property="Margin" Value="7" />
+                        </Trigger>
+                        <Trigger Property="WindowState" Value="Normal">
+                            <Setter TargetName="Maximize" Property="Visibility" Value="Visible" />
+                            <Setter TargetName="Restore" Property="Visibility" Value="Collapsed" />
+                        </Trigger>
+                        <MultiTrigger>
+                            <MultiTrigger.Conditions>
+                                <Condition Property="ResizeMode" Value="CanResizeWithGrip" />
+                                <Condition Property="WindowState" Value="Normal" />
+                            </MultiTrigger.Conditions>
+                            <Setter TargetName="ResizeGrip" Property="Visibility" Value="Visible" />
+                        </MultiTrigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+</ResourceDictionary>

+ 114 - 0
BellwetherBackend/MyDictionary.xaml

@@ -0,0 +1,114 @@
+<ResourceDictionary
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:controls="http://firstfloorsoftware.com/ModernUI"
+    xmlns:shell="http://schemas.microsoft.com/winfx/2006/xaml/presentation/shell">
+    <Style x:Key="ProcessRadioButton" TargetType="{x:Type RadioButton}">
+        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
+        <Setter Property="Height" Value="60" />
+        <Setter Property="Width" Value="150" />
+        <Setter Property="Margin" Value="5" />
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="{x:Type RadioButton}">
+                    <Border
+                        BorderBrush="Black"
+                        BorderThickness="2"
+                        CornerRadius="5">
+                        <Border
+                            x:Name="uxRootGrid"
+                            Width="{TemplateBinding Width}"
+                            Height="{TemplateBinding Height}"
+                            Background="Transparent"
+                            BorderBrush="Gray"
+                            FocusVisualStyle="{x:Null}"
+                            Stylus.IsPressAndHoldEnabled="False">
+                            <TextBlock
+                                x:Name="uxTextBlock"
+                                HorizontalAlignment="Center"
+                                VerticalAlignment="Center"
+                                Text="{TemplateBinding Content}"
+                                FontSize="18"
+                                FocusVisualStyle="{x:Null}"
+                                Foreground="Black"
+                                TextAlignment="Center" />
+                        </Border>
+                    </Border>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsMouseOver" Value="true">
+                            <Setter TargetName="uxRootGrid" Property="Background" Value="LightGray" />
+                            <Setter TargetName="uxTextBlock" Property="FontSize" Value="25" />
+                        </Trigger>
+                        <Trigger Property="IsChecked" Value="true">
+                            <Setter TargetName="uxRootGrid" Property="Background" Value="#FF0E6EB8" />
+                            <Setter TargetName="uxTextBlock" Property="Foreground" Value="White" />
+                            <Setter TargetName="uxTextBlock" Property="FontSize" Value="20" />
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+    <Style x:Key="uxTopRadioButton" TargetType="{x:Type RadioButton}">
+        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
+        <Setter Property="Height" Value="65" />
+        <Setter Property="Width" Value="200" />
+        <Setter Property="Margin" Value="10" />
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="{x:Type RadioButton}">
+                    <Grid
+                        x:Name="uxRootGrid"
+                        Width="{TemplateBinding Width}"
+                        Height="{TemplateBinding Height}"
+                        FocusVisualStyle="{x:Null}"
+                        Stylus.IsPressAndHoldEnabled="False">
+                        <Border
+                            x:Name="uxBorder"
+                            Width="{TemplateBinding Width}"
+                            Height="{TemplateBinding Height}"
+                            HorizontalAlignment="Left"
+                            VerticalAlignment="Top"
+                            Background="White"
+                            BorderBrush="Black"
+                            BorderThickness="1"
+                            CornerRadius="0"
+                            FocusVisualStyle="{x:Null}" />
+                        <TextBlock
+                            x:Name="uxTextBlock"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Text="{TemplateBinding Content}"
+                            FontSize="20"
+                            FocusVisualStyle="{x:Null}"
+                            Foreground="Black" />
+                    </Grid>
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsChecked" Value="true">
+                            <Setter TargetName="uxBorder" Property="Background" Value="#FF0E6EB8" />
+                            <Setter TargetName="uxTextBlock" Property="Foreground" Value="White" />
+                        </Trigger>
+                        <Trigger Property="IsMouseOver" Value="true">
+                            <Setter TargetName="uxTextBlock" Property="FontSize" Value="21" />
+                        </Trigger>
+                        <Trigger Property="IsEnabled" Value="False">
+                            <Setter TargetName="uxTextBlock" Property="Opacity" Value="0.5" />
+                            <Setter TargetName="uxBorder" Property="Background" Value="LightGray" />
+                        </Trigger>
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+    <Style x:Key="uxTexBoxStyle" TargetType="{x:Type TextBox}">
+        <Setter Property="Template">
+            <Setter.Value>
+                <ControlTemplate TargetType="{x:Type TextBox}">
+                    <ControlTemplate.Triggers>
+                        <Trigger Property="IsMouseOver" Value="true" />
+                    </ControlTemplate.Triggers>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
+</ResourceDictionary>

+ 55 - 0
BellwetherBackend/Properties/AssemblyInfo.cs

@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("BellwetherBackend")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("BellwetherBackend")]
+[assembly: AssemblyCopyright("Copyright ©  2021")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components.  If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
+//inside a <PropertyGroup>.  For example, if you are using US english
+//in your source files, set the <UICulture> to en-US.  Then uncomment
+//the NeutralResourceLanguage attribute below.  Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly: ThemeInfo(
+    ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+                                     //(used if a resource is not found in the page,
+                                     // or application resource dictionaries)
+    ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+                                              //(used if a resource is not found in the page,
+                                              // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+//      Major Version
+//      Minor Version
+//      Build Number
+//      Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 70 - 0
BellwetherBackend/Properties/Resources.Designer.cs

@@ -0,0 +1,70 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+
+namespace BellwetherBackend.Properties
+{
+    /// <summary>
+    ///   A strongly-typed resource class, for looking up localized strings, etc.
+    /// </summary>
+    // This class was auto-generated by the StronglyTypedResourceBuilder
+    // class via a tool like ResGen or Visual Studio.
+    // To add or remove a member, edit your .ResX file then rerun ResGen
+    // with the /str option, or rebuild your VS project.
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   Returns the cached ResourceManager instance used by this class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("BellwetherBackend.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   Overrides the current thread's CurrentUICulture property for all
+        ///   resource lookups using this strongly typed resource class.
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
BellwetherBackend/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 50 - 0
BellwetherBackend/Properties/Settings.Designer.cs

@@ -0,0 +1,50 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     This code was generated by a tool.
+//     Runtime Version:4.0.30319.42000
+//
+//     Changes to this file may cause incorrect behavior and will be lost if
+//     the code is regenerated.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace BellwetherBackend.Properties {
+    
+    
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.10.0.0")]
+    internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
+        
+        private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+        
+        public static Settings Default {
+            get {
+                return defaultInstance;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("172.17.20.61")]
+        public string ConnectIP {
+            get {
+                return ((string)(this["ConnectIP"]));
+            }
+            set {
+                this["ConnectIP"] = value;
+            }
+        }
+        
+        [global::System.Configuration.UserScopedSettingAttribute()]
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+        [global::System.Configuration.DefaultSettingValueAttribute("54188")]
+        public int ConnectPort {
+            get {
+                return ((int)(this["ConnectPort"]));
+            }
+            set {
+                this["ConnectPort"] = value;
+            }
+        }
+    }
+}

+ 12 - 0
BellwetherBackend/Properties/Settings.settings

@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)" GeneratedClassNamespace="BellwetherBackend.Properties" GeneratedClassName="Settings">
+  <Profiles />
+  <Settings>
+    <Setting Name="ConnectIP" Type="System.String" Scope="User">
+      <Value Profile="(Default)">172.17.20.61</Value>
+    </Setting>
+    <Setting Name="ConnectPort" Type="System.Int32" Scope="User">
+      <Value Profile="(Default)">54188</Value>
+    </Setting>
+  </Settings>
+</SettingsFile>

+ 46 - 0
BellwetherBackend/SubPage/UcBasicSetting.xaml

@@ -0,0 +1,46 @@
+<UserControl
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:BellwetherBackend.SubPage"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="BellwetherBackend.SubPage.UcBasicSetting">
+    <Grid Background="White">
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="15" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="15" />
+                <RowDefinition Height="Auto" />
+                <RowDefinition Height="15" />
+            </Grid.RowDefinitions>
+            <StackPanel
+                Grid.Row="1"
+                Height="35"
+                Orientation="Horizontal">
+                <TextBlock VerticalAlignment="Center" Text="自動回首頁時間" />
+                <Rectangle Width="20" />
+                <TextBox
+                    x:Name="uxBackHomeSecText"
+                    Width="100"
+                    TextChanged="uxBackHomeSecText_TextChanged" />
+                <Rectangle Width="20" />
+                <TextBlock VerticalAlignment="Center" Text="秒" />
+            </StackPanel>
+            <StackPanel
+                Grid.Row="3"
+                Height="35"
+                Orientation="Horizontal">
+                <TextBlock VerticalAlignment="Center" Text="太陽能url" />
+                <Rectangle Width="20" />
+                <TextBox
+                    x:Name="uxSolarEnergyUrlText"
+                    Width="500"
+                    TextChanged="uxBackHomeSecText_TextChanged" />
+            </StackPanel>
+        </Grid>
+    </Grid>
+</UserControl>

+ 51 - 0
BellwetherBackend/SubPage/UcBasicSetting.xaml.cs

@@ -0,0 +1,51 @@
+using BellwetherBackend.Utility;
+using System;
+using System.Windows.Controls;
+
+namespace BellwetherBackend.SubPage
+{
+    /// <summary>
+    /// Interaction logic for UcBasicSetting.xaml
+    /// </summary>
+    public partial class UcBasicSetting : UserControl
+    {
+        private Utility.SettingJson settingJson;
+
+        public UcBasicSetting()
+        {
+            InitializeComponent();
+
+            LoadSettingData();
+        }
+
+        private void LoadSettingData()
+        {
+            settingJson = Setting.settingJsonFile;
+
+            uxBackHomeSecText.Text = settingJson.BackHomeSec.ToString();
+        }
+
+        private void SaveData()
+        {
+            Setting.settingJsonFile = settingJson;
+        }
+
+        private void uxBackHomeSecText_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            if (this.IsLoaded)
+            {
+                uxBackHomeSecText.TextChanged -= uxBackHomeSecText_TextChanged;
+                if (Int32.TryParse(uxBackHomeSecText.Text, out int result))
+                {
+                    settingJson.BackHomeSec = result;
+                    SaveData();
+                }
+                else
+                {
+                    uxBackHomeSecText.Text = settingJson.BackHomeSec.ToString();
+                }
+                uxBackHomeSecText.TextChanged += uxBackHomeSecText_TextChanged;
+            }
+        }
+    }
+}

+ 202 - 0
BellwetherBackend/SubPage/UpdatePage.xaml

@@ -0,0 +1,202 @@
+<UserControl
+    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+    xmlns:local="clr-namespace:BellwetherBackend.SubPage"
+    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+    xmlns:mui="http://firstfloorsoftware.com/ModernUI"
+    d:DesignHeight="450"
+    d:DesignWidth="800"
+    mc:Ignorable="d"
+    x:Class="BellwetherBackend.SubPage.UpdatePage">
+    <Grid HorizontalAlignment="Center">
+        <Grid.ColumnDefinitions>
+            <ColumnDefinition Width="200" />
+            <ColumnDefinition Width="300" />
+            <ColumnDefinition Width="610" />
+            <ColumnDefinition Width="360" />
+            <ColumnDefinition Width="350" />
+        </Grid.ColumnDefinitions>
+        <Grid Grid.Column="1">
+            <StackPanel
+                x:Name="uxUpdateListPanel"
+                HorizontalAlignment="Center"
+                VerticalAlignment="Center"
+                Orientation="Vertical">
+                <TextBlock
+                    Width="280"
+                    Height="38"
+                    Margin="0,0,0,10"
+                    FontSize="30"
+                    TextAlignment="Center">
+                    更新項目選擇 :
+                </TextBlock>
+                <Border BorderBrush="Black" BorderThickness="2" />
+                <CheckBox
+                    Width="280"
+                    Height="50"
+                    FontSize="30"
+                    IsChecked="True"
+                    Tag="Basic">
+                    基本設定
+                </CheckBox>
+                <CheckBox
+                    Width="280"
+                    Height="50"
+                    FontSize="30"
+                    IsChecked="True"
+                    Tag="History">
+                    大事紀
+                </CheckBox>
+                <CheckBox
+                    Width="280"
+                    Height="50"
+                    FontSize="30"
+                    IsChecked="True"
+                    Tag="Product">
+                    產品展示
+                </CheckBox>
+                <CheckBox
+                    Width="280"
+                    Height="50"
+                    FontSize="30"
+                    IsChecked="True"
+                    Tag="CSR">
+                    社會責任
+                </CheckBox>
+            </StackPanel>
+        </Grid>
+        <Grid Grid.Column="2" VerticalAlignment="Center">
+            <StackPanel Orientation="Vertical">
+                <Grid Name="uxWorkingGrid">
+                    <Grid.ColumnDefinitions>
+                        <ColumnDefinition Width="2.5*" />
+                        <ColumnDefinition Width="0.5*" />
+                    </Grid.ColumnDefinitions>
+                    <Grid Name="uxIpGrid" Grid.Column="0">
+                        <Grid.ColumnDefinitions>
+                            <ColumnDefinition Width="0.3*" />
+                            <ColumnDefinition Width="0.1*" />
+                            <ColumnDefinition Width="2*" />
+                            <ColumnDefinition Width="0.1*" />
+                            <ColumnDefinition Width="2*" />
+                            <ColumnDefinition Width="0.1*" />
+                            <ColumnDefinition Width="2*" />
+                            <ColumnDefinition Width="0.1*" />
+                            <ColumnDefinition Width="2*" />
+                        </Grid.ColumnDefinitions>
+                        <Rectangle
+                            Name="uxConnectStateRect"
+                            Grid.Column="0"
+                            Margin="0,1,1,1"
+                            Fill="Red" />
+                        <TextBox
+                            Name="uxIp1Text"
+                            Grid.Column="2"
+                            Margin="2"
+                            HorizontalContentAlignment="Center"
+                            VerticalContentAlignment="Center"
+                            MaxLength="3" />
+                        <TextBlock
+                            Grid.Column="3"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Text="." />
+                        <TextBox
+                            Name="uxIp2Text"
+                            Grid.Column="4"
+                            Margin="2"
+                            HorizontalContentAlignment="Center"
+                            VerticalContentAlignment="Center"
+                            MaxLength="3" />
+                        <TextBlock
+                            Grid.Column="5"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Text="." />
+                        <TextBox
+                            Name="uxIp3Text"
+                            Grid.Column="6"
+                            Margin="2"
+                            HorizontalContentAlignment="Center"
+                            VerticalContentAlignment="Center"
+                            MaxLength="3" />
+                        <TextBlock
+                            Grid.Column="7"
+                            HorizontalAlignment="Center"
+                            VerticalAlignment="Center"
+                            Text="." />
+                        <TextBox
+                            Name="uxIp4Text"
+                            Grid.Column="8"
+                            Margin="2"
+                            HorizontalContentAlignment="Center"
+                            VerticalContentAlignment="Center"
+                            MaxLength="3" />
+                    </Grid>
+                    <StackPanel Grid.Column="1" Orientation="Horizontal">
+                        <mui:ModernButton
+                            Name="uxConnectBtn"
+                            Grid.Column="1"
+                            Margin="4,0,0,0"
+                            Background="White"
+                            Click="uxConnect_Click"
+                            EllipseDiameter="45"
+                            IconHeight="18"
+                            IconWidth="18"
+                            ToolTip="連線" />
+                        <mui:ModernButton
+                            Name="uxDisConnectBtn"
+                            Margin="2,0,0,0"
+                            Background="White"
+                            Click="uxDisConnectBtn_Click"
+                            EllipseDiameter="45"
+                            IconHeight="18"
+                            IconWidth="18"
+                            IsEnabled="False"
+                            ToolTip="中斷連線" />
+                    </StackPanel>
+                </Grid>
+                <ProgressBar
+                    Name="uxProgressBar"
+                    Grid.ColumnSpan="7"
+                    IsIndeterminate="True"
+                    Visibility="Collapsed" />
+            </StackPanel>
+        </Grid>
+        <Grid Grid.Column="3" VerticalAlignment="Center">
+            <StackPanel Orientation="Horizontal">
+                <Grid>
+                    <ProgressBar
+                        x:Name="uxUpdateProgressBar"
+                        Width="300"
+                        Height="26"
+                        BorderBrush="#FF786A6A"
+                        Foreground="#FFEF5353"
+                        Maximum="100"
+                        Minimum="0" />
+                </Grid>
+                <mui:ModernButton
+                    Name="uxUpdateBtn"
+                    Margin="2,0,0,0"
+                    HorizontalAlignment="Right"
+                    Background="White"
+                    Click="uxUpdateBtn_Click"
+                    EllipseDiameter="45"
+                    IconHeight="18"
+                    IconWidth="18"
+                    IsEnabled="False"
+                    ToolTip="開啟更新" />
+            </StackPanel>
+        </Grid>
+        <Grid Grid.Column="4" VerticalAlignment="Center">
+            <StackPanel Orientation="Vertical">
+                <TextBlock
+                    x:Name="uxStatus"
+                    Height="45"
+                    Margin="5,0,0,0"
+                    FontSize="30" />
+            </StackPanel>
+        </Grid>
+    </Grid>
+</UserControl>

+ 768 - 0
BellwetherBackend/SubPage/UpdatePage.xaml.cs

@@ -0,0 +1,768 @@
+using BellwetherBackend.Utility;
+using SocketTransfer;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+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.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+using System.IO;
+using System.Windows.Threading;
+using ICSharpCode.SharpZipLib.Zip;
+using System.Threading;
+using System.Net;
+
+namespace BellwetherBackend.SubPage
+{
+    public enum UpdateState
+    {
+        TransferCompleted, Transferring, Disconnected, UpdateCompleted, UpdateFail, Abort, Connected
+    }
+
+    /// <summary>
+    /// Interaction logic for UpdatePage.xaml
+    /// </summary>
+    public partial class UpdatePage : UserControl
+    {
+        private static SolidColorBrush IsConnectBrush = new SolidColorBrush(Colors.Green);
+        private static SolidColorBrush IsDisconnectBrush = new SolidColorBrush(Colors.Red);
+        private static string rootPath = System.AppDomain.CurrentDomain.BaseDirectory;
+        private static string tempFolder = @"Temp\";
+        private static string defaultZipFileName = @"Temp\Data.zip";
+
+        private string ipAddress;
+        public string IpAddress
+        {
+            get
+            {
+                if (CheckIpFormat(uxIp1Text.Text) && CheckIpFormat(uxIp2Text.Text) && CheckIpFormat(uxIp3Text.Text) && CheckIpFormat(uxIp4Text.Text))
+                {
+                    ipAddress = String.Format("{0}.{1}.{2}.{3}", uxIp1Text.Text, uxIp2Text.Text, uxIp3Text.Text, uxIp4Text.Text);
+                }
+                else
+                {
+                    ipAddress = "error format";
+                }
+                return ipAddress;
+            }
+            set
+            {
+                ipAddress = value;
+                string[] str = ipAddress.Split('.');
+                if (str.Length > 3)
+                {
+                    for (int i = 0; i < ipTextBlock.Length; i++)
+                    {
+                        ipTextBlock[i].Text = str[i];
+                    }
+                }
+                this.Dispatcher.BeginInvoke((Action)delegate ()
+                {
+                    CheckKioskConnect();
+                });
+            }
+        }
+
+        private int ipPort;
+        public int IpPort
+        {
+            set { ipPort = value; }
+            get { return ipPort; }
+        }
+
+        private bool isConnect;
+        public bool IsConnect
+        {
+            get { return isConnect; }
+            set
+            {
+                isConnect = value;
+                if (isConnect)
+                {
+                    uxConnectStateRect.Fill = IsConnectBrush;
+                    uxConnectBtn.IsEnabled = false;
+                    uxDisConnectBtn.IsEnabled = true;
+                    uxIpGrid.IsEnabled = false;
+                    uxUpdateBtn.IsEnabled = true;
+                    UpdatingState = UpdateState.Connected;
+                }
+                else
+                {
+                    uxConnectStateRect.Fill = IsDisconnectBrush;
+                    uxConnectBtn.IsEnabled = true;
+                    uxDisConnectBtn.IsEnabled = false;
+                    uxIpGrid.IsEnabled = true;
+                    uxUpdateBtn.IsEnabled = false;
+                    UpdatingState = UpdateState.Disconnected;
+                }
+            }
+        }
+
+        private UpdateState updatingState;
+        public UpdateState UpdatingState
+        {
+            get { return updatingState; }
+            set
+            {
+                updatingState = value;
+            }
+        }
+
+        private string localipAddress;
+        private TextBox[] ipTextBlock;
+        private BackgroundWorker connectWorker;
+        private SocketClient KioskSocketClient;
+
+        private bool canTransFileTag = false;
+        private List<string> wholeDataFolder = new List<string>();
+        private List<string> cutFilePaths = new List<string>();
+
+        public UpdatePage()
+        {
+            InitializeComponent();
+
+            CreateTempFolder();
+
+
+            new GlobalFunction();
+            uxConnectBtn.IconData = GlobalFunction.ConnectBtnData;
+            uxDisConnectBtn.IconData = GlobalFunction.DisconnectBtnData;
+            uxUpdateBtn.IconData = GlobalFunction.UpdateBtnData;
+
+            localipAddress = GetLocalIpAddress();
+            // 連線
+            ipTextBlock = new TextBox[]
+            {
+                uxIp1Text, uxIp2Text, uxIp3Text, uxIp4Text
+            };
+            IpAddress = Properties.Settings.Default["ConnectIP"].ToString();
+            IpPort = int.Parse(Properties.Settings.Default["ConnectPort"].ToString());
+
+            connectWorker = new BackgroundWorker();
+            connectWorker.WorkerSupportsCancellation = true;
+            connectWorker.DoWork += connectWorker_DoWork;
+            connectWorker.RunWorkerCompleted += connectWorker_RunWorkerCompleted;
+
+            uxIp1Text.TextChanged += uxIp1Text_TextChanged;
+            uxIp2Text.TextChanged += uxIp1Text_TextChanged;
+            uxIp3Text.TextChanged += uxIp1Text_TextChanged;
+            uxIp4Text.TextChanged += uxIp1Text_TextChanged;
+
+            this.Loaded += UpdatePage_Loaded;
+        }
+
+        private void UpdatePage_Loaded(object sender, RoutedEventArgs e)
+        {
+            //Setting.PageNameList[x]
+            List<CheckBox> checkBoxList = new List<CheckBox>();
+            foreach (UIElement element in uxUpdateListPanel.Children)
+            {
+                if (element is CheckBox checkBox)
+                    checkBoxList.Add(checkBox);
+            }
+
+            var visualElementCnt = checkBoxList.Count;
+            var dataStringCnt = Setting.PageNameList.Count;
+            for (int pageIndex = 0; pageIndex + 1 < visualElementCnt && pageIndex < dataStringCnt; pageIndex++)
+            {
+                checkBoxList[pageIndex + 1].Content = Setting.PageNameList[pageIndex];
+            }
+        }
+
+        public void CheckKioskConnect()
+        {
+            if (connectWorker.IsBusy)
+            {
+                connectWorker.CancelAsync();
+            }
+            connectWorker.RunWorkerAsync();
+        }
+
+        public void Disconnect()
+        {
+            DisconnectHandle();
+        }
+
+        private void StartLoading()
+        {
+            uxProgressBar.Visibility = Visibility.Visible;
+            uxWorkingGrid.IsEnabled = false;
+            uxWorkingGrid.Opacity = 0.3;
+        }
+
+        private void StopLoading()
+        {
+            uxProgressBar.Visibility = Visibility.Collapsed;
+            uxWorkingGrid.IsEnabled = true;
+            uxWorkingGrid.Opacity = 1.0;
+        }
+
+        private void CreateTempFolder()
+        {
+            string path = System.IO.Path.Combine(rootPath, tempFolder);
+            if (Directory.Exists(path))
+            {
+                ClearTempFolder();
+            }
+            else
+            {
+                Directory.CreateDirectory(path);
+            }
+        }
+        private void ClearTempFolder()
+        {
+            string path = System.IO.Path.Combine(rootPath, tempFolder);
+            if (Directory.Exists(path))
+            {
+                string[] files = Directory.GetFiles(path);
+
+                foreach (string file in files)
+                {
+                    try
+                    {
+                        if (File.Exists(file))
+                            File.Delete(file);
+                    }
+                    catch { }
+                }
+            }
+        }
+        private string GetLocalIpAddress()
+        {
+            string result = "";
+            string strHostName = Dns.GetHostName();
+            IPHostEntry iphostentry = Dns.GetHostEntry(strHostName);
+
+            foreach (IPAddress ipaddress in iphostentry.AddressList)
+            {
+                // 只取得IP V4的Address
+                if (ipaddress.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
+                {
+                    result = ipaddress.ToString();
+                }
+            }
+            return result;
+        }
+
+        private bool CheckIpFormat(string str)
+        {
+            byte checkPart = 0;
+            if (!byte.TryParse(str, out checkPart))
+            {
+                return false;
+            }
+            return true;
+        }
+
+        private void InitialUpdateStatus()
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                uxStatus.Text = "";
+                uxUpdateProgressBar.Value = 0;
+                if (KioskSocketClient != null)
+                    uxUpdateBtn.IsEnabled = true;
+                ClearTempFolder();
+            }, DispatcherPriority.Background);
+        }
+
+        private void ChangeUpdateProgrssBarValue(double value)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                uxUpdateProgressBar.Value += value;
+            }, DispatcherPriority.Background);
+        }
+
+        private void uxIp1Text_TextChanged(object sender, TextChangedEventArgs e)
+        {
+            Properties.Settings.Default["ConnectIP"] = uxIp1Text.Text + "." + uxIp2Text.Text + "." + uxIp3Text.Text + "." + uxIp4Text.Text;
+        }
+
+        private void connectWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                StopLoading();
+            }, DispatcherPriority.Background);
+        }
+
+        private void connectWorker_DoWork(object sender, DoWorkEventArgs e)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                // loading bar 
+                StartLoading();
+            }, DispatcherPriority.Background);
+
+            if (KioskSocketClient != null)
+            {
+                KioskSocketClient.ServerReady -= KioskSocketClient_ServerReady;
+                KioskSocketClient.ServerClose -= KioskSocketClient_ServerClose;
+            }
+
+            string serverIp = String.Empty;
+            this.Dispatcher.Invoke((Action)delegate ()
+            {
+                serverIp = IpAddress;
+                if (serverIp != "error format")
+                {
+                    KioskSocketClient = new SocketClient(IpAddress, IpPort, localipAddress);
+                    KioskSocketClient.ServerReady += KioskSocketClient_ServerReady;
+                    KioskSocketClient.ServerClose += KioskSocketClient_ServerClose;
+                }
+            }, DispatcherPriority.Background);
+
+            if (serverIp != "error format")
+            {
+                try
+                {
+                    KioskSocketClient.Connect();
+                }
+                catch
+                {
+                    this.Dispatcher.BeginInvoke((Action)delegate ()
+                    {
+                        IsConnect = false;
+                    }, DispatcherPriority.Background);
+                }
+            }
+            else
+            {
+                this.Dispatcher.BeginInvoke((Action)delegate ()
+                {
+                    IsConnect = false;
+                }, DispatcherPriority.Background);
+            }
+        }
+
+        private void KioskSocketClient_ServerReady(string serverIP, string version)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                IsConnect = true;
+            }, DispatcherPriority.Background);
+        }
+        private void KioskSocketClient_ServerClose(string serverIP)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                IsConnect = false;
+            }, DispatcherPriority.Background);
+        }
+
+        private void uxConnect_Click(object sender, RoutedEventArgs e)
+        {
+            CheckKioskConnect();
+        }
+
+        private void uxDisConnectBtn_Click(object sender, RoutedEventArgs e)
+        {
+            DisconnectHandle();
+        }
+
+        private void DisconnectHandle()
+        {
+            if (KioskSocketClient != null)
+            {
+                KioskSocketClient.ServerReady -= KioskSocketClient_ServerReady;
+                KioskSocketClient.ServerClose -= KioskSocketClient_ServerClose;
+                KioskSocketClient.Close();
+                KioskSocketClient = null;
+            }
+            IsConnect = false;
+            UpdatingState = UpdateState.Abort;
+        }
+
+        #region 更新開始
+        private void uxUpdateBtn_Click(object sender, RoutedEventArgs e)
+        {
+            List<string> packageFilePath = new List<string>();
+
+            canTransFileTag = true;
+            uxUpdateBtn.IsEnabled = false;
+            // 收集欲打包的資料路徑
+            StatusChange("收集打包資訊..");
+            wholeDataFolder = GetPackageFolder();
+            packageFilePath = GetUpdatePackageFilePath();
+
+            if (wholeDataFolder.Count == 0)
+            {
+                StatusChange("沒有選擇任何傳送檔案..");
+                // 所有狀態回復
+                WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
+                return;
+            }
+
+            // Step 1 : 打包
+            uxUpdateProgressBar.Value = 0;
+            StatusChange("開始打包..");
+            BackgroundWorker zipWorker = new BackgroundWorker();
+            zipWorker.WorkerSupportsCancellation = true;
+            zipWorker.DoWork += zipWorker_DoWork;
+            zipWorker.RunWorkerCompleted += zipWorker_RunWorkerCompleted;
+            zipWorker.RunWorkerAsync(packageFilePath);
+        }
+        private void StatusChange(string status)
+        {
+            this.Dispatcher.BeginInvoke((Action)delegate ()
+            {
+                uxStatus.Text = status;
+            }, DispatcherPriority.Background);
+        }
+        private void DivisionZipFile()
+        {
+            // Step 2 : 分割
+            uxUpdateProgressBar.Value = 0;
+            StatusChange("分割封裝檔..");
+            BackgroundWorker divisionWorker = new BackgroundWorker();
+            divisionWorker.WorkerSupportsCancellation = true;
+            divisionWorker.DoWork += divisionWorker_DoWork;
+            divisionWorker.RunWorkerCompleted += divisionWorker_RunWorkerCompleted;
+            divisionWorker.RunWorkerAsync();
+        }
+
+        private void TransCutFile()
+        {
+            // Step 3 : 傳送
+            uxUpdateProgressBar.Value = 0;
+            StatusChange("檔案傳送中...");
+            BackgroundWorker updateWorker = new BackgroundWorker();
+            updateWorker.WorkerSupportsCancellation = true;
+            updateWorker.DoWork += updateWorker_DoWork;
+            updateWorker.RunWorkerCompleted += updateWorker_RunWorkerCompleted;
+            updateWorker.RunWorkerAsync();
+        }
+        #endregion
+        #region 收集欲打包的資料
+        private List<string> GetPackageFolder()
+        {
+            List<string> resultPaceage = new List<string>();
+
+            for (int i = 0; i < uxUpdateListPanel.Children.Count; i++)
+            {
+                CheckBox chkBtn = uxUpdateListPanel.Children[i] as CheckBox;
+
+                if (chkBtn != null)
+                {
+                    if (chkBtn.IsChecked == true)
+                    {
+                        if (chkBtn.Tag.ToString() != "")
+                            resultPaceage.Add(chkBtn.Tag.ToString());
+                    }
+                }
+            }
+
+            return resultPaceage;
+        }
+
+        private List<string> GetUpdatePackageFilePath()
+        {
+            List<string> resultPackage = new List<string>();
+
+            // 整理要打包的東西 : 所有要打包的檔案的相對根目錄底下路徑
+            for (int i = 0; i < wholeDataFolder.Count; i++)
+            {
+                switch (wholeDataFolder[i])
+                {
+                    case "Basic":
+                        PackageBasicSetting(resultPackage);
+                        break;
+                    case "History":
+                        PackageHistoryWall(resultPackage, Setting.PageType.History);
+                        break;
+                    case "Product":
+                        PackageHistoryWall(resultPackage, Setting.PageType.Product);
+                        break;
+                    case "CSR":
+                        PackageHistoryWall(resultPackage, Setting.PageType.CSR);
+                        break;
+                }
+            }
+            return resultPackage;
+        }
+
+        private void PackageBasicSetting(List<string> resultPackage)
+        {
+            resultPackage.Add(Setting.settingJsonDataPath);
+        }
+
+        private void PackageHistoryWall(List<string> resultPackage, Setting.PageType type)
+        {
+            string folderPath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Data", Setting.PageFolderName[type]);
+            string DataConfigFileName = System.IO.Path.Combine(folderPath, @"Setting\ConfigSetting.ini");
+            string historyFileName = System.IO.Path.Combine(folderPath, @"HistoryWallData\HistoryFile.ini");
+            string DataThumFileFolder = System.IO.Path.Combine(folderPath, @"Thumb\");
+            string DataJsonImgFileFolder = System.IO.Path.Combine(folderPath, @"HistoryImage\");
+
+            // History : 1. Setting\ConfigSetting.ini + 2. HistoryWallData\HistoryFile.ini + 3. Thumb\bgMap file and logoMap file + 4. HistoryImage 整包
+            if (File.Exists(DataConfigFileName))
+            {
+                resultPackage.Add(DataConfigFileName);
+            }
+
+            if (File.Exists(historyFileName))
+            {
+                resultPackage.Add(historyFileName);
+            }
+
+            string[] files = Directory.GetFiles(DataThumFileFolder);
+
+            foreach (string file in files)
+            {
+                // 只接受 bgMap 及 logoMap 兩個檔名檔案
+                if (GlobalFunction.CheckFileIsImage(file) && (file.IndexOf("bgMap") != -1 || file.IndexOf("logoMap") != -1))
+                {
+                    resultPackage.Add(file);
+                }
+            }
+
+            if (Directory.Exists(DataJsonImgFileFolder))
+            {
+                List<string> dirs = new List<string>(Directory.EnumerateDirectories(DataJsonImgFileFolder));
+
+                foreach (var dir in dirs)
+                {
+                    string[] inforfiles = Directory.GetFiles(dir);
+
+                    foreach (string file in inforfiles)
+                    {
+                        // 接受圖片或影片
+                        if (GlobalFunction.CheckFileIsImage(file) || GlobalFunction.CheckFileIsVideo(file))
+                        {
+                            resultPackage.Add(file);
+                        }
+                    }
+                }
+            }
+        }
+        #endregion
+        #region  打包
+        private void zipWorker_DoWork(object sender, DoWorkEventArgs e)
+        {
+            List<string> packagePathList = e.Argument as List<string>;
+            FileStream FS = File.Create(defaultZipFileName);
+            ZipOutputStream s = new ZipOutputStream(FS);
+            string currentPath = Directory.GetCurrentDirectory();
+            s.SetLevel(9); //0 ~ 9
+            double stepValue = 100 / packagePathList.Count;
+
+            for (int i = 0; i < packagePathList.Count; i++)
+            {
+                FileStream fs = File.OpenRead(packagePathList[i]);
+                byte[] buffer = new byte[fs.Length];
+                fs.Read(buffer, 0, buffer.Length);
+
+                string zipPath = packagePathList[i];
+                if (packagePathList[i].Contains(currentPath))
+                    zipPath = zipPath.Remove(0, currentPath.Length + 1);
+                ZipEntry entry = new ZipEntry(zipPath);
+                entry.DateTime = DateTime.Now;
+                entry.Size = fs.Length;
+
+                fs.Close();
+                s.PutNextEntry(entry);
+                s.Write(buffer, 0, buffer.Length);
+                ChangeUpdateProgrssBarValue(stepValue);
+            }
+            s.Dispose();
+            s.Close();
+        }
+
+        private void zipWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            StatusChange("打包完成..");
+            uxUpdateProgressBar.Value = 100;
+            //切割打包資料夾
+            WpfDelayDoWork.DoBackgroundWork(DivisionZipFile, 1000);
+        }
+        #endregion
+        #region 切割
+        private void divisionWorker_DoWork(object sender, DoWorkEventArgs e)
+        {
+            string zipFilePath = System.IO.Path.Combine(Directory.GetCurrentDirectory(), defaultZipFileName);
+
+            if (File.Exists(zipFilePath))
+            {
+                try
+                {
+                    int segmentSize = 4194304; //4MB
+                    long fileSize = new FileInfo(zipFilePath).Length;
+                    int datas = 0;
+                    int segmentCount = (int)(fileSize / (long)segmentSize);
+                    int lastSegmentSize = (int)(fileSize % (long)segmentSize);
+                    segmentCount = lastSegmentSize > 0 ? segmentCount + 1 : segmentCount;
+                    double stepValue = 100 / segmentCount;
+                    FileStream fs = File.OpenRead(zipFilePath);
+                    cutFilePaths = new List<string>();
+
+                    for (int i = 0; i < segmentCount; i++)
+                    {
+                        byte[] binaryData;
+                        string segmentFileName = zipFilePath.Replace(".zip", String.Empty) + "[" + (i + 1) + "].cut";
+                        FileStream fOut = File.OpenWrite(segmentFileName);
+                        if (lastSegmentSize > 0 && i == segmentCount - 1)
+                        {
+                            binaryData = new byte[lastSegmentSize];
+                            datas = fs.Read(binaryData, 0, lastSegmentSize);
+                            fOut.Write(binaryData, 0, lastSegmentSize);
+                        }
+                        else
+                        {
+                            binaryData = new byte[segmentSize];
+                            datas = fs.Read(binaryData, 0, segmentSize);
+                            fOut.Write(binaryData, 0, segmentSize);
+                        }
+                        fOut.Flush();
+                        fOut.Close();
+                        ChangeUpdateProgrssBarValue(stepValue);
+                        cutFilePaths.Add(segmentFileName);
+                    }
+                    fs.Close();
+                    File.Delete(zipFilePath);
+                    canTransFileTag = true;
+                }
+                catch
+                {
+                    canTransFileTag = false;
+                }
+            }
+            else
+            {
+                canTransFileTag = false;
+            }
+        }
+
+        private void divisionWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            StatusChange("分割完成..");
+            uxUpdateProgressBar.Value = 100;
+            if (canTransFileTag)
+            {
+                //傳輸更新檔案開始
+                WpfDelayDoWork.DoBackgroundWork(TransCutFile, 1000);
+                return;
+            }
+
+            StatusChange("分割失敗..");
+            // 所有狀態回復
+            WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
+        }
+        #endregion
+        #region 傳送
+        bool isSendComplete = false;
+        private void updateWorker_DoWork(object sender, DoWorkEventArgs e)
+        {
+            if (cutFilePaths.Count > 0)
+            {
+                try
+                {
+                    isSendComplete = false;
+                    // 通知分割檔案總數
+                    KioskSocketClient.NotifyFileTransferStart(cutFilePaths.Count);
+                    // 掛上前台更新狀況事件
+                    KioskSocketClient.SendSegmentFileFinish += KioskSocketClient_SendSegmentFileFinish;
+                    KioskSocketClient.FailSendFile += KioskSocketClient_FailSendFile;
+                    KioskSocketClient.ReceiveServerNotify += KioskSocketClient_ReceiveServerNotify;
+                    //傳送 Cut File
+                    for (int i = 0; i < cutFilePaths.Count; i++)
+                    {
+                        while (isSendComplete)
+                        {
+                            Thread.Sleep(1000);
+                        }
+                        KioskSocketClient.SendFile(cutFilePaths[i], "0");
+                        isSendComplete = true;
+                    }
+                }
+                catch
+                {
+                    KioskSocketClient = null;
+                    canTransFileTag = false;
+                }
+            }
+        }
+
+        private void updateWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
+        {
+            if (canTransFileTag)
+            {
+                //傳輸更新檔案開始
+                StatusChange("傳送完成..");
+                uxUpdateProgressBar.Value = 100;
+                return;
+            }
+            StatusChange("傳送失敗..");
+            // 所有狀態回復
+            WpfDelayDoWork.DoBackgroundWork(InitialUpdateStatus, 3000);
+        }
+
+        private void KioskSocketClient_SendSegmentFileFinish(string serverIP, string index)
+        {
+            double stepValue = 100 / cutFilePaths.Count;
+
+            ChangeUpdateProgrssBarValue(stepValue);
+            isSendComplete = false;
+        }
+
+        #endregion
+        #region 前台更新狀況回報
+        private void KioskSocketClient_FailSendFile(object sender, EventArgs e)
+        {
+            StatusChange("傳輸異常...");
+            // 所有狀態回復
+            WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
+        }
+
+        private void KioskSocketClient_ReceiveServerNotify(string serverIP, string message)
+        {
+            if (message.Equals("Success"))
+            {
+                StatusChange("前台更新完成重新啟動中...");
+                // 所有狀態回復
+                WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
+            }
+            else if (message.Equals("Fail"))
+            {
+                StatusChange("傳輸異常...");
+                // 所有狀態回復
+                WpfDelayDoWork.DoBackgroundWorkAsync(Dispatcher.CurrentDispatcher, InitialUpdateStatus, 3000);
+            }
+        }
+        #endregion
+    }
+
+    public class WpfDelayDoWork
+    {
+        public static void DoWork(Action action, int millisecond = 300)
+        {
+            new Action<Dispatcher, Action, int>(DoWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
+        }
+
+        public static void DoBackgroundWork(Action action, int millisecond = 300)
+        {
+            new Action<Dispatcher, Action, int>(DoBackgroundWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
+        }
+
+        public static void DoWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
+        {
+            System.Threading.Thread.Sleep(millisecond);
+            dispatcher.BeginInvoke(action);
+        }
+
+        public static void DoBackgroundWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
+        {
+            System.Threading.Thread.Sleep(millisecond);
+            dispatcher.Invoke(action, DispatcherPriority.Background);
+        }
+    }
+}

+ 257 - 0
BellwetherBackend/Utility/GlobalFunction.cs

@@ -0,0 +1,257 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Xml.Linq;
+
+namespace BellwetherBackend.Utility
+{
+    public class GlobalFunction
+    {
+        //圖片規格
+        public static string[] imgDimList = { ".jpg", ".png", ".bmp", ".jpeg" };
+        //影片規格
+        public static string[] mediaDimList = { ".avi", ".mp4", "mpeg", ".mpg", ".wmv" };
+        //簡報
+        public static string[] pptDimList = { ".ppt", ".pptx" };
+
+        public static ImageSource GetBitMap(string imgpath)
+        {
+            BitmapImage bitmapImg = new BitmapImage();
+
+            if (File.Exists(imgpath))
+            {
+                bitmapImg.BeginInit();
+                bitmapImg.UriSource = new Uri(imgpath, UriKind.RelativeOrAbsolute);
+                //忽略原始圖檔的色盤設定,使用預設值,可縮短載入圖檔的時間
+                //如有遇到色彩不正確的問題,或者原圖有特殊的自定義色盤,請不要使用此設定
+                bitmapImg.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+                //使用以下的預先載入設定,在BitmapImage創建完成之後,可立刻釋放其所占用或鎖住的資源,以免咬住檔案
+                bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
+                //根據欲顯示的區域長或寬,來設定 DecodePixelHeight 或 DecodePixelWidth 的值
+                //bitmapImg.DecodePixelHeight = THUMB_HEIGHT;
+                //bitmapImg.DecodePixelWidth = THUMB_WIDTH;
+                bitmapImg.EndInit();
+                bitmapImg.Freeze();
+            }
+            return bitmapImg;
+        }
+
+        public static ImageSource GetBitMap(string imgpath, double resolutionWidth, double resolutionHeight)
+        {
+            BitmapImage bitmapImg = new BitmapImage();
+
+            if (File.Exists(imgpath))
+            {
+                bitmapImg.BeginInit();
+                bitmapImg.UriSource = new Uri(imgpath, UriKind.RelativeOrAbsolute);
+                //忽略原始圖檔的色盤設定,使用預設值,可縮短載入圖檔的時間
+                //如有遇到色彩不正確的問題,或者原圖有特殊的自定義色盤,請不要使用此設定
+                bitmapImg.CreateOptions = BitmapCreateOptions.IgnoreImageCache;
+                //使用以下的預先載入設定,在BitmapImage創建完成之後,可立刻釋放其所占用或鎖住的資源,以免咬住檔案
+                bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
+                //根據欲顯示的區域長或寬,來設定 DecodePixelHeight 或 DecodePixelWidth 的值
+                BitmapDecoder decoder = BitmapDecoder.Create(new Uri(imgpath), BitmapCreateOptions.None, BitmapCacheOption.None);
+                BitmapFrame frame = decoder.Frames[0];
+
+                //ShellFile shellFile = ShellFile.FromFilePath(imgpath);
+                var imageSourceHeight = frame.PixelHeight; //shellFile.Properties.System.Image.VerticalSize.Value;
+                var imageSourceWidth = frame.PixelWidth;//shellFile.Properties.System.Image.HorizontalSize.Value;
+                var imageSourceRatio = imageSourceWidth / (imageSourceHeight == 0 ? 1 : imageSourceHeight);
+
+                if (imageSourceHeight > resolutionHeight && imageSourceWidth > resolutionWidth)
+                {
+                    if (imageSourceRatio > resolutionWidth / resolutionHeight)
+                    {
+                        bitmapImg.DecodePixelWidth = Convert.ToInt32(resolutionWidth);
+                    }
+                    else
+                    {
+                        bitmapImg.DecodePixelHeight = Convert.ToInt32(resolutionHeight);
+                    }
+                }
+                else if (imageSourceHeight > resolutionHeight)
+                {
+                    bitmapImg.DecodePixelHeight = Convert.ToInt32(resolutionHeight);
+                }
+                else if (imageSourceWidth > resolutionWidth)
+                {
+                    bitmapImg.DecodePixelWidth = Convert.ToInt32(resolutionWidth);
+                }
+                bitmapImg.EndInit();
+                bitmapImg.Freeze();
+            }
+            return bitmapImg;
+        }
+
+        public static bool CheckFileIsImage(string file)
+        {
+            if (GlobalFunction.imgDimList.Contains(System.IO.Path.GetExtension(file.ToLower())))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        public static bool CheckFileIsVideo(string file)
+        {
+            if (GlobalFunction.mediaDimList.Contains(System.IO.Path.GetExtension(file.ToLower())))
+            {
+                return true;
+            }
+
+            return false;
+        }
+
+        public static string GetFolderFileName(string rootPath, string filename)
+        {
+            string result = "";
+            Random Counter = new Random(Guid.NewGuid().GetHashCode());
+
+            do
+            {
+                result = (Counter.Next(0, 10000)).ToString() + System.IO.Path.GetExtension(filename).ToLower();
+            }
+            while (File.Exists(Path.Combine(rootPath, result)));
+
+            return result;
+        }
+
+        #region icon
+        public static Geometry AddBtnData;
+        public static Geometry DeleteBtnData;
+        public static Geometry MoveUpBtnData;
+        public static Geometry MoveDownBtnData;
+        public static Geometry MapBtnData;
+        public static Geometry ImgDeleteData;
+        public static Geometry ConnectBtnData;
+        public static Geometry DisconnectBtnData;
+        public static Geometry UpdateBtnData;
+
+        public GlobalFunction()
+        {
+            LoadAllIconData();
+            //FillBaseFileSystem();
+        }
+
+        private Geometry LoadIconDataFromResource(string xamlName)
+        {
+            Geometry iconData = null;
+            var assembly = GetType().Assembly;
+
+            using (var stream = assembly.GetManifestResourceStream(xamlName))
+            {
+                var doc = XDocument.Load(stream);
+                var path = doc.Root.Element("{http://schemas.microsoft.com/winfx/2006/xaml/presentation}Path");
+                if (path != null)
+                {
+                    var data = (string)path.Attribute("Data");
+                    iconData = PathGeometry.Parse(data);
+                }
+                return iconData;
+            }
+        }
+
+        private void LoadAllIconData()
+        {
+            AddBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.add.xaml");
+            DeleteBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.delete.xaml");
+            MoveUpBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.upward.xaml");
+            MoveDownBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.downward.xaml");
+            MapBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.map.xaml");
+            ImgDeleteData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.imgdelete.xaml");
+            ConnectBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.connect.xaml");
+            DisconnectBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.disconnect.xaml");
+            UpdateBtnData = LoadIconDataFromResource("BellwetherBackend.Assets.appbar.control.update.xaml");
+        }
+        #endregion
+    }
+
+    public class ScrollViewerUtilities
+    {
+        #region HorizontalOffset
+
+        /// <summary>
+        /// HorizontalOffset Attached Dependency Property
+        /// </summary>
+        public static readonly DependencyProperty HorizontalOffsetProperty =
+            DependencyProperty.RegisterAttached("HorizontalOffset", typeof(double), typeof(ScrollViewerUtilities),
+                new FrameworkPropertyMetadata((double)0.0,
+                    new PropertyChangedCallback(OnHorizontalOffsetChanged)));
+
+        /// <summary>
+        /// Gets the HorizontalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static double GetHorizontalOffset(DependencyObject d)
+        {
+            return (double)d.GetValue(HorizontalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the HorizontalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static void SetHorizontalOffset(DependencyObject d, double value)
+        {
+            d.SetValue(HorizontalOffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Handles changes to the HorizontalOffset property.
+        /// </summary>
+        private static void OnHorizontalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            var viewer = (ScrollViewer)d;
+            viewer.ScrollToHorizontalOffset((double)e.NewValue);
+        }
+
+        #endregion
+
+        #region VerticalOffset
+
+        /// <summary>
+        /// VerticalOffset Attached Dependency Property
+        /// </summary>
+        public static readonly DependencyProperty VerticalOffsetProperty =
+            DependencyProperty.RegisterAttached("VerticalOffset", typeof(double), typeof(ScrollViewerUtilities),
+                new FrameworkPropertyMetadata((double)0.0,
+                    new PropertyChangedCallback(OnVerticalOffsetChanged)));
+
+        /// <summary>
+        /// Gets the VerticalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static double GetVerticalOffset(DependencyObject d)
+        {
+            return (double)d.GetValue(VerticalOffsetProperty);
+        }
+
+        /// <summary>
+        /// Sets the VerticalOffset property.  This dependency property 
+        /// indicates ....
+        /// </summary>
+        public static void SetVerticalOffset(DependencyObject d, double value)
+        {
+            d.SetValue(VerticalOffsetProperty, value);
+        }
+
+        /// <summary>
+        /// Handles changes to the VerticalOffset property.
+        /// </summary>
+        private static void OnVerticalOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            var viewer = (ScrollViewer)d;
+            viewer.ScrollToVerticalOffset((double)e.NewValue);
+        }
+
+        #endregion
+    }
+}

+ 94 - 0
BellwetherBackend/Utility/Setting.cs

@@ -0,0 +1,94 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace BellwetherBackend.Utility
+{
+    public static class Setting
+    {
+        private static readonly string dataDirectory = System.IO.Path.Combine(Directory.GetCurrentDirectory(), "Data");
+        public static readonly string settingJsonDataPath = System.IO.Path.Combine(dataDirectory, "setting.ini");
+
+        public static readonly List<string> PageNameList = new List<string>() { "大事記", "產品展示", "社會責任" };
+
+        public enum PageType : int
+        {
+            FrontPage,
+            History,
+            Product,
+            CSR,
+        }
+
+        public static readonly Dictionary<PageType, string> PageFolderName
+            = new Dictionary<PageType, string>() {
+                { PageType.History, "History" },
+                { PageType.Product, "Product" },
+                { PageType.CSR, "CSR" },
+            };
+
+        private static SettingJson _settingJsonFile;
+        public static SettingJson settingJsonFile
+        {
+            get
+            {
+                if (_settingJsonFile != null)
+                    return _settingJsonFile;
+                else
+                {
+                    AnalyzJsonFile();
+                    return _settingJsonFile;
+                }
+            }
+            set
+            {
+                _settingJsonFile = value;
+                //save Json
+                SaveJson();
+            }
+        }
+
+        private static void AnalyzJsonFile()
+        {
+            string jsonResult;
+
+            if (!File.Exists(settingJsonDataPath))
+            {
+                _settingJsonFile = new SettingJson()
+                {
+                    BackHomeSec = 60,
+                };
+
+                return;
+            }
+            else
+            {
+                using (StreamReader sr = new StreamReader(settingJsonDataPath))
+                {
+                    jsonResult = sr.ReadToEnd();
+                }
+                _settingJsonFile = JsonConvert.DeserializeObject<SettingJson>(jsonResult);
+            }
+        }
+
+        private static void SaveJson()
+        {
+            string jsonString;// = JsonConvert.SerializeObject(_settingJsonFile, Newtonsoft.Json.Formatting.Indented);
+
+            jsonString = JsonConvert.SerializeObject(_settingJsonFile, Newtonsoft.Json.Formatting.Indented);
+            using (StreamWriter sw = new StreamWriter(settingJsonDataPath, false, Encoding.Unicode))
+            {
+                sw.Write(jsonString);
+                sw.Close();
+            }
+        }
+    }
+
+    public class SettingJson
+    {
+        public int BackHomeSec { get; set; }
+    }
+}

+ 24 - 0
HistoryDLL/CompleteEventArgs.cs

@@ -0,0 +1,24 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace HistoryDLL
+{
+    public class CompleteEventArgs : EventArgs
+    {
+        private string filePath;
+
+        public string FilePath
+        {
+            get { return filePath; }
+            set { filePath = value; }
+        }
+
+        public CompleteEventArgs(string p)
+        {
+            FilePath = p;
+        }
+    }
+}

+ 200 - 0
HistoryDLL/ConfigSettingClass.cs

@@ -0,0 +1,200 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Media;
+
+namespace HistoryDLL
+{
+    public class WindowsResolution
+    {
+        public CyclicScroller.MonitorFlag ncm;
+
+        public WindowsResolution()
+        {
+            int Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
+            int Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
+
+            //判斷是否為多螢幕~由 width 判斷
+            double value = Math.Ceiling((double)Width / 1920);
+
+            if (value == 1)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor1_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 1;
+            }
+            else if (value == 2)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor2_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 2;
+            }
+            else if (value == 3)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor3_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 3;
+            }
+            else if (value == 4)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor4_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 4;
+            }
+            else if (value == 5)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor5_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 5;
+            }
+            else if (value == 6)
+            {
+                ncm = CyclicScroller.MonitorFlag.Monitor6_1;
+                ConfigSettingClass.MainBackCollect.ScreenSetting = 6;
+            }
+        }
+    }
+
+    public class ConfigSettingClass
+    {
+        #region Static Members
+        public static MainBackground MainBackCollect = new MainBackground()
+        {
+            BackgroundColor = Color.FromArgb(255, 255, 255, 255),
+            BackgroundColorPoint = new Point(0, 0),
+            ImgBackground = String.Empty,
+            ImgLogo = String.Empty,
+            DefaultLangIndex = 0,
+            BackHomeMillisecond = 20,
+            ScreenSetting = 1,
+            LangText = new string[] { "中文", "English", "", "" },
+            LangFlowDir = new FlowDirection[] { FlowDirection.LeftToRight, FlowDirection.LeftToRight, FlowDirection.LeftToRight, FlowDirection.LeftToRight },
+            IsUsing4kResolution = false
+        };
+
+        public static Event EventCollect = new Event()
+        {
+            BackgroundColor = Color.FromArgb(230, 3, 115, 185),
+            BackgroundColorPoint = new Point(0, 0),
+            TextColor = Color.FromArgb(255, 232, 238, 255),
+            TextColorPoint = new Point(0, 0),
+            ThicknessColor = Color.FromArgb(255, 177, 232, 255),
+            ThicknessColorPoint = new Point(0, 0)
+        };
+        public static EventContent EventContentCollect = new EventContent()
+        {
+            BackgroundColor = Color.FromArgb(233, 115, 217, 255),
+            BackgroundColorPoint = new Point(0, 0),
+            TextColor = Color.FromArgb(198, 0, 6, 9),
+            TextColorPoint = new Point(0, 0),
+            ThicknessColor = Color.FromArgb(255, 198, 255, 255),
+            ThicknessColorPoint = new Point(0, 0)
+        };
+        public static Timeline TimelineCollect = new Timeline()
+        {
+            BackgroundColor = Color.FromArgb(177, 168, 197, 255),
+            BackgroundColorPoint = new Point(0, 0),
+            TextColor = Color.FromArgb(176, 255, 255, 255),
+            TextColorPoint = new Point(0, 0),
+            ThicknessColor = Color.FromArgb(255, 0, 87, 154),
+            ThicknessColorPoint = new Point(0, 0)
+        };
+        public static TimelineExtent TimelineExtentCollect = new TimelineExtent()
+        {
+            BackgroundColor = Color.FromArgb(204, 0, 41, 104),
+            BackgroundColorPoint = new Point(0, 0),
+            TextColor = Color.FromArgb(255, 162, 220, 255),
+            TextColorPoint = new Point(0, 0),
+            ThicknessColor = Color.FromArgb(255, 76, 49, 0),
+            ThicknessColorPoint = new Point(0, 0)
+        };
+        public static ButtonSelect BtnSelectCollect = new ButtonSelect()
+        {
+            BackgroundColor = Color.FromArgb(168, 12, 0, 0),
+            BackgroundColorPoint = new Point(0, 0),
+            TextColor = Color.FromArgb(255, 222, 241, 255),
+            TextColorPoint = new Point(0, 0),
+            BackgroundColorUnselect = Color.FromArgb(168, 0, 129, 181),
+            BackgroundColorUnselectPoint = new Point(0, 0),
+            TextColorUnselect = Color.FromArgb(120, 255, 255, 255),
+            TextColorUnselectPoint = new Point(0, 0)
+        };
+        #endregion
+
+        public ConfigSettingClass(string ConfigPath, WindowsResolution windowsresolution)
+        {
+            if (File.Exists(ConfigPath))
+            {
+                string jsonResult;
+                using (StreamReader sr = new StreamReader(ConfigPath))
+                {
+                    jsonResult = sr.ReadToEnd();
+                }
+                var container = DeserializeFromJson<DataCollect>(jsonResult);
+                if (container != null)
+                {
+                    MainBackCollect = container.MainBackgroundCollect;
+                    EventCollect = container.EventCollect;
+                    EventContentCollect = container.EventContentCollect;
+                    TimelineCollect = container.TimelineCollect;
+                    TimelineExtentCollect = container.TimelineExtentCollect;
+                    BtnSelectCollect = container.ButtonSelectCollect;
+                }
+
+                try
+                {
+                    if (ConfigSettingClass.MainBackCollect.LangFlowDir == null || ConfigSettingClass.MainBackCollect.LangFlowDir.Length < 4 ||
+                    ConfigSettingClass.MainBackCollect.LangText == null || ConfigSettingClass.MainBackCollect.LangText.Length < 4)
+                    {
+                        MainBackCollect = null;
+                        return;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    MainBackCollect = null;
+                    return;
+                }
+            }
+            else
+            {
+                SetDefaultBgAndLogo(windowsresolution);
+            }
+
+            if (ConfigSettingClass.MainBackCollect.BackHomeMillisecond <= 5)
+            {
+                ConfigSettingClass.MainBackCollect.BackHomeMillisecond = 5;
+            }
+        }
+
+        private void SetDefaultBgAndLogo(WindowsResolution windowsresolution)
+        {
+            MainBackCollect.ImgLogo = "logo.png";
+
+            switch (windowsresolution.ncm)
+            {
+                case CyclicScroller.MonitorFlag.Monitor1_1:
+                    {
+                        //MainBackCollect.ImgBackground = "1x1.jpg";
+                        break;
+                    }
+                case CyclicScroller.MonitorFlag.Monitor2_1:
+                    {
+                        MainBackCollect.ImgBackground = "2x1.jpg";
+                        break;
+                    }
+                case CyclicScroller.MonitorFlag.Monitor3_1:
+                    {
+                        MainBackCollect.ImgBackground = "3x1.jpg";
+                        break;
+                    }
+            }
+        }
+
+        public static T DeserializeFromJson<T>(string json)
+        {
+            T deserializedProduct = JsonConvert.DeserializeObject<T>(json);
+            return deserializedProduct;
+        }
+    }
+}

+ 100 - 0
HistoryDLL/CutThumbnail.cs

@@ -0,0 +1,100 @@
+using System.Drawing;
+
+namespace HistoryDLL
+{
+    enum SelectType
+    {
+        //按寬高 (可能變形)
+        HW = 0x0001,
+        //指定寬, 高按比例改變
+        W = 0x0010,
+        //指定高, 寬按比例改變
+        H = 0x0100,
+        //指定高寬進行裁減(不變形)
+        Cut = 0x1000
+    };
+
+    public class CutThumbnail
+    {
+        public CutThumbnail(string imagepath, int cutWidth, int cutHeight, string imageFormat, string ThumbPath)
+        {
+            MakeThumbnail(imagepath, ThumbPath, cutWidth, cutHeight, SelectType.Cut, imageFormat);
+        }
+
+        private void MakeThumbnail(string originalImagePath, string thumbnailPath, int width, int height, SelectType mode, string imageFormat)
+        {
+            System.Drawing.Image originalImage = System.Drawing.Image.FromFile(originalImagePath);
+
+            int towidth = (int)width;
+            int toheight = (int)height;
+
+            int x = 0;
+            int y = 0;
+            int ow = originalImage.Width;
+            int oh = originalImage.Height;
+
+            switch (mode)
+            {
+                case SelectType.HW://指定高宽缩放(可能变形) 
+                    break;
+                case SelectType.W://指定宽,高按比例 
+                    toheight = originalImage.Height * width / originalImage.Width;
+                    break;
+                case SelectType.H://指定高,宽按比例 
+                    towidth = originalImage.Width * height / originalImage.Height;
+                    break;
+                case SelectType.Cut://指定高宽裁减(不变形) 
+                    if ((double)originalImage.Width / (double)originalImage.Height > (double)towidth / (double)toheight)
+                    {
+                        oh = originalImage.Height;
+                        ow = originalImage.Height * towidth / toheight;
+                        y = 0;
+                        x = (originalImage.Width - ow) / 2;
+                    }
+                    else
+                    {
+                        ow = originalImage.Width;
+                        oh = originalImage.Width * height / towidth;
+                        x = 0;
+                        y = (originalImage.Height - oh) / 2;
+                    }
+                    break;
+                default:
+                    break;
+            }
+            //新建一个bmp图片 
+            System.Drawing.Image bitmap = new System.Drawing.Bitmap(towidth, toheight);
+            //新建一个画板 
+            Graphics g = System.Drawing.Graphics.FromImage(bitmap);
+            //设置高质量插值法 
+            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.High;
+            //设置高质量,低速度呈现平滑程度 
+            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
+            //清空画布并以透明背景色填充 
+            g.Clear(System.Drawing.Color.Transparent);
+            //在指定位置并且按指定大小绘制原图片的指定部分 
+            g.DrawImage(originalImage, new System.Drawing.Rectangle(0, 0, towidth, toheight), new System.Drawing.Rectangle(x, y, ow, oh), GraphicsUnit.Pixel);
+            try
+            {
+                System.Drawing.Imaging.ImageFormat imgtype = System.Drawing.Imaging.ImageFormat.Jpeg;
+
+                if (imageFormat == "jpg")
+                {
+                    imgtype = System.Drawing.Imaging.ImageFormat.Jpeg;
+                }
+                //保存缩略图
+                bitmap.Save(thumbnailPath, imgtype);
+            }
+            catch (System.Exception e)
+            {
+                throw e;
+            }
+            finally
+            {
+                originalImage.Dispose();
+                bitmap.Dispose();
+                g.Dispose();
+            }
+        }
+    }
+}

+ 42 - 0
HistoryDLL/CyclicScroller.xaml

@@ -0,0 +1,42 @@
+<UserControl x:Class="HistoryDLL.CyclicScroller"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
+             PreviewTouchDown="Window_PreviewTouchDown" PreviewTouchUp="Window_PreviewTouchUp">
+
+    <UserControl.Resources>
+        <ResourceDictionary>
+            <ResourceDictionary.MergedDictionaries>
+                <ResourceDictionary Source="Style.xaml" />
+            </ResourceDictionary.MergedDictionaries>
+        </ResourceDictionary>
+    </UserControl.Resources>
+    
+    <Grid x:Name="uxMainWindow">
+        <Image x:Name="uxBackGroundImg" RenderOptions.BitmapScalingMode="HighQuality" Stretch="Uniform" />
+        <Image x:Name="uxLeftLogoMap" VerticalAlignment="Top" Height="133" Width="337" HorizontalAlignment="Left" Margin="50,50,0,0" Stretch="Uniform" Visibility="Collapsed"></Image>
+        <Image x:Name="uxRightLogoMap" VerticalAlignment="Top" HorizontalAlignment="Right" Height="133" Width="337" Margin="0,50,50,0" Stretch="Uniform" Visibility="Collapsed"></Image>
+        <Grid x:Name="uxCyclicGrid" Opacity="1">
+            <ScrollViewer Name="uxMyScroll" ScrollViewer.CanContentScroll="False" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Visibility="Visible" HorizontalAlignment="Left" Margin="0,0,0,245" VerticalAlignment="Bottom" IsManipulationEnabled="True" 
+                          ManipulationStarted="uxMyScroll_ManipulationStarted" ManipulationDelta="uxMyScroll_ManipulationDelta" ManipulationInertiaStarting="uxMyScroll_ManipulationInertiaStarting" ManipulationCompleted="uxMyScroll_ManipulationCompleted" ScrollChanged="uxMyScroll_ScrollChanged">
+                <StackPanel Name="uxMyStackPanel" VerticalAlignment="Bottom" Orientation="Horizontal" HorizontalAlignment="Left" >
+                </StackPanel>
+            </ScrollViewer>
+        </Grid>
+
+        <StackPanel Orientation="Horizontal" Width="250" Height="100" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,10">
+            <Button x:Name="uxHomeBtnL" Width="73" Height="70" Margin="10" Visibility="Collapsed" Click="HomeBtn_Click" Style="{StaticResource homeSwitchBtn}">
+            </Button>
+            <Button x:Name="uxMainLangBtnL" Width="133" Height="44" Margin="10" Visibility="Collapsed" Click="ChangeLangBtn_Click" Style="{StaticResource languageSwitchBtn}">
+            </Button>
+        </StackPanel>
+
+        <StackPanel Orientation="Horizontal" Width="250" Height="100" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="0,0,0,10" FlowDirection="RightToLeft">
+            <Button x:Name="uxHomeBtnR" Width="73" Height="70" Margin="10" Visibility="Collapsed" Click="HomeBtn_Click" Style="{StaticResource homeSwitchBtn}">
+            </Button>
+            <Button x:Name="uxMainLangBtnR" Width="133" Height="44" Margin="10" Visibility="Collapsed" Click="ChangeLangBtn_Click" Style="{StaticResource languageSwitchBtn}">
+            </Button>
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 857 - 0
HistoryDLL/CyclicScroller.xaml.cs

@@ -0,0 +1,857 @@
+using HistoryDLL.Json;
+using MediaViewerLib.Utilities;
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+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
+{
+    /// <summary>
+    /// CyclicScroller.xaml 的互動邏輯
+    /// </summary>
+    public partial class CyclicScroller : UserControl
+    {
+        public enum HistoryControlMode
+        {
+            Boot = 0x001,
+            Manual = 0x010,
+            AutoRun = 0x100,
+        };
+
+        public enum TouchorManipulation
+        {
+            TouchEvent = 0x01,
+            ManipulationEvent = 0x10,
+        };
+
+        public enum MonitorFlag
+        {
+            Monitor1_1 = 0x000001,
+            Monitor2_1 = 0x000010,
+            Monitor3_1 = 0x000100,
+            Monitor4_1 = 0x001000,
+            Monitor5_1 = 0x010000,
+            Monitor6_1 = 0x100000,
+        };
+
+        public enum StoryBoardStatus
+        {
+            StoryBoardIsRun = 0x01,
+            StoryBoardIsStop = 0x10,
+        };
+
+        public delegate void HomeBackInforDelegate();
+        public event HomeBackInforDelegate HomeBackInforEvent;
+        public event EventHandler OnDataLoadCompeleted;
+
+        //創造 LiveContainer 物件的Delegate
+        private delegate void CreateLiveContainerDelegate();
+
+        //從xml 中取得時際實際有多少個年份資料
+        private List<XmlData> xmlDataList = new List<XmlData>();
+        //透過取得的年份將MainEvent建立出來後放到該Buffer中
+        private List<LiveContainer> LiveContainerList = new List<LiveContainer>();
+        //Get Windows Resolution (根據 n * 1的螢幕取得windows的寬高)
+        private static WindowsResolution CurrentMonitorCount = new WindowsResolution();
+        //public static ConfigSettingClass config = new ConfigSettingClass(GlobalFunction.ConfigSettingFilePath, CurrentMonitorCount);
+        //當前載入的起始位置 0 : 代表當前第一個年份是xml資料的首年
+        private int currentLoadIndex = 0;
+        //是否需要"當前"年份顯示在正中間
+        private bool NeedToGetCenter = true;
+        private int CenterIndexValue = 0;
+        //是否要有首頁動畫
+        private bool RunHomePageAnimation = true;
+        //TouchDown 事件是否有發生 ?
+        private bool isTouchDown = false;
+        private bool isManipulatonEvent = false;
+        private bool isAutoRun = false;
+        //移動前 Horizontal.X的值
+        double MoveStartHorizontalX = 0.0;
+        //移動後 Horizontal.X的值
+        double MoveEndHorizontalX = 0.0;
+        //從開始到結束全部的移動距離
+        double MoveTotalDistance = 0.0;
+        //容許開始到結束的全部移動量小於該值則為點擊事件
+        double AllowMaxDistance = 8000;
+        //重新定位的Storyboard
+        private Storyboard storyboardForLocate = new Storyboard();
+        private StoryBoardStatus storyboardStatus = StoryBoardStatus.StoryBoardIsStop;
+        //重新定位的 Storyboard 速度調整係數
+        private int StorySmoothValue = 300;
+        //輪播的Storyboard
+        private Storyboard autoRunStoryboard = new Storyboard();
+        //當前歷史牆載入完成
+        private bool isHistoryWallLoadComplete = false;
+        //狀態為手動或者輪播模式
+        public HistoryControlMode ControlMode = HistoryControlMode.Boot;
+        //Loading~
+        HomePage hp;
+
+        public CyclicScroller(int languageIndex)
+        {
+            InitializeComponent();
+            
+            if (ConfigSettingClass.MainBackCollect == null)
+            {
+                MessageBox.Show("設定錯誤,請透過後台更新設定!!");
+                Application.Current.Shutdown();
+                return;
+            }
+
+            //初始化除了Spec外的基本設定
+            //refresh setting
+            new ConfigSettingClass(GlobalFunction.ConfigSettingFilePath, CurrentMonitorCount);
+            InitialWholeSetting();
+
+            if (GlobalFunction.isSolutionUsing4K)
+            {
+                MainEventWidth *= 2;
+                MainEventHeight *= 2;
+                YearEventHeight *= 2;
+
+                this.uxMyScroll.Margin = new Thickness(this.uxMyScroll.Margin.Left, this.uxMyScroll.Margin.Top, this.uxMyScroll.Margin.Right, this.uxMyScroll.Margin.Bottom * 2);
+            }
+
+            if (CurrentMonitorCount.ncm == 0)
+            {
+                MessageBox.Show("螢幕解析度取得失敗, 可能會造成載入異常!!");
+                Application.Current.Shutdown();
+                return;
+            }
+
+            this.Loaded += new RoutedEventHandler(CyclicScroller_Loaded);
+
+            this.KeyDown += new KeyEventHandler(CyclicScroller_KeyDown);
+        }
+
+
+        private void CyclicScroller_KeyDown(object sender, KeyEventArgs e)
+        {
+            //取得Ctrl + s進入後台設定
+            if (e.Key == Key.S && Keyboard.Modifiers == ModifierKeys.Shift)
+            {
+                Exception closeEx = CloseProcess("nLightenHistoryWallEdit");
+                if (closeEx != null)
+                {
+                    Debug.WriteLine(closeEx.Message);
+                }
+                Thread.Sleep(100);
+                Exception ex = OpenProcess(AppDomain.CurrentDomain.BaseDirectory + "nLightenHistoryWallEdit.exe");
+                if (ex != null)
+                {
+                    MessageBox.Show(ex.Message);
+                }
+            }
+        }
+
+        void CyclicScroller_Loaded(object sender, RoutedEventArgs e)
+        {
+            //取得資料
+            if (!GetHistoryData())
+            {
+                MessageBox.Show("資料準備中,敬請期待!");
+                Application.Current.Shutdown();
+                return;
+            }
+            //*設定規範值請參閱 SpecificationValue.cs file.
+            SetSpecValue();
+            //設定當前語系
+            SetLanguage();
+            //設定回正被中斷時~應該回到的顯示位置
+            SetReturnPos();
+            //根據螢幕數量~顯示螢幕中會有幾個內容(children)
+            ChildrenCount = GetChildrenCount();
+            //根據可以顯示的 Children 數量~新建出 Grid For 裝載DetailViewer
+            CreateExtraUnitGrid();
+            //初始化該 ExtraUnitGrid ~包括 狀態 位置 
+            InitializeExtraUnitGrid();
+            //拖動隱藏區塊顯示設定
+            SetDisplayPart();
+            //將首頁輪播 LoadBar 加到畫面中
+            AddHomePageAnimation();
+            //計算總事件~並將該直傳到Homepage中
+            CalcCountToHomePage();
+            //延遲載入~避免程式咬死
+            WpfDelayDoWork.DoBackgroundWork(CreateLiveConainer, 1000);
+        }
+
+        private void CreateLiveConainer()
+        {
+            if (xmlDataList.Count <= 0)
+            { return; }
+            //Loading Start
+            LoadingStart();
+            //總共會有多少筆 MainEvent ? 透過 YearList 中的個數將 MainEvent 預先建立起來
+            CreatMainEvent();
+            //是否需要將首年顯示在中間
+            if (NeedToGetCenter)
+            {
+                CenterIndexValue = GetCenterIndexValue();
+            }
+            //之後代表會有 ChildrenCount 個數量會在 Scrollviewer 當中
+            currentLoadIndex = GetIndexFromLeftSide();
+            currentLoadIndex -= CenterIndexValue;
+            AddEventBlock(currentLoadIndex, false);
+            //回正Storyboard
+            BackToPosFromCurrentLoadIndex(currentLoadIndex);
+
+            //自動輪播
+            GlobalFunction.CheckAutoRunTimer.Start();
+            isHistoryWallLoadComplete = true;
+        }
+        //回正
+        private void BackToPosFromCurrentLoadIndex(int currentLoadIndex)
+        {
+            isTouchDown = false;
+
+            double dd = Math.Abs(MainEventWidth + NoneUseRange - uxMyScroll.HorizontalOffset) / StorySmoothValue;
+
+            if (dd <= 0.3)
+            {
+                dd = 0.3;
+            }
+            else if (dd >= 0.5)
+            {
+                dd = 0.5;
+            }
+
+            //完成後由 storyboard 回到中間位置
+            DoubleAnimation dbOffset = new DoubleAnimation()
+            {
+                Duration = TimeSpan.FromSeconds(dd),
+                EasingFunction = new PowerEase()
+                {
+                    EasingMode = EasingMode.EaseOut,
+                    Power = 2
+                },
+            };
+
+            ScrollViewerUtilities.UseMotionStop = false;
+            Storyboard.SetTarget(dbOffset, (DependencyObject)this.FindName("uxMyScroll"));
+            Storyboard.SetTargetProperty(dbOffset, new PropertyPath(ScrollViewerUtilities.HorizontalOffsetProperty));
+            storyboardForLocate.Children.Add(dbOffset);
+            storyboardForLocate.FillBehavior = FillBehavior.HoldEnd;
+
+            dbOffset.From = uxMyScroll.HorizontalOffset;
+            dbOffset.To = MainEventWidth + NoneUseRange;
+
+            SetStoryBoardStatus(StoryBoardStatus.StoryBoardIsRun);
+        }
+
+        void storyboardForLocate_Completed(object sender, EventArgs e)
+        {
+            SetStoryBoardStatus(StoryBoardStatus.StoryBoardIsStop);
+
+            if (ControlMode == HistoryControlMode.Boot)
+            {
+                ControlMode = HistoryControlMode.Manual;
+            }
+            //確實停止後才開始判斷是否為點擊sdlu
+            if (storyboardStatus == StoryBoardStatus.StoryBoardIsStop)
+            {
+                if (MoveTotalDistance <= AllowMaxDistance)
+                {
+                    //通知 判斷為點擊
+                    SendInfoToLiveContainer(TouchorManipulation.TouchEvent);
+                }
+                else
+                {
+                    //通知 判斷為Manipulation
+                    SendInfoToLiveContainer(TouchorManipulation.ManipulationEvent);
+                }
+
+                MoveTotalDistance = 0.0;
+                //改變被點擊開的兩旁資訊
+                ChangeDetailSide();
+            }
+        }
+
+        //啟動或停止回正的storyboard
+        private void SetStoryBoardStatus(StoryBoardStatus sbs)
+        {
+            if (sbs == StoryBoardStatus.StoryBoardIsRun)
+            {
+                storyboardForLocate.Begin();
+                storyboardStatus = sbs;
+            }
+            else if (sbs == StoryBoardStatus.StoryBoardIsStop)
+            {
+                storyboardForLocate.Stop();
+                storyboardStatus = sbs;
+            }
+        }
+
+        #region 將每個年份事件區塊加到 Scrollviewer 中
+        /// <summary>
+        /// 將要顯示的事件區塊加到 StackPanel 中
+        /// </summary>
+        /// <param name="startIndex">從事件包(LiveContainerList)中取出事件的起始索引位置</param>
+        /// <param name="IsRightSide">往左邊改變或者往右邊改變</param>
+        private void AddEventBlock(int startIndex, bool IsRightSide)
+        {
+            if (ClearScrollChildren(IsRightSide))
+            {
+                for (int index = 0; index < ChildrenCount + 2; index++)
+                {
+                    int addcount = (startIndex + index) % LiveContainerList.Count;
+
+                    AddGridIntoScroll(addcount, index, true);
+                }
+            }
+            else    //如果不是第一次載入~代表該狀況為移動畫面造成改變~所以依照移動的方向做區塊的改變
+            {
+                int index = 0;
+
+                //由右到左
+                if (IsRightSide)
+                {
+                    index = ChildrenCount + 1;
+                }
+                else //由左到右
+                {
+                    index = 0;
+                }
+                int addcount = (startIndex + index) % LiveContainerList.Count;
+
+                AddGridIntoScroll(addcount, index, IsRightSide);
+            }
+
+            //改變年份區塊的索引值與顏色
+            ChangeBlockColor();
+
+            //**改變視角位置 (移動到中間的區塊)**
+            if (IsRightSide)
+            {
+                uxMyScroll.ScrollToHorizontalOffset(uxMyScroll.HorizontalOffset - MainEventWidth);
+            }
+            else
+            {
+                uxMyScroll.ScrollToHorizontalOffset(uxMyScroll.HorizontalOffset + MainEventWidth);
+            }
+        }
+
+        private void ChangeBlockColor()
+        {
+            //更新物件在Scroller中的索引位置~並改變其顏色
+            for (int count = 0; count < uxMyStackPanel.Children.Count; count++)
+            {
+                ((LiveContainer)uxMyStackPanel.Children[count]).Set_Get_ContainerIndex = count;
+                if (count <= 1 || count >= ChildrenCount)
+                {
+                    ((LiveContainer)uxMyStackPanel.Children[count]).ChangeControlColor(false);
+                }
+                else
+                    ((LiveContainer)uxMyStackPanel.Children[count]).ChangeControlColor(true);
+            }
+        }
+
+        private bool ClearScrollChildren(bool IsRightSide)
+        {
+            //如果整個Panel都沒有物件的話代表這是第一次載入物件~所以不須執行任何移除物件的動作
+            if (uxMyStackPanel.Children.Count > 0)
+            {
+                if (IsRightSide)
+                {
+                    //移除第一個
+                    ((LiveContainer)uxMyStackPanel.Children[0]).Set_Get_ContainerIndex = -1;
+                    uxMyStackPanel.Children.RemoveAt(0);
+                }
+                else
+                {
+                    //移除最後一個
+                    ((LiveContainer)uxMyStackPanel.Children[uxMyStackPanel.Children.Count - 1]).Set_Get_ContainerIndex = -1;
+                    uxMyStackPanel.Children.RemoveAt(uxMyStackPanel.Children.Count - 1);
+                }
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// 新增一個區塊到 Stackpanel 中
+        /// </summary>
+        /// <param name="addcount">要新增的區塊是事件包 (LiveContainerList)中的哪一個</param>
+        /// <param name="index">主要是回報給Homepage, 是哪幾個年份區塊在stackpanel 中</param>
+        /// <param name="IsAddBlock">新增的方式是 Add or Insert</param>
+        private void AddGridIntoScroll(int addcount, int index, bool IsAddBlock)
+        {
+            if (IsAddBlock)
+            {
+                uxMyStackPanel.Children.Add(LiveContainerList[addcount]);
+            }
+            else
+            {
+                uxMyStackPanel.Children.Insert(0, LiveContainerList[addcount]);
+            }
+
+            //將初始完成後~顯示在畫面中的年份資料傳給Homepage
+            if (RunHomePageAnimation)
+            {
+                if (index >= 1 && index <= ChildrenCount)
+                {
+                    hp.xmlDataList.Add(LiveContainerList[addcount].xmlData);
+                }
+            }
+        }
+        #endregion
+
+        /// <summary>
+        /// 透過 YearList 中的個數將 MainEvent 預先建立起來"如不足則循環"
+        /// </summary>
+        private void CreatMainEvent()
+        {
+            //"如不足則循環"方式為~依照各螢幕數量不同給予不同的常數值
+            int staticvalue = GetCycleCount();
+
+            for (int index = 0; index < staticvalue; index++)
+            {
+                for (int count = 0; count < xmlDataList.Count; count++)
+                {
+                    LiveContainer liveContainer = new LiveContainer(xmlDataList[count], MainEventWidth, MainEventHeight);
+
+                    //通知 LiveContainer 通道
+                    liveContainer.ListenFromCyclicTouchStatus(this);
+                    //接收來自 LiveContainer 通道
+                    liveContainer.LiveContainerBubbleToCyclicScrollerEvent += new LiveContainer.LiveContainerBubbleToCyclicScroller(ReceiveFromLiveContainerInfo);
+
+                    liveContainer.CreateLiveContainer();
+                    LiveContainerList.Add(liveContainer);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 這邊的計算方式為~
+        /// 如果是單螢幕則全部需要ChildrenCount個加四個備份所以是ChildrenCount + 4個, 
+        /// 雙螢幕需要ChildrenCount個加四個備份所以是ChildrenCount + 4個, 
+        /// 三螢幕需要ChildrenCount個加四個備份所以是ChildrenCount + 4個
+        /// 如果xml中的年份不足, 則必須進行循環. 此result則為循環次數
+        /// </summary>
+        /// <returns></returns>
+        private int GetCycleCount()
+        {
+            int result = 0;
+
+            //如果設定的年份少於全部需要的則必須
+            switch (CurrentMonitorCount.ncm)
+            {
+                case MonitorFlag.Monitor1_1:
+                case MonitorFlag.Monitor2_1:
+                case MonitorFlag.Monitor3_1:
+                case MonitorFlag.Monitor4_1:
+                case MonitorFlag.Monitor5_1:
+                case MonitorFlag.Monitor6_1:
+                    {
+                        result = (TotalShowChildren / xmlDataList.Count) + 1;
+                        break;
+                    }
+            }
+            return result;
+        }
+
+        public static T DeserializeFromJson<T>(string json)
+        {
+            T deserializedProduct = JsonConvert.DeserializeObject<T>(json);
+            return deserializedProduct;
+        }
+
+        /// <summary>
+        ///  //取得 ini 中的資料
+        /// </summary>
+        /// <returns></returns>
+        private bool GetHistoryData()
+        {
+            List<EventGroup> eventgroups = new List<EventGroup>();
+            HistoryWallEventJson hweventJson = new HistoryWallEventJson();
+
+            if (File.Exists(GlobalFunction.JsonFilePath))
+            {
+                string jsonResult;
+
+                xmlDataList.Clear();
+                using (StreamReader sr = new StreamReader(GlobalFunction.JsonFilePath))
+                {
+                    jsonResult = sr.ReadToEnd();
+                }
+                hweventJson = DeserializeFromJson<HistoryWallEventJson>(jsonResult);
+                eventgroups = hweventJson.EventGroups;
+                if (hweventJson.EventGroups.Count <= 0)
+                {
+                    return false;
+                }
+
+                for (int index = 0; index < hweventJson.EventGroups.Count; index++)
+                {
+                    if (hweventJson.EventGroups[index].ListDates.Count > 0)
+                    {
+                        XmlData xmldata = new XmlData(hweventJson.EventGroups[index]);
+
+                        xmlDataList.Add(xmldata);
+                    }
+                }
+            }
+            else
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        /// <summary>
+        /// 自動移動
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        void AutoRunTimer_Tick(object sender, EventArgs e)
+        {
+            uxMyScroll.ScrollToHorizontalOffset(uxMyScroll.HorizontalOffset + 1);
+        }
+
+        private void uxMyScroll_ManipulationStarted(object sender, ManipulationStartedEventArgs e)
+        {
+            if (isHistoryWallLoadComplete)
+            {
+                SetStoryBoardStatus(StoryBoardStatus.StoryBoardIsStop);
+                isTouchDown = true;
+                isManipulatonEvent = false;
+                MoveStartHorizontalX = uxMyScroll.HorizontalOffset;
+            }
+
+            e.Handled = true;
+        }
+
+        private void uxMyScroll_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
+        {
+            if (isTouchDown)
+            {
+                uxMyScroll.ScrollToHorizontalOffset(uxMyScroll.HorizontalOffset - e.DeltaManipulation.Translation.X);
+                MoveTotalDistance += Math.Abs(uxMyScroll.HorizontalOffset - e.DeltaManipulation.Translation.X);
+            }
+
+            e.Handled = true;
+        }
+
+        private void uxMyScroll_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
+        {
+            if (isTouchDown)
+            {
+                isTouchDown = false;
+                BackToPosFromCurrentLoadIndex(currentLoadIndex);
+            }
+            isManipulatonEvent = false;
+            e.Handled = true;
+        }
+
+        private void uxMyScroll_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
+        {
+            e.TranslationBehavior = new InertiaTranslationBehavior()
+            {
+                InitialVelocity = e.InitialVelocities.LinearVelocity,
+                DesiredDeceleration = 20.0 * 96.0 / (1000.0 * 1000.0)
+            };
+
+            e.Handled = true;
+        }
+
+        /// <summary>
+        /// 改變被點擊開的兩旁資訊
+        /// </summary>
+        private void ChangeDetailSide()
+        {
+            int count = ExtraUnitGridList.Count;
+
+            for (int index = 0; index < count; index++)
+            {
+                if (ExtraUnitGridList[index].IsUsing != 0 &&
+                    ExtraUnitGridList[index].Get_Set_BlockControlMode != ExtraUnitGrid.ControlMode.Extend)
+                {
+                    int mappingStackpanel = index + 1;
+
+                    if (((LiveContainer)uxMyStackPanel.Children[mappingStackpanel]).uxYearStr.Text != ExtraUnitGridList[index].textblock.Text)
+                    {
+                        if (ExtraUnitGridList[index].Get_Set_BlockControlMode != ExtraUnitGrid.ControlMode.MinStatus)
+                        {
+                            ExtraUnitGridList[index].textblock.Text = ((LiveContainer)uxMyStackPanel.Children[mappingStackpanel]).uxYearStr.Text;
+                        }
+                        ThumbnailContainer thumbnailControl = new ThumbnailContainer();
+                        List<string> folderPaths = new List<string>();
+
+                        ExtraUnitGridList[index].DetailViewerControlHide();
+                        folderPaths = GetThumbnailControl(mappingStackpanel);
+                        thumbnailControl.ImgPath = MediaUtilties.GetImageFromFolders(folderPaths.ToArray());
+                        ExtraUnitGridList[index].BorderUp.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
+                        ExtraUnitGridList[index].BorderUp.Child = thumbnailControl;
+
+                        ExtraUnitGridList[index].DetailViewerControlShow(null, null);
+                    }
+                }
+            }
+        }
+
+        private Exception OpenProcess(string exePath)
+        {
+            if (File.Exists(exePath))
+            {
+                ProcessStartInfo startInfo = new ProcessStartInfo();
+                startInfo.FileName = exePath;
+                try
+                {
+                    Process startProcess = Process.Start(startInfo);
+                    return null;
+                }
+                catch (Exception ex)
+                {
+                    return ex;
+                }
+            }
+            else
+            {
+                return new Exception(exePath + "檔案不存在!");
+            }
+        }
+
+        private Exception CloseProcess(string processName)
+        {
+            try
+            {
+                bool isKill = false;
+                System.Diagnostics.Process[] myProcesses = System.Diagnostics.Process.GetProcesses();
+                foreach (System.Diagnostics.Process myProcess in myProcesses)
+                {
+                    if (myProcess.ProcessName == processName)
+                    {
+                        Debug.WriteLine(myProcess.ProcessName + " " + myProcess.MainWindowHandle.ToString());
+                        myProcess.Kill();
+                        isKill = true;
+                    }
+                }
+                if (isKill)
+                {
+                    return null;
+                }
+                else
+                {
+                    return new Exception("Cannot find " + processName);
+                }
+            }
+            catch (Exception ex)
+            {
+                return ex;
+            }
+        }
+
+        private void Window_PreviewTouchDown(object sender, TouchEventArgs e)
+        {
+            //停止輪播
+            StopAutoRunTheWall();
+            GlobalFunction.CheckAutoRunTimer.Stop();
+        }
+
+        //避免點擊在非歷史軸的時, 歷史軸會因為輪播停止而卡住的狀況
+        private void Window_PreviewTouchUp(object sender, TouchEventArgs e)
+        {
+            if (!isManipulatonEvent && isHistoryWallLoadComplete && isAutoRun)
+            {
+                BackToPosFromCurrentLoadIndex(currentLoadIndex);
+            }
+
+            isAutoRun = false;
+            if (!GlobalFunction.isVideoPlay)
+                GlobalFunction.CheckAutoRunTimer.Start();
+        }
+
+        private void uxMyScroll_ScrollChanged(object sender, System.Windows.Controls.ScrollChangedEventArgs e)
+        {
+            if (ControlMode == HistoryControlMode.Boot)
+            {
+                return;
+            }
+
+            MoveEndHorizontalX = uxMyScroll.HorizontalOffset;
+
+            //手指頭往左邊的移動
+            if (MoveEndHorizontalX > MainEventWidth * 2 + NoneUseRange - (MainEventWidth / 2))
+            {
+                autoRunStoryboard.Stop();
+                //判斷當前的Index是否超出"最大"容許範圍~進行調整
+                currentLoadIndex = GetIndexFromRightSide();
+                //重新加入EventBlock
+                AddEventBlock(currentLoadIndex, true);
+                if (ControlMode == HistoryControlMode.AutoRun)
+                {
+                    SetAutoRunStoryBoard(MoveEndHorizontalX - MainEventWidth, MoveEndHorizontalX - MainEventWidth + MainEventWidth);
+                    autoRunStoryboard.Begin();
+                }
+            }
+            //手指頭往右邊的移動
+            else if (MoveEndHorizontalX < MainEventWidth + NoneUseRange - (MainEventWidth / 2))
+            {
+                //判斷當前的Index是否低於"最小"容許範圍~進行調整
+                currentLoadIndex = GetIndexFromLeftSide();
+                //重新加入EventBlock
+                AddEventBlock(currentLoadIndex, false);
+            }
+        }
+
+        #region 切換語系與回首頁按鈕
+        private void ChangeLangBtn_Click(object sender, RoutedEventArgs e)
+        {
+            int changeLanIndex = 0;
+
+            if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 0)
+            {
+                if (canUsingLangList[1])
+                {
+                    changeLanIndex = 1;
+                }
+                else if (canUsingLangList[2])
+                {
+                    changeLanIndex = 2;
+                }
+                else if (canUsingLangList[3])
+                {
+                    changeLanIndex = 3;
+                }
+            }
+            else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 1)
+            {
+                if (canUsingLangList[2])
+                {
+                    changeLanIndex = 2;
+                }
+                else if (canUsingLangList[3])
+                {
+                    changeLanIndex = 3;
+                }
+                else if (canUsingLangList[0])
+                {
+                    changeLanIndex = 0;
+                }
+            }
+            else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 2)
+            {
+                if (canUsingLangList[3])
+                {
+                    changeLanIndex = 3;
+                }
+                else if (canUsingLangList[0])
+                {
+                    changeLanIndex = 0;
+                }
+                else if (canUsingLangList[1])
+                {
+                    changeLanIndex = 1;
+                }
+            }
+            else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 3)
+            {
+                if (canUsingLangList[0])
+                {
+                    changeLanIndex = 0;
+                }
+                else if (canUsingLangList[1])
+                {
+                    changeLanIndex = 1;
+                }
+                else if (canUsingLangList[2])
+                {
+                    changeLanIndex = 2;
+                }
+            }
+
+            if (changeLanIndex == 0)
+            {
+                ConfigSettingClass.MainBackCollect.DefaultLangIndex = changeLanIndex;
+                System.Windows.Application.Current.Properties["Language"] = "Language1";
+            }
+            else if (changeLanIndex == 1)
+            {
+                ConfigSettingClass.MainBackCollect.DefaultLangIndex = changeLanIndex;
+                System.Windows.Application.Current.Properties["Language"] = "Language2";
+            }
+            else if (changeLanIndex == 2)
+            {
+                ConfigSettingClass.MainBackCollect.DefaultLangIndex = changeLanIndex;
+                System.Windows.Application.Current.Properties["Language"] = "Language3";
+            }
+            else if (changeLanIndex == 3)
+            {
+                ConfigSettingClass.MainBackCollect.DefaultLangIndex = changeLanIndex;
+                System.Windows.Application.Current.Properties["Language"] = "Language0";
+            }
+
+            uxMainLangBtnL.Content = ConfigSettingClass.MainBackCollect.LangText[ConfigSettingClass.MainBackCollect.DefaultLangIndex];
+            uxMainLangBtnR.Content = ConfigSettingClass.MainBackCollect.LangText[ConfigSettingClass.MainBackCollect.DefaultLangIndex];
+
+            for (int i = 0; i < LiveContainerList.Count; i++)
+            {
+                LiveContainerList[i].WriteYearBarStr();
+                //改變事件區塊中顯示文字分兩部分
+                //1. 已經在事件區塊中顯示的 Planerotate
+                LiveContainerList[i].ChangeCurPlaneRotateLan();
+                //2. 在緩衝區中待顯示的 Planerotate
+                //LiveContainerList[i].ChangePlaneRotateLan();
+            }
+
+            for (int j = 0; j < ExtraUnitGridList.Count; j++)
+            {
+                if (ExtraUnitGridList[j].curDataIndex != -1)
+                {
+                    ExtraUnitGridList[j].textblock.Text = ((LiveContainer)uxMyStackPanel.Children[j + 1]).uxYearStr.Text;
+                }
+            }
+        }
+
+        private void HomeBtn_Click(object sender, RoutedEventArgs e)
+        {
+            if (HomeBackInforEvent != null)
+                this.Dispatcher.BeginInvoke(HomeBackInforEvent, DispatcherPriority.Background);
+        }
+        #endregion
+    }
+
+
+    public class WpfDelayDoWork
+    {
+        public static void DoWork(Action action, int millisecond = 300)
+        {
+            new Action<Dispatcher, Action, int>(DoWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
+        }
+
+        public static void DoBackgroundWork(Action action, int millisecond = 300)
+        {
+            new Action<Dispatcher, Action, int>(DoBackgroundWorkAsync).BeginInvoke(Dispatcher.CurrentDispatcher, action, millisecond, null, null);
+        }
+
+        static void DoWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
+        {
+            System.Threading.Thread.Sleep(millisecond);
+            dispatcher.BeginInvoke(action);
+        }
+
+        static void DoBackgroundWorkAsync(Dispatcher dispatcher, Action action, int millisecond)
+        {
+            System.Threading.Thread.Sleep(millisecond);
+            dispatcher.Invoke(action, DispatcherPriority.Background);
+        }
+    }
+}

+ 390 - 0
HistoryDLL/CyclicScrollerCommunication.cs

@@ -0,0 +1,390 @@
+using MediaViewerLib.Utilities;
+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.Media;
+using System.Windows.Media.Imaging;
+
+namespace HistoryDLL
+{
+    /// <summary>
+    /// CyclicScroller 事件傳遞與通訊
+    /// </summary>
+    public partial class CyclicScroller : UserControl
+    {
+        //外掛 Delegate event for communicate with LiveContainer (通知用 ~ 通知確認動作清除 LiveContainer 點擊動作)
+        public delegate void CyclicScrollerBubbleToLiveContainer(string ProcessCode);
+        public event CyclicScrollerBubbleToLiveContainer CyclicScrollerBubbleToLiveContainerEvent;
+
+        public List<TouchInfo> touchinfoList = new List<TouchInfo>();
+
+        //通知各 LiveContainer 函數~manipulation 事件或者為點擊展開事件
+        void SendInfoToLiveContainer(TouchorManipulation Triggerevent)
+        {
+            if (Triggerevent == TouchorManipulation.TouchEvent)
+            {
+                if (touchinfoList.Count != 0)
+                {
+                    for (int index = 0; index < touchinfoList.Count; index++)
+                    {
+                        //for (int count = 0; count < ExtraUnitGridList.Count; count++)
+                        {
+                            int count = touchinfoList[index].TouchIndex - 1;
+                            if (touchinfoList[index].TouchIndex == ExtraUnitGridList[count].Get_Set_MonitorIndex)
+                            {
+                                if (CheckExtendIsLegal(count))
+                                {
+                                    //判斷是否可以展開?
+                                    if (ExtraUnitGridList[count].Get_Set_BlockControlMode == ExtraUnitGrid.ControlMode.CanExtend ||
+                                        ExtraUnitGridList[count].IsUsing == 0)
+                                    {
+                                        //將點擊到的最上層物件加到MainWindow
+                                        AddExtraUnitGridListInToMainWindow(count);
+                                        AddExtraUnitGridListInToMainWindow(count - 1);
+                                        AddExtraUnitGridListInToMainWindow(count + 1);
+
+                                        //加載DetailViewer
+                                        ExtraUnitGridList[count].BorderUp.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
+
+                                        ExtraUnitGridList[count].BorderUp.Child = AddDetailViewer(touchinfoList[index].TouchIndex, touchinfoList[index].IndexofEvent, touchinfoList[index].IndexofPic);
+                                        ExtraUnitGridList[count].ExtendFunction();
+
+                                        //寫入文字
+                                        ExtraUnitGridList[count].textblock.Text = ((LiveContainer)uxMyStackPanel.Children[touchinfoList[index].TouchIndex]).uxYearStr.Text;
+                                        ExtraUnitGridList[count].curDataIndex = -1;
+
+                                        if (count + 1 < ExtraUnitGridList.Count)
+                                        {
+                                            ThumbnailContainer thumbnailControl = new ThumbnailContainer();
+                                            List<string> folderPaths = new List<string>();
+
+                                            folderPaths = GetThumbnailControl(touchinfoList[index].TouchIndex + 1);
+                                            thumbnailControl.ImgPath = MediaUtilties.GetImageFromFolders(folderPaths.ToArray());
+                                            ExtraUnitGridList[count + 1].BorderUp.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
+                                            ExtraUnitGridList[count + 1].BorderUp.Child = thumbnailControl;
+
+                                            ExtraUnitGridList[count + 1].textblock.Text = ((LiveContainer)uxMyStackPanel.Children[touchinfoList[index].TouchIndex + 1]).uxYearStr.Text;
+                                            ExtraUnitGridList[count + 1].curDataIndex = touchinfoList[index].TouchIndex + 1;
+                                            ExtraUnitGridList[count + 1].ShrinkFunction("Right");
+                                        }
+                                        if (count - 1 >= 0)
+                                        {
+                                            ThumbnailContainer thumbnailControl = new ThumbnailContainer();
+                                            List<string> folderPaths = new List<string>();
+
+                                            folderPaths = GetThumbnailControl(touchinfoList[index].TouchIndex - 1);
+                                            thumbnailControl.ImgPath = MediaUtilties.GetImageFromFolders(folderPaths.ToArray());
+                                            ExtraUnitGridList[count - 1].BorderUp.VerticalAlignment = System.Windows.VerticalAlignment.Bottom;
+                                            ExtraUnitGridList[count - 1].BorderUp.Child = thumbnailControl;
+
+                                            ExtraUnitGridList[count - 1].textblock.Text = ((LiveContainer)uxMyStackPanel.Children[touchinfoList[index].TouchIndex - 1]).uxYearStr.Text;
+                                            ExtraUnitGridList[count - 1].curDataIndex = touchinfoList[index].TouchIndex - 1;
+                                            ExtraUnitGridList[count - 1].ShrinkFunction("Left");
+                                        }
+                                        CheckDisplayRange();
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            else if (Triggerevent == TouchorManipulation.ManipulationEvent)
+            {
+                this.Dispatcher.BeginInvoke(CyclicScrollerBubbleToLiveContainerEvent, "Manipulation");
+            }
+
+            touchinfoList.Clear();
+        }
+
+        private bool CheckExtendIsLegal(int index)
+        {
+            bool result = true;
+            index += 1;
+            //判斷右邊
+            if (index + 2 < ExtraUnitGridList.Count)
+            {
+                if (ExtraUnitGridList[index + 2].ShrinkStoryboardRun)
+                    result = false;
+            }
+            //判斷左邊
+            if (index - 2 >= 0)
+            {
+                if (ExtraUnitGridList[index - 2].ShrinkStoryboardRun)
+                    result = false;
+            }
+
+            return result;
+        }
+
+        /// <summary>
+        /// 通知各 LiveContainer 函數 自動輪播或者停止自動輪播事件通知
+        /// </summary>
+        /// <param name="ControlMode">當前模式</param>
+        private void SendControlModeToLiveContainer(HistoryControlMode ControlMode)
+        {
+            if (ControlMode == HistoryControlMode.AutoRun)
+            {
+                this.Dispatcher.BeginInvoke(CyclicScrollerBubbleToLiveContainerEvent, "AutoRun");
+            }
+            else if (ControlMode == HistoryControlMode.Manual)
+            {
+                this.Dispatcher.BeginInvoke(CyclicScrollerBubbleToLiveContainerEvent, "Manual");
+            }
+        }
+
+        private UIElement AddDetailViewer(int LiveContainerIndex, int indexofevent, int indexofpic)
+        {
+            //ImageBrush imagebrush = new ImageBrush(new BitmapImage(new Uri(@"pack://application:,,,/" + GlobalFunction.projectname + @";component/Data/Thumb/shadow_big.png", UriKind.RelativeOrAbsolute)));
+            ImageBrush imagebrush = null;
+            Grid gd = new Grid();
+            int xy = 15;
+
+            gd.Width = 810 + xy;
+            gd.Height = 535 + 14;
+            if (GlobalFunction.isSolutionUsing4K)
+            {
+                gd.Width *= 2;
+                gd.Height *= 2;
+            }
+
+            //imagebrush.Stretch = Stretch.Uniform;
+            gd.Background = Brushes.Transparent;
+            gd.VerticalAlignment = System.Windows.VerticalAlignment.Center;
+            gd.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
+            gd.Margin = GlobalFunction.isSolutionUsing4K ? new Thickness(0, 50, 0, 0) : new Thickness(0);
+
+            DetailViewer viewer = new DetailViewer(((LiveContainer)uxMyStackPanel.Children[LiveContainerIndex]).xmlData, LiveContainerIndex, indexofevent, indexofpic);
+            viewer.IndexOfControl = LiveContainerIndex;
+            viewer.Margin = new Thickness(0, 0, GlobalFunction.isSolutionUsing4K ? 8 : 4, GlobalFunction.isSolutionUsing4K ? 9 : 4);
+            viewer.VerticalAlignment = System.Windows.VerticalAlignment.Center;
+            viewer.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;
+            viewer.ChangeLanguageBtnTriggerEvent += new DetailViewer.ChangeLanguageBtnTriggerDelegate(viewer_ChangeLanguageBtnTriggerEvent);
+            viewer.CloseBtnTriggerEvent += Viewer_CloseBtnTriggerEvent;
+            //viewer.OnCloseEvent += new EventHandler<EventArgs>(viewer_OnCloseEvent);
+            gd.Children.Add(viewer);
+
+            return gd;
+        }
+
+        private void viewer_ChangeLanguageBtnTriggerEvent(int index, int useLangIndex)
+        {
+            LiveContainer lc = uxMyStackPanel.Children[index] as LiveContainer;
+
+            if (useLangIndex == 0)
+            {
+                ExtraUnitGridList[index - 1].textblock.Text = lc.xmlData.yearlan1;
+            }
+            else if (useLangIndex == 1)
+            {
+                ExtraUnitGridList[index - 1].textblock.Text = lc.xmlData.yearlan2;
+            }
+            else if (useLangIndex == 2)
+            {
+                ExtraUnitGridList[index - 1].textblock.Text = lc.xmlData.yearlan3;
+            }
+            else if (useLangIndex == 3)
+            {
+                ExtraUnitGridList[index - 1].textblock.Text = lc.xmlData.yearlan4;
+            }
+        }
+
+
+        private void Viewer_CloseBtnTriggerEvent(int indexOfCtrl)
+        {
+            SendInfoToMainWindow(indexOfCtrl);
+        }
+
+        private List<string> GetThumbnailControl(int LiveContainerIndex)
+        {
+            List<string> resultList = new List<string>();
+            XmlData data = ((LiveContainer)uxMyStackPanel.Children[LiveContainerIndex]).xmlData;
+
+            for (int i = 0; i < data.monthclassList.Count; i++)
+            {
+                resultList.Add(GlobalFunction.EventFileImgPath + data.monthclassList[i].imagepath);
+            }
+
+            return resultList;
+        }
+
+        //通知主視窗~可以將點擊開的物件縮回
+        private void SendInfoToMainWindow(int index)
+        {
+            for (int count = 0; count < ExtraUnitGridList.Count; count++)
+            {
+                if (index == ExtraUnitGridList[count].Get_Set_MonitorIndex)
+                {
+                    //判斷是否可以縮小
+                    if (ExtraUnitGridList[count].Get_Set_BlockControlMode == ExtraUnitGrid.ControlMode.Extend)
+                    {
+                        //回到原始大小
+                        ExtraUnitGridList[count].ReturnToOriginalSize();
+                        if (count + 1 < ExtraUnitGridList.Count)
+                        {
+                            ExtraUnitGridList[count + 1].BackSize("Right");
+                        }
+                        if (count - 1 >= 0)
+                        {
+                            ExtraUnitGridList[count - 1].BackSize("Left");
+                        }
+                    }
+                }
+            }
+        }
+
+        private void AddExtraUnitGridListInToMainWindow(int index)
+        {
+            if (index < 0 || index >= ExtraUnitGridList.Count)
+            {
+                return;
+            }
+
+            if (ExtraUnitGridList[index].IsUsing == 0)
+            {
+                ExtraUnitGridList[index].IsUsing = 1;
+                if (!uxMainWindow.Children.Contains(ExtraUnitGridList[index]))
+                {
+                    uxMainWindow.Children.Add(ExtraUnitGridList[index]);
+                }
+            }
+            else
+            {
+                ExtraUnitGridList[index].IsUsing = 2;
+            }
+        }
+
+        //接收到~來自各LiveContainer 的通知
+        void ReceiveFromLiveContainerInfo(string ProcessCode, int index, int indexofevent, int indexofpic)
+        {
+            if (ProcessCode == "TouchDown")
+            {
+                TouchInfo tif = new TouchInfo(index, indexofevent, indexofpic);
+
+                touchinfoList.Add(tif);
+                //檢查 TouchInfo 是否有重複的索引
+                //檢查先被點擊的兩旁是否有被點擊~如果有被點擊則點擊無效~將該點擊濾掉
+                touchinfoList = FilterTouchInfo(touchinfoList);
+                //排列處理順序由小至大
+                if (touchinfoList.Count > 1)
+                {
+                    touchinfoList = ArrangeTouchInfo(touchinfoList);
+                }
+            }
+            else if (ProcessCode == "Load Complete")
+            {
+                if (RunHomePageAnimation)
+                {
+                    hp.AddLoadCount();
+                    //OnDataLoadCompeleted?.Invoke(this,null);
+                }
+            }
+        }
+
+        //接收來自 ExtraUnitGrid 的通知
+        void ExtraGrid_ExtraUnitGridBubbleToCyclicScrollerEvent(string ProcessCode, int index)
+        {
+            if (ProcessCode == "Change")
+            {
+                //通知主視窗~可以將點擊開的物件縮回
+                ExtraUnitGridList[index].ShrinkStoryboardRun = true;
+                SendInfoToMainWindow(index);
+            }
+            else if (ProcessCode == "Remove")
+            {
+                //移除該物件~先判斷該物件的兩邊的IsUsing已經被False
+                if (ExtraUnitGridList[index].IsUsing == 0)
+                {
+                    uxMainWindow.Children.Remove(ExtraUnitGridList[index]);
+                }
+                if (index + 1 > 0 && index + 1 < ExtraUnitGridList.Count)
+                {
+                    ExtraUnitGridList[index + 1].ShrinkStoryboardRun = false;
+                }
+                CheckDisplayRange();
+            }
+        }
+
+        /// <summary>
+        /// 1.檢查 TouchInfo 是否有重複的索引
+        /// 2.檢查先被點擊的兩旁是否有被點擊~如果有被點擊則點擊無效~將該點擊濾掉
+        /// </summary>
+        /// <param name="tif">來源</param>
+        private List<TouchInfo> FilterTouchInfo(List<TouchInfo> tifList)
+        {
+            List<TouchInfo> resultList = new List<TouchInfo>();
+            int totalcount = tifList.Count;
+
+            for (int count = 0; count < totalcount; count++)
+            {
+                int currentindex = tifList[count].TouchIndex;
+
+                if (!IsExistCount(currentindex, resultList))
+                {
+                    //不存在則新增
+                    resultList.Add(tifList[count]);
+                }
+            }
+            return resultList;
+        }
+
+        /// <summary>
+        /// 排列處理順序由小至大
+        /// </summary>
+        /// <param name="touchinfoList">來源</param>
+        /// <returns></returns>
+        private List<TouchInfo> ArrangeTouchInfo(List<TouchInfo> tifList)
+        {
+            List<TouchInfo> resultList = new List<TouchInfo>();
+            List<int> Arrange = new List<int>();
+
+            for (int count = 0; count < tifList.Count; count++)
+            {
+                Arrange.Add(tifList[count].TouchIndex);
+            }
+            Arrange.Sort();
+
+            for (int i = 0; i < Arrange.Count; i++)
+            {
+                for (int j = 0; j < tifList.Count; j++)
+                {
+                    if (Arrange[i] == tifList[j].TouchIndex)
+                    {
+                        resultList.Add(tifList[j]);
+                    }
+                }
+            }
+
+            return resultList;
+        }
+
+        private bool IsExistCount(int currentindex, List<TouchInfo> resultList)
+        {
+            bool resultbool = false;
+            int resultListCount = resultList.Count;
+
+            for (int count = 0; count < resultListCount; count++)
+            {
+                if (currentindex == resultList[count].TouchIndex)
+                {
+                    return true;
+                }
+                //兩旁也要濾掉
+                if ((currentindex - 1) == resultList[count].TouchIndex)
+                {
+                    return true;
+                }
+                if ((currentindex + 1) == resultList[count].TouchIndex)
+                {
+                    return true;
+                }
+            }
+
+            return resultbool;
+        }
+    }
+}

+ 323 - 0
HistoryDLL/CyclicScrollerOpcityMask.cs

@@ -0,0 +1,323 @@
+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.Media;
+
+namespace HistoryDLL
+{
+    public partial class CyclicScroller : UserControl
+    {
+        //OpacityMask Setting
+        LinearGradientBrush myLinearGradientBrush = new LinearGradientBrush();
+        GradientStopCollection myGradientStopCollection = new GradientStopCollection();
+        GradientStop LeftLineLeftPointStopFirst = new GradientStop();
+        GradientStop LeftLineRightPointStopFirst = new GradientStop();
+        GradientStop RightLineLeftPointStopFirst = new GradientStop();
+        GradientStop RightLineRightPointStopFirst = new GradientStop();
+
+        GradientStop LeftLineLeftPointStopSecond = new GradientStop();
+        GradientStop LeftLineRightPointStopSecond = new GradientStop();
+        GradientStop RightLineLeftPointStopSecond = new GradientStop();
+        GradientStop RightLineRightPointStopSecond = new GradientStop();
+
+        GradientStop LeftLineLeftPointStopThree = new GradientStop();
+        GradientStop LeftLineRightPointStopThree = new GradientStop();
+        GradientStop RightLineLeftPointStopThree = new GradientStop();
+        GradientStop RightLineRightPointStopThree = new GradientStop();
+
+        bool IsUsingFirst = false, IsUsingSecond = false, IsUsingThree = false;
+        /// <summary>
+        /// 拖動隱藏區塊顯示設定
+        /// </summary>
+        private void SetDisplayPart()
+        {
+            #region First
+            LeftLineLeftPointStopFirst.Offset = 0.0;
+            Color c1 = new Color();
+            c1 = GetColorRGB(true);
+            LeftLineLeftPointStopFirst.Color = c1;
+
+            LeftLineRightPointStopFirst.Offset = 0.0;
+            Color c2 = new Color();
+            c2 = GetColorRGB(false);
+            LeftLineRightPointStopFirst.Color = c2;
+
+            RightLineLeftPointStopFirst.Offset = 0.0;
+            Color c3 = new Color();
+            c3 = GetColorRGB(false);
+            RightLineLeftPointStopFirst.Color = c3;
+
+            RightLineRightPointStopFirst.Offset = 0.0;
+            Color c4 = new Color();
+            c4 = GetColorRGB(true);
+            RightLineRightPointStopFirst.Color = c4;
+            #endregion 
+
+            #region Second
+            LeftLineLeftPointStopSecond.Offset = 0.0;
+            Color c5 = new Color();
+            c5 = GetColorRGB(true);
+            LeftLineLeftPointStopSecond.Color = c5;
+
+            LeftLineRightPointStopSecond.Offset = 0.0;
+            Color c6 = new Color();
+            c6 = GetColorRGB(false);
+            LeftLineRightPointStopSecond.Color = c6;
+
+            RightLineLeftPointStopSecond.Offset = 0.0;
+            Color c7 = new Color();
+            c7 = GetColorRGB(false);
+            RightLineLeftPointStopSecond.Color = c7;
+
+            RightLineRightPointStopSecond.Offset = 0.0;
+            Color c8 = new Color();
+            c8 = GetColorRGB(true);
+            RightLineRightPointStopSecond.Color = c8;
+            #endregion
+
+            #region Three
+            LeftLineLeftPointStopThree.Offset = 0.0;
+            Color c9 = new Color();
+            c9 = GetColorRGB(true);
+            LeftLineLeftPointStopThree.Color = c9;
+
+            LeftLineRightPointStopThree.Offset = 0.0;
+            Color c10 = new Color();
+            c10 = GetColorRGB(false);
+            LeftLineRightPointStopThree.Color = c10;
+
+            RightLineLeftPointStopThree.Offset = 0.0;
+            Color c11 = new Color();
+            c11 = GetColorRGB(false);
+            RightLineLeftPointStopThree.Color = c11;
+
+            RightLineRightPointStopThree.Offset = 0.0;
+            Color c12 = new Color();
+            c12 = GetColorRGB(true);
+            RightLineRightPointStopThree.Color = c12;
+            #endregion
+
+            #region add GradientStop into Collection
+            myGradientStopCollection.Add(LeftLineLeftPointStopThree);
+            myGradientStopCollection.Add(LeftLineRightPointStopThree);
+            myGradientStopCollection.Add(RightLineLeftPointStopThree);
+            myGradientStopCollection.Add(RightLineRightPointStopThree);
+            myGradientStopCollection.Add(LeftLineLeftPointStopSecond);
+            myGradientStopCollection.Add(LeftLineRightPointStopSecond);
+            myGradientStopCollection.Add(RightLineLeftPointStopSecond);
+            myGradientStopCollection.Add(RightLineRightPointStopSecond);
+            myGradientStopCollection.Add(LeftLineLeftPointStopFirst);
+            myGradientStopCollection.Add(LeftLineRightPointStopFirst);
+            myGradientStopCollection.Add(RightLineLeftPointStopFirst);
+            myGradientStopCollection.Add(RightLineRightPointStopFirst);
+            #endregion
+
+            myLinearGradientBrush.StartPoint = new Point(0, 0);
+            myLinearGradientBrush.EndPoint = new Point(1, 0);
+            myLinearGradientBrush.GradientStops = myGradientStopCollection;
+
+            uxCyclicGrid.OpacityMask = myLinearGradientBrush;
+        }
+
+        private Color GetColorRGB(bool Show)
+        {
+            Color result = new Color();
+
+            result.R = 255;
+            result.G = 255;
+            result.B = 255;
+            if (Show)
+            {
+                result.A = 255;
+            }
+            else
+            {
+                result.A = 0;
+            }
+
+            return result;
+        }
+
+        //判斷允許後面顯示的區域~
+        //不管螢幕個數~最多為三個可畫分的區塊~在SetDisplayPart 函數中~已經將工具加入
+        //判斷方式 : 取用時~必須判斷為連續幾個 isusing 後 ~ 為一個區塊將計算值放到第一個區塊中~
+        //一般來說一個螢幕指會需要用到一個該工具~如果今天是雙或者三螢幕
+        //則必須按照第一個取用方式~去設定第二個甚至第三個~
+        private void CheckDisplayRange()
+        {
+            int startindex = -1, endindex = -1;
+            int useTools = 1;
+            bool HaveUsing = false;
+            double startvalue = 0;
+            double endvalue = 0;
+
+            IsUsingFirst = IsUsingSecond = IsUsingThree = false;
+
+            for (int i = 0; i < ExtraUnitGridList.Count; i++)
+            {
+                if (ExtraUnitGridList[i].IsUsing != 0 && !HaveUsing)
+                {
+                    #region GradientStop 的起始位置
+                    HaveUsing = true;
+                    startindex = i;
+                    startvalue = 0;
+                    double Leftwidth = 0;
+                    //計算到此左邊的寬度
+                    for (int index = 0; index < startindex; index++)
+                    {
+                        if (index == 0)
+                        {
+                            //主要為最左邊的寬度~判斷最左邊區塊寬度~為縮小或者為正常大小
+                            if (ExtraUnitGridList[index].Width <= MainEventWidth - (ExtraUnitGridList[index].ShrinkValueOne))
+                            {
+                                //縮小 : 原始大小 - 隱藏的大小 - 右邊被縮小的距離
+                                Leftwidth += MainEventWidth - NoneUseRange - (ExtraUnitGridList[index].ShrinkValueOne);
+                            }
+                            else
+                            {
+                                //正常大小計算方式 : 原始大小 - 隱藏的大小
+                                Leftwidth += MainEventWidth - NoneUseRange;
+                            }
+                        }
+                        else
+                        {
+                            Leftwidth += ExtraUnitGridList[index].Width;
+                        }
+                    }
+                    startvalue = Leftwidth / (double)ResolutionValueWidth;
+                    //Console.WriteLine("起點 : " + Leftwidth);
+                    #endregion
+                }
+                else
+                {
+                    if (HaveUsing && ExtraUnitGridList[i].IsUsing == 0)
+                    {
+                        #region GradientStop 的停止位置 (還沒找到最後一個)
+                        endindex = i;
+                        HaveUsing = false;
+                        endvalue = 0;
+                        double Leftwidth = 0;
+                        //計算到此左邊的寬度
+                        for (int index = 0; index < endindex; index++)
+                        {
+                            if (index == 0)
+                            {
+                                if (ExtraUnitGridList[index].Width < MainEventWidth)
+                                {
+                                    //因為左邊縮小的話只有右邊 - ExtraUnitGridList[index].ShrinkValueOne 顧~不用除以2
+                                    Leftwidth += MainEventWidth - NoneUseRange - (ExtraUnitGridList[index].ShrinkValueOne);
+                                }
+                                else
+                                {
+                                    Leftwidth += MainEventWidth - NoneUseRange;
+                                }
+                            }
+                            else
+                            {
+                                Leftwidth += ExtraUnitGridList[index].Width;
+                            }
+                        }
+                        endvalue = Leftwidth / (double)ResolutionValueWidth;
+                        //Console.WriteLine("終點 : " + Leftwidth);
+
+                        if (useTools == 1)
+                        {
+                            LeftLineLeftPointStopFirst.Offset = startvalue;
+                            LeftLineRightPointStopFirst.Offset = startvalue;
+                            RightLineLeftPointStopFirst.Offset = endvalue;
+                            RightLineRightPointStopFirst.Offset = endvalue;
+
+                            IsUsingFirst = true;
+                            useTools++;
+                        }
+                        else if (useTools == 2)
+                        {
+                            LeftLineLeftPointStopSecond.Offset = startvalue;
+                            LeftLineRightPointStopSecond.Offset = startvalue;
+                            RightLineLeftPointStopSecond.Offset = endvalue;
+                            RightLineRightPointStopSecond.Offset = endvalue;
+
+                            IsUsingSecond = true;
+                            useTools++;
+                        }
+                        else if (useTools == 3)
+                        {
+                            LeftLineLeftPointStopThree.Offset = startvalue;
+                            LeftLineRightPointStopThree.Offset = startvalue;
+                            RightLineLeftPointStopThree.Offset = endvalue;
+                            RightLineRightPointStopThree.Offset = endvalue;
+
+                            IsUsingThree = true;
+                            useTools = 1;
+                        }
+                        #endregion
+                    }
+                    //或者最後一個Grid
+                    else if (HaveUsing && i + 1 == ExtraUnitGridList.Count)
+                    {
+                        #region GradientStop 的停止位置 (最後一個的話)
+                        HaveUsing = false;
+                        endvalue = 1;
+
+                        if (useTools == 1)
+                        {
+                            LeftLineLeftPointStopFirst.Offset = startvalue;
+                            LeftLineRightPointStopFirst.Offset = startvalue;
+                            RightLineLeftPointStopFirst.Offset = endvalue;
+                            RightLineRightPointStopFirst.Offset = endvalue;
+
+                            IsUsingFirst = true;
+                            useTools++;
+                        }
+                        else if (useTools == 2)
+                        {
+                            LeftLineLeftPointStopSecond.Offset = startvalue;
+                            LeftLineRightPointStopSecond.Offset = startvalue;
+                            RightLineLeftPointStopSecond.Offset = endvalue;
+                            RightLineRightPointStopSecond.Offset = endvalue;
+
+                            IsUsingSecond = true;
+                            useTools++;
+                        }
+                        else if (useTools == 3)
+                        {
+                            LeftLineLeftPointStopThree.Offset = startvalue;
+                            LeftLineRightPointStopThree.Offset = startvalue;
+                            RightLineLeftPointStopThree.Offset = endvalue;
+                            RightLineRightPointStopThree.Offset = endvalue;
+
+                            IsUsingThree = true;
+                            useTools = 1;
+                        }
+                        #endregion
+                    }
+                }
+            }
+            if (!IsUsingFirst)
+            {
+                LeftLineLeftPointStopFirst.Offset = 0;
+                LeftLineRightPointStopFirst.Offset = 0;
+                RightLineLeftPointStopFirst.Offset = 0;
+                RightLineRightPointStopFirst.Offset = 0;
+            }
+            if (!IsUsingSecond)
+            {
+                LeftLineLeftPointStopSecond.Offset = 0;
+                LeftLineRightPointStopSecond.Offset = 0;
+                RightLineLeftPointStopSecond.Offset = 0;
+                RightLineRightPointStopSecond.Offset = 0;
+            }
+            if (!IsUsingThree)
+            {
+                LeftLineLeftPointStopThree.Offset = 0;
+                LeftLineRightPointStopThree.Offset = 0;
+                RightLineLeftPointStopThree.Offset = 0;
+                RightLineRightPointStopThree.Offset = 0;
+            }
+        }
+    }
+}

+ 518 - 0
HistoryDLL/CyclicScrollerSubFunction.cs

@@ -0,0 +1,518 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+using System.Windows.Media.Animation;
+using System.Windows.Media.Imaging;
+
+namespace HistoryDLL
+{
+    public partial class CyclicScroller : UserControl,IDisposable
+    {
+        private int AutoRunVelocityValue = 0;
+
+        private bool IsConfigSettingExist = false;
+
+        private List<bool> canUsingLangList = new List<bool>(4) { false, false, false, false };
+
+        /// <summary>
+        /// 初始化除了Spec外的基本設定
+        /// </summary>
+        private void InitialWholeSetting(string settingPath = null)
+        {
+            //建Setting Folder 並判斷是否有存在 ConfigSetting.ini 檔案
+            if (!Directory.Exists(GlobalFunction.settingPath))
+            {
+                Directory.CreateDirectory(GlobalFunction.settingPath);
+            }
+            else if (File.Exists(GlobalFunction.ConfigSettingFilePath))
+            {
+                IsConfigSettingExist = true;
+            }
+
+            //設定是否啟用切換主標題語系功能
+            SetChangeLangStatus();
+            //設定是否啟用回首頁功能
+            SetHomeBtnStatus();
+            //取得自動輪播時候的速度
+            AutoRunVelocityValue = GetAutoRunVelocity();
+            //掛載 StoryBoard 完成後的事件
+            storyboardForLocate.Completed += new EventHandler(storyboardForLocate_Completed);
+            //設定自動輪撥的 Timer
+            GlobalFunction.CheckAutoRunTimer.Interval = TimeSpan.FromMilliseconds(ConfigSettingClass.MainBackCollect.BackHomeMillisecond * 1000);
+            GlobalFunction.CheckAutoRunTimer.Tick += CheckAutoRunTimer_Tick;
+            // 取得 4K 解析度設定
+            GlobalFunction.isSolutionUsing4K = ConfigSettingClass.MainBackCollect.IsUsing4kResolution;
+
+            //設定背景圖
+            if (IsConfigSettingExist)
+            {
+                if (File.Exists(GlobalFunction.thumbPath + ConfigSettingClass.MainBackCollect.ImgBackground))
+                {
+                    this.uxBackGroundImg.Visibility = System.Windows.Visibility.Visible;
+                    this.Background = Brushes.White;
+                    this.uxBackGroundImg.Source = GetBitMap(GlobalFunction.thumbPath + ConfigSettingClass.MainBackCollect.ImgBackground);
+                }
+                else
+                {
+                    this.uxBackGroundImg.Visibility = System.Windows.Visibility.Collapsed;
+                    this.Background = new SolidColorBrush(ConfigSettingClass.MainBackCollect.BackgroundColor);
+                }
+            }
+            else
+            {
+                //如無設定檔案~則依照解析度載入對應的圖檔
+                LoadBackgroundFromResolution();
+            }
+            //設定左上及右上logo
+            if (File.Exists(GlobalFunction.thumbPath + ConfigSettingClass.MainBackCollect.ImgLogo))
+            {
+                uxLeftLogoMap.Visibility = Visibility.Visible;
+                uxRightLogoMap.Visibility = Visibility.Visible;
+
+                uxLeftLogoMap.Source = new BitmapImage(new Uri(GlobalFunction.thumbPath + ConfigSettingClass.MainBackCollect.ImgLogo));
+                uxRightLogoMap.Source = new BitmapImage(new Uri(GlobalFunction.thumbPath + ConfigSettingClass.MainBackCollect.ImgLogo));
+
+                RenderOptions.SetBitmapScalingMode(uxLeftLogoMap, BitmapScalingMode.HighQuality);
+                RenderOptions.SetBitmapScalingMode(uxRightLogoMap, BitmapScalingMode.HighQuality);
+            }
+            else
+            {
+                uxLeftLogoMap.Opacity = 0;
+                uxRightLogoMap.Opacity = 0;
+            }
+        }
+
+        private void LoadBackgroundFromResolution()
+        {
+            if (CurrentMonitorCount.ncm == MonitorFlag.Monitor1_1)
+            {
+                //this.Background = new ImageBrush(new BitmapImage(new Uri(GlobalFunction.thumbPath + "1x1.jpg")));
+            }
+            else if (CurrentMonitorCount.ncm == MonitorFlag.Monitor2_1)
+            {
+                this.Background = new ImageBrush(new BitmapImage(new Uri(GlobalFunction.thumbPath + "1x2.jpg")));
+            }
+            else if (CurrentMonitorCount.ncm == MonitorFlag.Monitor3_1)
+            {
+                this.Background = new ImageBrush(new BitmapImage(new Uri(GlobalFunction.thumbPath + "1x3.jpg")));
+            }
+        }
+
+        //透過ChangeLan.txt 取得是否顯示改變主標題語系功能
+        private void SetChangeLangStatus()
+        {
+            if (File.Exists(GlobalFunction.CanChangeLangPath))
+            {
+                string text = System.IO.File.ReadAllText(GlobalFunction.CanChangeLangPath);
+                int usingCount = 0;
+
+                if (text.ToLower() == "true")
+                {
+                    if (ConfigSettingClass.MainBackCollect.LangText[0] != "")
+                    {
+                        canUsingLangList[0] = true;
+                        usingCount++;
+                    }
+
+                    if (ConfigSettingClass.MainBackCollect.LangText[1] != "")
+                    {
+                        canUsingLangList[1] = true;
+                        usingCount++;
+                    }
+
+                    if (ConfigSettingClass.MainBackCollect.LangText[2] != "")
+                    {
+                        canUsingLangList[2] = true;
+                        usingCount++;
+                    }
+
+                    if (ConfigSettingClass.MainBackCollect.LangText[3] != "")
+                    {
+                        canUsingLangList[3] = true;
+                        usingCount++;
+                    }
+                }
+
+                if (usingCount >= 2)
+                {
+                    uxMainLangBtnR.Visibility = Visibility.Visible;
+                    uxMainLangBtnL.Visibility = Visibility.Visible;
+                }
+            }
+        }
+
+        //透過HomeClick.txt 取得是否顯示回首頁功能
+        private void SetHomeBtnStatus()
+        {
+            if (File.Exists(GlobalFunction.CanHomeClickPath))
+            {
+                string text = System.IO.File.ReadAllText(GlobalFunction.CanHomeClickPath);
+
+                if (text.ToLower() == "true")
+                {
+                    uxHomeBtnR.Visibility = Visibility.Visible;
+                    uxHomeBtnL.Visibility = Visibility.Visible;
+                }
+            }
+        }
+
+        //透過Velocity.txt 取得設定的自動輪播速度
+        private int GetAutoRunVelocity()
+        {
+            int result = 5;
+
+            if (File.Exists(GlobalFunction.AutoRunVelocityPath))
+            {
+                string text = System.IO.File.ReadAllText(GlobalFunction.AutoRunVelocityPath);
+
+                result = int.Parse(text);
+            }
+
+            return result;
+        }
+
+        //設定自動輪播的動畫
+        private void SetAutoRunStoryBoard(double from, double to)
+        {
+            autoRunStoryboard.Children.Clear();
+
+            DoubleAnimation dbOffset = new DoubleAnimation()
+            {
+                Duration = TimeSpan.FromSeconds(AutoRunVelocityValue),
+            };
+
+            ScrollViewerUtilities.UseMotionStop = false;
+            Storyboard.SetTarget(dbOffset, (DependencyObject)this.FindName("uxMyScroll"));
+            Storyboard.SetTargetProperty(dbOffset, new PropertyPath(ScrollViewerUtilities.HorizontalOffsetProperty));
+            autoRunStoryboard.Children.Add(dbOffset);
+            autoRunStoryboard.FillBehavior = FillBehavior.HoldEnd;
+
+            dbOffset.From = from;
+            dbOffset.To = to;
+        }
+
+        private ImageSource GetBitMap(string imgpath)
+        {
+            BitmapImage bitmapImg = new BitmapImage();
+
+            bitmapImg.BeginInit();
+            bitmapImg.UriSource = new Uri(imgpath, UriKind.RelativeOrAbsolute);
+            //忽略原始圖檔的色盤設定,使用預設值,可縮短載入圖檔的時間
+            //如有遇到色彩不正確的問題,或者原圖有特殊的自定義色盤,請不要使用此設定
+            bitmapImg.CreateOptions = BitmapCreateOptions.IgnoreColorProfile;
+            //使用以下的預先載入設定,在BitmapImage創建完成之後,可立刻釋放其所占用或鎖住的資源,以免咬住檔案
+            bitmapImg.CacheOption = BitmapCacheOption.OnLoad;
+            //根據欲顯示的區域長或寬,來設定 DecodePixelHeight 或 DecodePixelWidth 的值
+            bitmapImg.EndInit();
+            bitmapImg.Freeze();
+
+            return bitmapImg;
+        }
+
+        /// <summary>
+        /// 新建出 Grid For 裝載DetailViewer
+        /// </summary>
+        private void CreateExtraUnitGrid()
+        {
+            ExtraUnitGridList.Clear();
+
+            for (int count = 0; count < ChildrenCount; count++)
+            {
+                ExtraUnitGrid ExtraGrid = new ExtraUnitGrid(MainEventWidth, MainEventHeight, YearEventHeight, NoneUseRange);
+
+                ExtraGrid.ExtraUnitGridBubbleToCyclicScrollerEvent += new ExtraUnitGrid.ExtraUnitGridBubbleToCyclicScroller(ExtraGrid_ExtraUnitGridBubbleToCyclicScrollerEvent);
+                ExtraUnitGridList.Add(ExtraGrid);
+            }
+        }
+
+        /// <summary>
+        /// 初始化該 ExtraUnitGrid ~包括 狀態 位置 
+        /// </summary>
+        private void InitializeExtraUnitGrid()
+        {
+            int index = 1;
+            //替每個 Grid 標上索引值~該索引值是代表該Grid在螢幕上的位置(從1開始算起)
+            //且如果是第一個或者是最後一個~則狀態UnUse灰色
+            for (int count = 0; count < ExtraUnitGridList.Count; count++)
+            {
+                ExtraUnitGridList[count].Get_Set_MonitorIndex = index;
+
+                //設定狀態
+                if (index == 1 || index == ExtraUnitGridList.Count)
+                {
+                    //判斷用
+                    ExtraUnitGridList[count].Get_Set_BlockControlMode = ExtraUnitGrid.ControlMode.UnUse;
+                    //回原始狀態用
+                    ExtraUnitGridList[count].SetOriControlMode(ExtraUnitGrid.ControlMode.UnUse);
+                }
+                else
+                {
+                    ExtraUnitGridList[count].Get_Set_BlockControlMode = ExtraUnitGrid.ControlMode.CanExtend;
+                    ExtraUnitGridList[count].SetOriControlMode(ExtraUnitGrid.ControlMode.CanExtend);
+                }
+                index++;
+            }
+            //調整位置
+            for (int count = 0; count < ExtraUnitGridList.Count; count++)
+            {
+                //先設定第一個
+                if (count == 0)
+                {
+                    ExtraUnitGridList[count].Margin = new Thickness(-NoneUseRange, 0, 0, uxMyScroll.Margin.Bottom - 5);
+                    ExtraUnitGridList[count].RecodeMarginLeft = ExtraUnitGridList[count].Margin.Left;
+                    continue;
+                }
+                ExtraUnitGridList[count].Margin = new Thickness(ExtraUnitGridList[count - 1].Margin.Left + MainEventWidth, 0, 0, uxMyScroll.Margin.Bottom - 5);
+                ExtraUnitGridList[count].RecodeMarginLeft = ExtraUnitGridList[count].Margin.Left;
+            }
+        }
+
+        /// <summary>
+        /// 設定當前語系
+        /// </summary>
+        private void SetLanguage()
+        {
+            //預設
+            System.Windows.Application.Current.Properties["Language"] = "Language1";
+            uxMainLangBtnL.Content = ConfigSettingClass.MainBackCollect.LangText[0];
+            uxMainLangBtnR.Content = ConfigSettingClass.MainBackCollect.LangText[0];
+            //如果更改
+            if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 1)
+            {
+                System.Windows.Application.Current.Properties["Language"] = "Language2";
+                uxMainLangBtnL.Content = ConfigSettingClass.MainBackCollect.LangText[1];
+                uxMainLangBtnR.Content = ConfigSettingClass.MainBackCollect.LangText[1];
+            }
+            else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 2)
+            {
+                System.Windows.Application.Current.Properties["Language"] = "Language3";
+                uxMainLangBtnL.Content = ConfigSettingClass.MainBackCollect.LangText[2];
+                uxMainLangBtnR.Content = ConfigSettingClass.MainBackCollect.LangText[2];
+            }
+            else if (ConfigSettingClass.MainBackCollect.DefaultLangIndex == 3)
+            {
+                System.Windows.Application.Current.Properties["Language"] = "Language4";
+                uxMainLangBtnL.Content = ConfigSettingClass.MainBackCollect.LangText[3];
+                uxMainLangBtnR.Content = ConfigSettingClass.MainBackCollect.LangText[3];
+            }
+        }
+
+        /// <summary>
+        /// 設定回正被中斷時~應該回到的顯示位置
+        /// </summary>
+        private void SetReturnPos()
+        {
+            System.Windows.Application.Current.Properties["ReturnPos"] = MainEventWidth + NoneUseRange;
+        }
+
+        /// <summary>
+        /// 判斷當前的Index是否超出"最大"容許範圍~進行調整
+        /// </summary>
+        /// <returns></returns>
+        private int GetIndexFromRightSide()
+        {
+            int index = currentLoadIndex;
+
+            if (index < LiveContainerList.Count)
+            {
+                index += 1;
+            }
+            else
+            {
+                index = 1;
+            }
+
+            return index;
+        }
+
+        /// <summary>
+        /// 判斷當前的Index是否低於"最小"容許範圍~進行調整
+        /// </summary>
+        /// <returns></returns>
+        private int GetIndexFromLeftSide()
+        {
+            int index = currentLoadIndex;
+
+            if (index > 0)
+            {
+                index -= 1;
+            }
+            else
+            {
+                index = LiveContainerList.Count - 1;
+            }
+
+            return index;
+        }
+
+        /// <summary>
+        /// 透過螢幕可容納的個數取得當前年份中間位置
+        /// </summary>
+        /// <returns></returns>
+        private int GetCenterIndexValue()
+        {
+            int result = 0;
+
+            switch (CurrentMonitorCount.ncm)
+            {
+                case MonitorFlag.Monitor1_1:
+                case MonitorFlag.Monitor2_1:
+                case MonitorFlag.Monitor3_1:
+                case MonitorFlag.Monitor4_1:
+                case MonitorFlag.Monitor5_1:
+                case MonitorFlag.Monitor6_1:
+                    {
+                        result = ChildrenCount / 2;
+                        break;
+                    }
+            }
+
+            return result;
+        }
+
+        #region 首頁動畫
+        /// <summary>
+        /// 計算總事件~並將該直傳到Homepage中
+        /// </summary>
+        private void CalcCountToHomePage()
+        {
+            if (!RunHomePageAnimation)
+            {
+                return;
+            }
+            int staticvalue = GetCycleCount();
+            int totalevent = 0;
+
+            for (int index = 0; index < staticvalue; index++)
+            {
+                for (int count = 0; count < xmlDataList.Count; count++)
+                {
+                    totalevent += xmlDataList[count].monthclassList.Count;
+                }
+            }
+            hp.SetEventCount(totalevent);
+        }
+
+        /// <summary>
+        /// Loading start
+        /// </summary>
+        private void LoadingStart()
+        {
+            if (RunHomePageAnimation)
+            {
+                this.uxCyclicGrid.Opacity = 0;
+            }
+        }
+
+        private void AddHomePageAnimation()
+        {
+            if (RunHomePageAnimation)
+            {
+                hp = new HomePage(ResolutionValueWidth, ResolutionValueHeight);
+                hp.SetBlockCommonSetting(MainEventWidth, YearEventHeight, NoneUseRange);
+                hp.SetHistoryWallControl(uxCyclicGrid);
+                hp.OnLoadProgessComplete += Hp_OnLoadProgessComplete;
+                uxMainWindow.Children.Add(hp);
+            }
+        }
+
+        private void Hp_OnLoadProgessComplete(object sender, EventArgs e)
+        {
+            OnDataLoadCompeleted?.Invoke(this,null);
+        }
+        #endregion
+
+        #region 自動輪播相關
+        void CheckAutoRunTimer_Tick(object sender, EventArgs e)
+        {
+            // 確認 Detailviewer 狀況 sdlu
+            if (CheckExtraGridIsVideoRun())
+            {
+                //將上層Grid關閉
+                CloseExtraGrid();
+                //自動輪播開始
+                WpfDelayDoWork.DoWork(HistoryWallAutoRun, 1000);
+                isAutoRun = true;
+                GlobalFunction.CheckAutoRunTimer.Stop();
+            }
+        }
+
+        private bool CheckExtraGridIsVideoRun()
+        {
+            bool isCheckVideo = true;
+
+            int count = ExtraUnitGridList.Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                Grid gd = ExtraUnitGridList[i].BorderUp.Child as Grid;
+
+                if (gd != null && gd.Children.Count > 0)
+                {
+                    DetailViewer dv = gd.Children[0] as DetailViewer;
+
+                    if (dv.isPlayVideo)
+                    {
+                        isCheckVideo = false;
+                        break;
+                    }
+                }
+            }
+
+            return isCheckVideo;
+        }
+
+        /// <summary>
+        /// 關閉上層Grid
+        /// </summary>
+        private void CloseExtraGrid()
+        {
+            int count = ExtraUnitGridList.Count;
+
+            for (int i = 0; i < count; i++)
+            {
+                ExtraUnitGridList[i].BorderDown_TouchUp(null, null);
+            }
+        }
+
+        /// <summary>
+        /// 自動移動啟動
+        /// </summary>
+        private void HistoryWallAutoRun()
+        {
+            if (ControlMode == HistoryControlMode.Manual)
+            {
+                ControlMode = HistoryControlMode.AutoRun;
+                SendControlModeToLiveContainer(ControlMode);
+                SetAutoRunStoryBoard(this.uxMyScroll.HorizontalOffset, this.uxMyScroll.HorizontalOffset + MainEventWidth);
+                autoRunStoryboard.Begin();
+            }
+        }
+
+        /// <summary>
+        /// 關閉自動移動
+        /// </summary>
+        private void StopAutoRunTheWall()
+        {
+            if (ControlMode == HistoryControlMode.AutoRun)
+            {
+                ScrollViewerUtilities.UseMotionStop = true;
+                autoRunStoryboard.Stop();
+                ControlMode = HistoryControlMode.Manual;
+                SendControlModeToLiveContainer(ControlMode);
+            }
+        }
+        #endregion
+
+        public void Dispose()
+        {
+            GlobalFunction.CheckAutoRunTimer.Tick -= CheckAutoRunTimer_Tick;
+        }
+    }
+}

BIN
HistoryDLL/DLL/KernelViewerCtrlDll.dll


BIN
HistoryDLL/DLL/MediaGalleryDll.dll


BIN
HistoryDLL/DLL/MediaViewerLib.dll


BIN
HistoryDLL/DLL/Microsoft.WindowsAPICodePack.Shell.dll


BIN
HistoryDLL/DLL/Microsoft.WindowsAPICodePack.dll


BIN
HistoryDLL/DLL/NLLoadingIndicator.dll


BIN
HistoryDLL/DLL/NLPlaneRotator.dll


BIN
HistoryDLL/DLL/Newtonsoft.Json.dll


BIN
HistoryDLL/DLL/nLightenLibs.dll


+ 1 - 0
HistoryDLL/Data/HistoryWallPage/Setting/ChangeLan.txt

@@ -0,0 +1 @@
+false

+ 1 - 0
HistoryDLL/Data/HistoryWallPage/Setting/HomeClick.txt

@@ -0,0 +1 @@
+false

+ 1 - 0
HistoryDLL/Data/HistoryWallPage/Setting/ScaleDetailviewer.txt

@@ -0,0 +1 @@
+false

+ 1 - 0
HistoryDLL/Data/HistoryWallPage/Setting/Velocity.txt

@@ -0,0 +1 @@
+5

BIN
HistoryDLL/Data/HistoryWallPage/Thumb/1x1.jpg


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/1x2.jpg


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/1x3.jpg


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/color322x212.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/exit_focus.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/exit_idle.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/home.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/language_bk.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/launch_icon.ico


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/logo.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/ok_focus.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/ok_idle.png


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/registration_bk.jpg


BIN
HistoryDLL/Data/HistoryWallPage/Thumb/shadow_big.png


Some files were not shown because too many files changed in this diff